#1
|
||||
|
||||
Reflector gets wrong decompiling result?
same dll and same function body, different decompiling results for Reflector, dotPeek, dnSpy(all are latest versions).
Reflector Code:
private uint e(byte[] a, ref int b) { b += 4; return BitConverter.ToUInt32(a, b); } Code:
private uint e(byte[] a, ref int b) { int uint32 = (int) BitConverter.ToUInt32(a, b); b += 4; return (uint) uint32; } Code:
.method private hidebysig instance unsigned int32 e( unsigned int8[] a, int32& b ) cil managed { .maxstack 8 IL_0000: ldarg.1 // a IL_0001: ldarg.2 // b IL_0002: ldind.i4 IL_0003: call unsigned int32 [mscorlib]System.BitConverter::ToUInt32(unsigned int8[], int32) IL_0008: ldarg.2 // b IL_0009: ldarg.2 // b IL_000a: ldind.i4 IL_000b: ldc.i4.4 IL_000c: add IL_000d: stind.i4 IL_000e: ret } // end of method e
__________________
AKA Solomon/blowfish. |
The Following User Says Thank You to WhoCares For This Useful Post: | ||
chants (02-26-2019) |
#2
|
|||
|
|||
Reflector has bad dataflow optimization semantics now apparently in ref arg cases
|
#3
|
||||
|
||||
Nah, Reflector is the one who got it right.
Seems the others got thoroughly confused there ... int uint32 = .. |
The Following User Says Thank You to deepzero For This Useful Post: | ||
chants (02-27-2019) |
#4
|
|||
|
|||
Yup I meant other way around, Reflector right
|
#5
|
||||
|
||||
"b +=4;", should appear first or last?
__________________
AKA Solomon/blowfish. |
#6
|
||||
|
||||
First.
Code:
IL_0000: ldarg.1 // load a IL_0001: ldarg.2 // load b (which is a reference) IL_0002: ldind.i4 //dereference b (bc it is is reference: int&) IL_0003: call BitConverter::ToUInt() //call and put result on stack Code:
IL_0008: ldarg.2 // load b on stack for later use IL_0009: ldarg.2 // load b IL_000a: ldind.i4 //dereference it IL_000b: ldc.i4.4 //load interger-constant "4" to stack IL_000c: add //add the values of b and "4" and put the result on the stack Code:
<value: result of b+4> <reference: b> (was loaded at IL_0008) <value: return value of the BitConverter call> Then the last piece of the puzzle: Code:
IL_000d: stind.i4 //store the result of "b+4" in b Code:
<value: return value of the BitConverter call> Code:
IL_000e: ret So in conclusion the method does two things: 1) b += 4 and 2) return BitConverter(). So reflector is right and the others are wrong. You should file a bug report. A more literal decompilation would be: Code:
private uint e(byte[] a, ref int b) { uint32 tmp = BitConverter.ToUInt32(a, b); b += 4; return tmp; } |
#7
|
||||
|
||||
ok, I understand those IL instructions now. thanks!
Besides ECMA specification, MS also documents the instructions: https://docs.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes.ldind_i4?view=netframework-4.7.2
__________________
AKA Solomon/blowfish. |
#8
|
|||
|
|||
However, if the referenced value (b) is unused, in all caller contexts which invoke this function, then theoretically
Quote:
|
#9
|
||||
|
||||
"b" is used as an incremental pointer/index to the buffer "a", so "b +=4;" can't be optimized out.
Later there are more parsing of the buffer data by calling the function e(a, b) many times.
__________________
AKA Solomon/blowfish. |
#10
|
|||
|
|||
I just meant in those cases where caller never uses 'b' after the call then the assignment is optimizable (not the addition as you mention its an index):
Quote:
|
Thread Tools | |
Display Modes | |
|
|
Similar Threads | ||||
Thread | Thread Starter | Forum | Replies | Last Post |
Decompiling the mov compiler | chants | General Discussion | 3 | 12-08-2016 21:16 |
Who are familiar with decompiling? | DMichael | General Discussion | 3 | 08-09-2013 01:04 |
VB3 decompiling | wasq | General Discussion | 23 | 05-23-2005 02:30 |