We have the following method in a class in one of our projects:
private unsafe void SomeMethod()
{
// Beginning of the method omitted for brevity
var nv = new Vector4[x];
fixed (Vector4* vp = nv)
{
fixed (float* tp = /* Source float ptr */)
{
fixed (double* ap = /* Source double ptr */)
{
for (var i = atlArray.Length - 1; i >= 0; --i)
{
vp[((i + 1) << 3) - 2] = new Vector4(tp[i], btt, 0.0f, 1.0f);
// Additional Vector4 construction omitted for brevity
nttp[i] = new Vector2(tp[i], this.ttvp);
nts[i] = string.Format(ap[i], /* etc. */);
}
}
}
}
this.ts = nts;
this.ttp = nttp;
this.V = nv; // <- This is a property setter
}
I've had to obfuscate this, but hopefully it's still clear enough to get an idea of what's going on.
On one of our developers' machines, in debug builds, the C# compiler removes the three assignments that occur after the fixed block is closed. If we attempt to put a breakpoint on these lines, the breakpoint skips to the ending brace of the method when the application starts. Code that appears between a fixed block and the end of a method is removed in other methods too, but puzzlingly, not in all of them.
After some experimentation, we found that turning on optimization for the affected project caused the missing code to be included. However, this work-around fails for our unit testing - the code is missing, and changing the optimization of the affected project and its test project does not help. We also found that moving the three assignments inside the inner-most fixed statement worked - it becomes clear why when examining the IL.
In the debug DLL built on the affected machine (with optimization turned off), a return op appears directly after ap is popped off the stack:
IL_03a1: nop
IL_03a2: ldc.i4.0
IL_03a3: conv.u
IL_03a4: stloc.s ap
IL_03a6: ret
This explains why moving the three assignments before the stloc instruction works. In the debug DLL built on my machine, the return op occurs in the expected place, after the three assignments:
IL_03a5: nop
IL_03a6: ldc.i4.0
IL_03a7: conv.u
IL_03a8: stloc.s ap
IL_03aa: nop
IL_03ab: ldc.i4.0
IL_03ac: conv.u
IL_03ad: stloc.s tp
IL_03af: nop
IL_03b0: ldc.i4.0
IL_03b1: conv.u
IL_03b2: stloc.s vp
IL_03b4: ldarg.0
IL_03b5: ldloc.s nts
IL_03b7: stfld string[] N.B.E.B::ts
IL_03bc: ldarg.0
IL_03bd: ldloc.s nttp
IL_03bf: stfld valuetype [SharpDX]SharpDX.Vector2[] N.B.E.B::ttp
IL_03c4: ldarg.0
IL_03c5: ldloc.s nv
IL_03c7: call instance void N.B.E.B::set_V(valuetype [SharpDX]SharpDX.Vector4[])
IL_03cc: nop
IL_03cd: ret
We've so far failed to produce an SSCCE - this seems to manifest only in very specific circumstances, and only in one of our projects. We've checked that the same versions of Visual Studio, the .NET framework, the C# compiler and MSBuild are being used on both machines. We've checked other potential differences like OS version and updates. Things appear to be the same on both machines (they are the same model of laptop). We're a bit puzzled, frankly. Any help would be much appreciated.
My colleague, the developer whose machine this was affecting, found a difference in the diagnostic output from the build - it was the C# compiler. We thought that MSBuild was using the csc.exe in the expected location (c:\Program Files (x86)\MSBuild\12.0\Bin), but bizarrely, it was actually executing a csc.exe in C:\Users\[user]\AppData\Local\Microsoft\VisualStudio\12.0\Extensions, which had a completely different version. We don't know how that compiler executable came to be there, or how it was being referenced by MSBuild, but once it was removed, MSBuild reverted to using the version of csc.exe in its home Bin directory, and the code is being built correctly now.
Related
I have no idea how to do compile IL code at runtime.
I use .NET core 3.1 and I can generate a string which contains
.assembly extern mscorlib {}
.assembly Hello {}
.module Hello.exe
.class Hello.Program
extends [mscorlib]System.Object
{
.method static void Main(string[] args)
cil managed
{
.entrypoint
ldstr "H"
call void[mscorlib]
System.Console::
Write(string)
ldstr "i"
call void[mscorlib]
System.Console::
Write(string)
ret
}
}
But how do I then compile the file? I want to do it at runtime.
(ignore the bad IL code)
So, i found out how to do it. I copied the ilasm.exe and fusion.dll from my .net framework folder and then i saved the string to a file and then i used ProcessInfo to run ilasm file. That then outputted the exe i wanted.
For anybody who is wondering, ilasm.exe is located in
C:\Windows\Microsoft.NET\Framework\Verison
if you replace verison with the framework verison, for example v4.0.30319.
Thanks to anybody who tried to help!
I need to inspect code, that JIT emits for generic method with different struct parameters. I read articles about WinDbg and SOS.dll and it's possible to inspect non-generic methods. But for generic methods, which should be JIT-ed for each struct type there is no JIT-ed code in method table, where can i find it?
namespace ConsoleApp1
{
class Program
{
public void Foo<T>(T arg)
{
//some code here
}
static void Main(string[] args)
{
var program = new Program();
program.Foo("test");
program.Foo(1.0);
program.Foo(new Guid());
program.Foo((byte)1);
program.Foo((char)1);
program.Foo(1);
}
}
}
WinDbg:
0:006> .loadby sos clr
0:006> !Name2EE ConsoleApp1!ConsoleApp1.Program
Module: 00007ffa3abf4118
Assembly: ConsoleApp1.exe
Token: 0000000002000002
MethodTable: 00007ffa3abf5a18
EEClass: 00007ffa3abf24b8
Name: ConsoleApp1.Program
Dump method table
0:006> !DumpMT -md 00007ffa3abf5a18
EEClass: 00007ffa3abf24b8
Module: 00007ffa3abf4118
Name: ConsoleApp1.Program
mdToken: 0000000002000002
File: D:\repos\ConsoleApp1\ConsoleApp1\bin\Debug\net462\ConsoleApp1.exe
BaseSize: 0x18
ComponentSize: 0x0
Slots in VTable: 7
Number of IFaces in IFaceMap: 0
--------------------------------------
MethodDesc Table
Entry MethodDesc JIT Name
00007ffa9759c080 00007ffa970f7fb8 PreJIT System.Object.ToString()
00007ffa97604360 00007ffa970f7fc0 PreJIT System.Object.Equals(System.Object)
00007ffa97674770 00007ffa970f7fe8 PreJIT System.Object.GetHashCode()
00007ffa975cf570 00007ffa970f8000 PreJIT System.Object.Finalize()
00007ffa3ad005c0 00007ffa3abf5a10 JIT ConsoleApp1.Program..ctor()
00007ffa3ad00078 00007ffa3abf59e0 NONE ConsoleApp1.Program.Foo(!!0) // "base" IL code
00007ffa3ad00480 00007ffa3abf5a00 JIT ConsoleApp1.Program.Main(System.String[])
And ofc I got no code for Foo
0:006> !U 00007ffa3abf59e0
Not jitted yet
Is it any ideas?
I took your code and compiled it as x86 debug build. I then attached to the process and waited until it terminated.
I find the same result as you:
Entry MethodDe JIT Name
[...]
00250038 00204d34 NONE JitExample2.Program.Foo(!!0)
Here it says NONE, which has the meaning "not jitted".
0:000> !dumpmd 00204d34
Method Name: JitExample2.Program.Foo(!!0)
[...]
IsJitted: no
So the answer seems to be confirmed: it's not jitted.
I don't know any official method of getting a list of jitted generic methods. But with the help of !bpmd it's possible:
0:000> !bpmd JitExample2 JitExample2.Program.Foo
Found 1 methods in module 00204024...
MethodDesc = 00204d34
Setting breakpoint: bp 0025074A [JitExample2.Program.Foo[[System.Char, mscorlib]](Char)]
Setting breakpoint: bp 002506EA [JitExample2.Program.Foo[[System.Byte, mscorlib]](Byte)]
Setting breakpoint: bp 00250687 [JitExample2.Program.Foo[[System.Guid, mscorlib]](System.Guid)]
Setting breakpoint: bp 00250627 [JitExample2.Program.Foo[[System.Double, mscorlib]](Double)]
Setting breakpoint: bp 002505B0 [JitExample2.Program.Foo[[System.__Canon, mscorlib]](System.__Canon)]
Setting breakpoint: bp 002507AA [JitExample2.Program.Foo[[System.Int32, mscorlib]](Int32)]
You can then use the addresses after bp to show the JIT code:
0:000> !u 0025074A
Normal JIT generated code
JitExample2.Program.Foo[[System.Char, mscorlib]](Char)
Begin 00250728, size 4b
C:\Users\For example John\JitExample2\Program.cs # 8:
00250728 55 push ebp
00250729 8bec mov ebp,esp
0025072b 83ec10 sub esp,10h
0025072e 33c0 xor eax,eax
[...]
I'm debugging the source code for mscorlib1 with WinDbg/SOS. I'm curious, is it possible to get the managed function name if you see its address in assembly? For example, this is some of the code I'm seeing in the disassembly window:
00007ffd`7f035d7c 488d0d3d3af5ff lea rcx,[System_Private_CoreLib_ni+0x8797c0 (00007ffd`7ef897c0)]
00007ffd`7f035d83 e890728eff call System_Private_CoreLib_ni+0x20d018 (00007ffd`7e91d018)
00007ffd`7f035d88 488bf0 mov rsi,rax
00007ffd`7f035d8b b9874a0000 mov ecx,4A87h
00007ffd`7f035d90 e8834a91ff call System_Private_CoreLib_ni+0x23a818 (00007ffd`7e94a818)
00007ffd`7f035d95 488bc8 mov rcx,rax
00007ffd`7f035d98 e87356b9ff call System_Private_CoreLib_ni+0x4bb410 (00007ffd`7ebcb410)
00007ffd`7f035d9d 488bd0 mov rdx,rax
00007ffd`7f035da0 488bce mov rcx,rsi
00007ffd`7f035da3 e8e89fbdff call System_Private_CoreLib_ni+0x4ffd90 (00007ffd`7ec0fd90)
I want to find out what the names of some of these functions being call-ed are. I figure the command to use for this would be !dumpmd, but none of these commands seem to work:
!dumpmd 0x20d018
!dumpmd e890728eff
!dumpmd 00007ffd`7e91d018
All of them respond with "... is not a MethodDesc". How then can I get the managed function name from the assembly, or is it not possible?
1 mscorlib was recently renamed System.Private.CoreLib for .NET Core, so that's why you see that instead of mscorlib_ni.
!dumpmd 0x20d018
can't work, because you only pass the offset relative to the module. Without specifying the module (System_Private_CoreLib_ni), !dumpmd cannot know what you're referring to.
!dumpmt e890728eff
can't work, because you pass machine code to !dumpmt. e8 is the machine code for the assembly instruction call and the rest is a relative offset. To interpret that, !dumpmt would need to know the address of the instruction so that it can calculate the address of the method being called.
!dumpmt 00007ffd`7e91d018
could at least be plausible, because you pass an absolute address. That is a meaningful address. But it's not the address of a method table which !dumpmt expects.
With a given native address, you can use
!IP2MD <Code address> Displays the MethodDesc structure at the specified address in code that has been JIT-compiled.
Actually the command will display much more, including the method name.
0:000> !ip2md 001fce80
MethodDesc: 00508ab4
Method Name: ReporterCmd.Program+<>c..cctor()
Class: 0025e10c
MethodTable: 00508ad0
mdToken: 06000027
Module: 00193fbc
IsJitted: yes
CodeAddr: 001fce48
Transparency: Critical
The sosex (download) command !mln as implemented by #Steve Johnson and mentioned in his answer is really helpful, since it will auto detect the nearest useful thing, so you needn't know in detail what you have.
0:000> !mln 001fce80
Method instance: (BEGIN=001fce48)(MD=00508ab4 disassemble)[ReporterCmd.Program+<>c..cctor()]
If you're learning about .NET internals, I recommend using !mln and then finding out how to get the same results using other methods so that you know about the relationship of things.
Pass the entire address to !sosex.mln
I tested Dotfuscator with some of my DLLs written in C#.
It seemed it works really well on .NET environment, so this time I tried them with Unity3D. Those simple DLLs were just coded only with simple standard C# classes and methods, no reflection, no LINQ, no other custom or 3rd party APIs including Unity's. But failed to make them work in my Unity3d project, while original pure DLLs which aren't obfuscated were working fine.
After struggling for a few hours, I decided to test with new simple projects. Below is all I got in C#, there are no other code, no other references at all.
[System.Reflection.Obfuscation(Feature = "renaming", Exclude = true)]
public class Class1
{
[System.Reflection.Obfuscation(Feature = "renaming", Exclude = true)]
public static int Get()
{
return 123;
}
}
After compiling this to DLL, I put it in an EMPTY project on Unity3D Editor and played, and it worked well. But when I gave another try after obfuscating the DLL with Dotfuscator, it stopped saying "InvalidProgramException: Invalid IL code in Class1:Get (): IL_000c: pop".
As you can see above, I added attributes which prevent the code from being renamed, and of course, I could see in Reflector, the name of both class and method weren't actually renamed.
Yesterday I newly registered and downloaded the evaluation version of the latest Dotfuscator Professional Edition 4.21.0 from PreEmptive's site. I compiled both on Visual Studio 2008 and 2015 with .NET 3.5, also tried with all different Solution Platforms. The version of Unity is 5.3.4f1.
My guess now is Dotfuscator only works with MSIL, not Mono 2.X which Unity3D internally uses.
Am I right? Is there anyone using Dotfuscator with Unity3D or Mono well?
[EDIT]
I checked IL code using ILDasm, don't understand what's going on, but interesting to see a bunch of code is modified.
Before applying Dotfuscator
.method public hidebysig static int32 Get() cil managed
{
.custom instance void [mscorlib]System.Reflection.ObfuscationAttribute::.ctor() = ( 01 00 02 00 54 0E 07 46 65 61 74 75 72 65 08 72 // ....T..Feature.r
65 6E 61 6D 69 6E 67 54 02 07 45 78 63 6C 75 64 // enamingT..Exclud
65 01 ) // e.
// Code Size 6 (0x6)
.maxstack 8
IL_0000: ldc.i4 0x75bcd15
IL_0005: ret
} // end of method Class1::Get
After applying Dotfuscator
.method public hidebysig static int32 Get() cil managed
{
// Code Size 127 (0x7f)
.maxstack 2
.locals init (int32 V_0)
IL_0000: ldc.i4 0x993
IL_0005: stloc V_0
IL_0009: ldloca V_0
IL_000d: ldind.i4
IL_000e: ldc.i4 0x993
IL_0013: stloc V_0
IL_0017: ldloca V_0
IL_001b: ldind.i4
IL_001c: ceq
IL_001e: switch (
IL_002f,
IL_004c,
IL_002f)
IL_002f: br.s IL_003e
IL_0031: ldc.i4.0
IL_0032: stloc V_0
IL_0036: ldloca V_0
IL_003a: ldind.i4
IL_003b: pop
IL_003c: br.s IL_004a
IL_003e: ldc.i4.0
IL_003f: stloc V_0
IL_0043: ldloca V_0
IL_0047: ldind.i4
IL_0048: br.s IL_003b
IL_004a: nop
IL_004b: nop
IL_004c: ldc.i4 0x1
IL_0051: stloc V_0
IL_0055: ldloca V_0
IL_0059: ldind.i4
IL_005a: br.s IL_0068
IL_005c: ldc.i4.0
IL_005d: stloc V_0
IL_0061: ldloca V_0
IL_0065: ldind.i4
IL_0066: br.s IL_0068
IL_0068: brfalse.s IL_006a
IL_006a: ldc.i4.0
IL_006b: stloc V_0
IL_006f: ldloca V_0
IL_0073: ldind.i4
IL_0074: brfalse IL_0079
IL_0079: ldc.i4 0x75bcd15
IL_007e: ret
} // end of method Class1::Get
UPDATE: As of version 6.0, Dotfuscator Professional no longer supports Unity. (See changelog for 6.0.0-beta). It continues to support Mono. The original answer follows.
Yes, Dotfuscator Professional Edition supports Mono and Unity. The reason you're seeing differences in the IL is due to the Control Flow obfuscation that Professional Edition provides. This is a distinct from the Renaming feature from which you have excluded your identifiers.
By default, Dotfuscator uses as many Control Flow transforms as it can get away with on the .NET Framework (i.e., Microsoft's implementation). However, some of these transforms are not compatible with Mono. Dotfuscator provides an option to disable such transforms.
After loading your Dotfuscator project in the GUI, this option can be found on the Settings tab, under "Advanced", named "Use only Mono-compatible transforms". Set this option to "Yes", then save and rebuild the project.
If that is still giving you problems, you can disable Control Flow entirely to see if that fixes the problem. This is also on the Settings tab, under "Features", "Disable Control Flow". Set this option to "Yes", then save and rebuild the project.
Full disclosure: I work for the Dotfuscator team at PreEmptive Solutions. If you have more questions, keep in mind that evaluation users like yourself also have full access to PreEmptive support.
I'm interested in viewing the actual x86 assembly output by a C# program (not the CLR bytecode instructions). Is there a good way to do this?
While debugging your application in Visual Studio, you can right-click on a code where you have stopped (using breakpoint) and click "Go to Disassembly". You can debug through native instructions.
As for doing that with *.exe files on disk, maybe you could use NGen to generate native output and then disassemble it (although I never tried that, so I can't guarantee that it will work).
Here are some sample opcodes from simple arithmetic operation that was written in c#:
int x = 5;
mov dword ptr [ebp-40h],5
int y = 6;
mov dword ptr [ebp-44h],6
int z = x + y;
mov eax,dword ptr [ebp-40h]
add eax,dword ptr [ebp-44h]
mov dword ptr [ebp-48h],eax
As #IvanDanilov answered, you can use WinDbg and SOS. I am answering separately to provide a walk-through.
In this example, I want to view the disassembly of the AreEqual() method from:
using System;
namespace TestArrayCompare
{
class Program
{
static bool AreEqual(byte[] a1, byte[] a2)
{
bool result = true;
for (int i = 0; i < a1.Length; ++i)
{
if (a1[i] != a2[i])
result = false;
}
return result;
}
static void Main(string[] args)
{
byte[] a1 = new byte[100];
byte[] a2 = new byte[100];
if (AreEqual(a1, a2))
{
Console.WriteLine("`a1' equals `a2'.");
}
else
{
Console.WriteLine("`a1' does not equal `a2'.");
}
}
}
}
Steps:
Open WinDbg. From the File menu, select "Open Executable...". Browse to the location of the EXE (in my case, C:\Users\Daniel\Documents\Visual Studio 2013\Projects\TestArrayCompare\TestArrayCompare\bin\Release\TestArrayCompare.exe).
Add the directory containing the PDB file to the symbol path. For example:
.sympath "C:\Users\Daniel\Documents\Visual Studio 2013\Projects\TestArrayCompare\TestArrayCompare\bin\Release"
In WinDbg's Command window, set a breakpoint when clr.dll is loaded via:
sxe ld:clr
Continue by running the 'Go' command: g
At the clr.dll ModLoad, load SOS: .loadby sos clr
Run BPMD to break on the method for which you wish to see the disassembly. For example:
0:000> !BPMD TestArrayCompare.exe TestArrayCompare.Program.AreEqual
Adding pending breakpoints...
Continue again by running the 'Go' command: g
Run Name2EE to see the method descriptor. For example:
0:000> !Name2EE TestArrayCompare.exe TestArrayCompare.Program.AreEqual
Module: 00a62edc
Assembly: TestArrayCompare.exe
Token: 06000001
MethodDesc: 00a637a4
Name: TestArrayCompare.Program.AreEqual(Byte[], Byte[])
Not JITTED yet. Use !bpmd -md 00a637a4 to break on run.
Run the BPMD command in the "Not JITTED yet" line. For example:
0:000> !bpmd -md 00a637a4
MethodDesc = 00a637a4
Adding pending breakpoints...
Continue again: g
You should see "JITTED ..." in the Command window. Re-run the Name2EE command to see the address of the JIT code. For example:
0:000> !Name2EE TestArrayCompare.exe TestArrayCompare.Program.AreEqual
Module: 00a62edc
Assembly: TestArrayCompare.exe
Token: 06000001
MethodDesc: 00a637a4
Name: TestArrayCompare.Program.AreEqual(Byte[], Byte[])
JITTED Code Address: 00b500c8
Use the u command to disassemble, starting at the listed code address. For example:
0:000> u 00b500c8 L20
00b500c8 55 push ebp
00b500c9 8bec mov ebp,esp
00b500cb 57 push edi
00b500cc 56 push esi
...
(For the above, I was using WinDbg 6.3.9600.17200 X86 from the Windows 8.1 SDK.)
One handy reference is the SOS.dll (SOS Debugging Extension) reference page on MSDN.
You should use WinDbg with SOS/SOSEX, ensure that method you want to see x86 code for is JITted in method tables and then see actual unassembly with u command. Thus you would see actual code.
As others mentioned here, with ngen you could see code that is not exactly matches actual JIT compilation result. With Visual Studio it is also possible because JIT's compilation depends heavily on the fact if debugger is present or not.
UPD: Some clarification. WinDbg is a debugger also, but it is native one.
Here you can read about the technique in detail.
You could use Visual Studio Debugger by placing a breakpoint and then viewing the Dissassembly window (Alt+Ctrl+D) or try the Native Image Generator Tool (ngen.exe).
You can do a memory dump. However, note that the in-memory code does not necessarily contain every method.
ngen does AOT, or Ahead-of-time code generation, which can be different from JIT code.