.NET Inside Out Part 23 – Machine code address of any .NET Core method

This is the twentieth third part of the .NET Inside Out series. For your convenience you can find other parts in the table of contents in Part 1 – Virtual and non-virtual calls in C#

.NET Core introduced tiered compilation and reworked AOT compilation. Previously, we could get address of machine code by calling GetFunctionPointer on a method handle. However, it didn’t work for NGEN-ed methods and doesn’t work for ReadyToRun code or tiered methods. How to do it?

If you go through coreclr repository you’ll find this method:

If we call it from C# we’ll be able to get the machine code address. Let’s do it:

General idea is we want to generate some machine code to call the method directly. To do that, we use .NET Inside Out Part 9 — Generating Func from a bunch of bytes in C# revisited approach. In lines 31-34 we pass the method descriptor via ecx register (the this pointer). Then use the trick to push address and return to it which is effectively a call to an absolute address. Finally, we return the value of the eax register. Rest of the code is explained in other part.

You can run this on some ReadyToRun method (like in the example) and see that value returned by internal method differs from the value returned by .NET API.

It works, however, we need to know the physical address of the MethodDesc::GetNativeCode() method. For the purpose of this demo I just extracted it with WinDBG, however, you can automate it in many ways. Keep in mind that the address will change between applications and system restarts.