flat assembler
Message board for the users of flat assembler.

Index > Heap > Curiosity with VS2008

Goto page 1, 2  Next
Author
Thread Post new topic Reply to topic
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4633
Location: Argentina
LocoDelAssembly
Hi, after bitching for a while because of the extreme inefficiencies I've perceiving by looking at the disassembly window of a VB.NET project (built in Release mode, BTW), I've decided to check with OllyDbg if I was really getting a real approximate of the x86 code that is executed under normal circumstances.

Here with OllyDbg2:
Code:
CPU Disasm
Address   Hex dump          Command                                  Comments
00D20A98    55              PUSH EBP
00D20A99    8BEC            MOV EBP,ESP
00D20A9B    57              PUSH EDI
00D20A9C    56              PUSH ESI
00D20A9D    53              PUSH EBX
00D20A9E    83EC 08         SUB ESP,8
00D20AA1    8BD9            MOV EBX,ECX
00D20AA3    8BCB            MOV ECX,EBX
00D20AA5    8B01            MOV EAX,DWORD PTR DS:[ECX]
00D20AA7    FF90 A0000000   CALL DWORD PTR DS:[EAX+0A0]
00D20AAD    8BF8            MOV EDI,EAX
00D20AAF    C1FF 1F         SAR EDI,1F
00D20AB2    8BF0            MOV ESI,EAX
00D20AB4    8BCB            MOV ECX,EBX
00D20AB6    8B01            MOV EAX,DWORD PTR DS:[ECX]
00D20AB8    FF90 A0000000   CALL DWORD PTR DS:[EAX+0A0]
00D20ABE    99              CDQ
00D20ABF    0FA4C2 08       SHLD EDX,EAX,8
00D20AC3    C1E0 08         SHL EAX,8
00D20AC6    0BC6            OR EAX,ESI
00D20AC8    0BD7            OR EDX,EDI
00D20ACA    8BF0            MOV ESI,EAX
00D20ACC    8BFA            MOV EDI,EDX
00D20ACE    8BCB            MOV ECX,EBX
00D20AD0    8B01            MOV EAX,DWORD PTR DS:[ECX]
00D20AD2    FF90 A0000000   CALL DWORD PTR DS:[EAX+0A0]
00D20AD8    99              CDQ
00D20AD9    0FA4C2 10       SHLD EDX,EAX,10
00D20ADD    C1E0 10         SHL EAX,10
00D20AE0    0BC6            OR EAX,ESI
00D20AE2    0BD7            OR EDX,EDI
00D20AE4    8BF0            MOV ESI,EAX
00D20AE6    8BFA            MOV EDI,EDX
00D20AE8    8BCB            MOV ECX,EBX
00D20AEA    8B01            MOV EAX,DWORD PTR DS:[ECX]
00D20AEC    FF90 A0000000   CALL DWORD PTR DS:[EAX+0A0]
00D20AF2    99              CDQ
00D20AF3    0FA4C2 18       SHLD EDX,EAX,18
00D20AF7    C1E0 18         SHL EAX,18
00D20AFA    0BC6            OR EAX,ESI
00D20AFC    0BD7            OR EDX,EDI
00D20AFE    8BF0            MOV ESI,EAX
00D20B00    8BFA            MOV EDI,EDX
00D20B02    8BCB            MOV ECX,EBX
00D20B04    8B01            MOV EAX,DWORD PTR DS:[ECX]
00D20B06    FF90 A0000000   CALL DWORD PTR DS:[EAX+0A0]
00D20B0C    0BF8            OR EDI,EAX
00D20B0E    8BCB            MOV ECX,EBX
00D20B10    8B01            MOV EAX,DWORD PTR DS:[ECX]
00D20B12    FF90 A0000000   CALL DWORD PTR DS:[EAX+0A0]
00D20B18    99              CDQ
00D20B19    8BD0            MOV EDX,EAX
00D20B1B    C1E2 08         SHL EDX,8
00D20B1E    33C0            XOR EAX,EAX
00D20B20    0BC6            OR EAX,ESI
00D20B22    0BD7            OR EDX,EDI
00D20B24    8BF0            MOV ESI,EAX
00D20B26    8BFA            MOV EDI,EDX
00D20B28    8BCB            MOV ECX,EBX
00D20B2A    8B01            MOV EAX,DWORD PTR DS:[ECX]
00D20B2C    FF90 A0000000   CALL DWORD PTR DS:[EAX+0A0]
00D20B32    99              CDQ
00D20B33    8BD0            MOV EDX,EAX
00D20B35    C1E2 10         SHL EDX,10
00D20B38    33C0            XOR EAX,EAX
00D20B3A    0BC6            OR EAX,ESI
00D20B3C    0BD7            OR EDX,EDI
00D20B3E    8BF0            MOV ESI,EAX
00D20B40    8BFA            MOV EDI,EDX
00D20B42    8BCB            MOV ECX,EBX
00D20B44    8B01            MOV EAX,DWORD PTR DS:[ECX]
00D20B46    FF90 A0000000   CALL DWORD PTR DS:[EAX+0A0]
00D20B4C    99              CDQ
00D20B4D    8BD0            MOV EDX,EAX
00D20B4F    C1E2 18         SHL EDX,18
00D20B52    33C0            XOR EAX,EAX
00D20B54    0BC6            OR EAX,ESI
00D20B56    0BD7            OR EDX,EDI
00D20B58    8BF0            MOV ESI,EAX
00D20B5A    8BFA            MOV EDI,EDX
00D20B5C    8975 EC         MOV DWORD PTR SS:[EBP-14],ESI
00D20B5F    897D F0         MOV DWORD PTR SS:[EBP-10],EDI
00D20B62    DD45 EC         FLD QWORD PTR SS:[EBP-14]
00D20B65    8D65 F4         LEA ESP,[EBP-0C]
00D20B68    5B              POP EBX
00D20B69    5E              POP ESI
00D20B6A    5F              POP EDI
00D20B6B    5D              POP EBP
00D20B6C    C3              RETN    


Now the same with VS2008:
Code:
      Public Shared Function readDouble(ByVal stream As FileStream) As Double
         Dim result As Int64

         result = stream.ReadByte()
00000000  push        ebp  
00000001  mov         ebp,esp 
00000003  push        ebx  
00000004  sub         esp,74h 
00000007  xor         eax,eax 
00000009  mov         dword ptr [ebp-0Ch],eax 
0000000c  mov         dword ptr [ebp-8],eax 
0000000f  mov         dword ptr [ebp-78h],ecx 
00000012  cmp         dword ptr ds:[009795E8h],0 
00000019  je          00000020 
0000001b  call        76BA88F9 
00000020  mov         dword ptr [ebp-14h],0 
00000027  mov         dword ptr [ebp-10h],0 
0000002e  mov         ecx,dword ptr [ebp-78h] 
00000031  mov         eax,dword ptr [ecx] 
00000033  call        dword ptr [eax+000000A0h] 
00000039  mov         dword ptr [ebp-18h],eax 
0000003c  mov         eax,dword ptr [ebp-18h] 
0000003f  cdq              
00000040  mov         dword ptr [ebp-14h],eax 
00000043  mov         dword ptr [ebp-10h],edx 
         result = result Or CLng(stream.ReadByte()) << 8
00000046  mov         eax,dword ptr [ebp-14h] 
00000049  mov         edx,dword ptr [ebp-10h] 
0000004c  mov         dword ptr [ebp-20h],eax 
0000004f  mov         dword ptr [ebp-1Ch],edx 
00000052  mov         ecx,dword ptr [ebp-78h] 
00000055  mov         eax,dword ptr [ecx] 
00000057  call        dword ptr [eax+000000A0h] 
0000005d  mov         dword ptr [ebp-24h],eax 
00000060  mov         eax,dword ptr [ebp-20h] 
00000063  mov         edx,dword ptr [ebp-1Ch] 
00000066  mov         ecx,dword ptr [ebp-24h] 
00000069  mov         ebx,ecx 
0000006b  sar         ebx,1Fh 
0000006e  shld        ebx,ecx,8 
00000072  shl         ecx,8 
00000075  or          eax,ecx 
00000077  or          edx,ebx 
00000079  mov         dword ptr [ebp-14h],eax 
0000007c  mov         dword ptr [ebp-10h],edx 
         result = result Or CLng(stream.ReadByte()) << 16
0000007f  mov         eax,dword ptr [ebp-14h] 
00000082  mov         edx,dword ptr [ebp-10h] 
00000085  mov         dword ptr [ebp-2Ch],eax 
00000088  mov         dword ptr [ebp-28h],edx 
0000008b  mov         ecx,dword ptr [ebp-78h] 
0000008e  mov         eax,dword ptr [ecx] 
00000090  call        dword ptr [eax+000000A0h] 
00000096  mov         dword ptr [ebp-30h],eax 
00000099  mov         eax,dword ptr [ebp-2Ch] 
0000009c  mov         edx,dword ptr [ebp-28h] 
0000009f  mov         ecx,dword ptr [ebp-30h] 
000000a2  mov         ebx,ecx 
000000a4  sar         ebx,1Fh 
000000a7  shld        ebx,ecx,10h 
000000ab  shl         ecx,10h 
000000ae  or          eax,ecx 
000000b0  or          edx,ebx 
000000b2  mov         dword ptr [ebp-14h],eax 
000000b5  mov         dword ptr [ebp-10h],edx 
         result = result Or CLng(stream.ReadByte()) << 24
000000b8  mov         eax,dword ptr [ebp-14h] 
000000bb  mov         edx,dword ptr [ebp-10h] 
000000be  mov         dword ptr [ebp-38h],eax 
000000c1  mov         dword ptr [ebp-34h],edx 
000000c4  mov         ecx,dword ptr [ebp-78h] 
000000c7  mov         eax,dword ptr [ecx] 
000000c9  call        dword ptr [eax+000000A0h] 
000000cf  mov         dword ptr [ebp-3Ch],eax 
000000d2  mov         eax,dword ptr [ebp-38h] 
000000d5  mov         edx,dword ptr [ebp-34h] 
000000d8  mov         ecx,dword ptr [ebp-3Ch] 
000000db  mov         ebx,ecx 
000000dd  sar         ebx,1Fh 
000000e0  shld        ebx,ecx,18h 
000000e4  shl         ecx,18h 
000000e7  or          eax,ecx 
000000e9  or          edx,ebx 
000000eb  mov         dword ptr [ebp-14h],eax 
000000ee  mov         dword ptr [ebp-10h],edx 
         result = result Or CLng(stream.ReadByte()) << 32
000000f1  mov         eax,dword ptr [ebp-14h] 
000000f4  mov         edx,dword ptr [ebp-10h] 
000000f7  mov         dword ptr [ebp-44h],eax 
000000fa  mov         dword ptr [ebp-40h],edx 
000000fd  mov         ecx,dword ptr [ebp-78h] 
00000100  mov         eax,dword ptr [ecx] 
00000102  call        dword ptr [eax+000000A0h] 
00000108  mov         dword ptr [ebp-48h],eax 
0000010b  mov         eax,dword ptr [ebp-44h] 
0000010e  mov         edx,dword ptr [ebp-40h] 
00000111  or          edx,dword ptr [ebp-48h] 
00000114  mov         dword ptr [ebp-14h],eax 
00000117  mov         dword ptr [ebp-10h],edx 
         result = result Or CLng(stream.ReadByte()) << 40
0000011a  mov         eax,dword ptr [ebp-14h] 
0000011d  mov         edx,dword ptr [ebp-10h] 
00000120  mov         dword ptr [ebp-50h],eax 
00000123  mov         dword ptr [ebp-4Ch],edx 
00000126  mov         ecx,dword ptr [ebp-78h] 
00000129  mov         eax,dword ptr [ecx] 
0000012b  call        dword ptr [eax+000000A0h] 
00000131  mov         dword ptr [ebp-54h],eax 
00000134  mov         eax,dword ptr [ebp-50h] 
00000137  mov         edx,dword ptr [ebp-4Ch] 
0000013a  mov         ecx,dword ptr [ebp-54h] 
0000013d  mov         ebx,ecx 
0000013f  sar         ebx,1Fh 
00000142  mov         ebx,ecx 
00000144  shl         ebx,8 
00000147  xor         ecx,ecx 
00000149  or          eax,ecx 
0000014b  or          edx,ebx 
0000014d  mov         dword ptr [ebp-14h],eax 
00000150  mov         dword ptr [ebp-10h],edx 
         result = result Or CLng(stream.ReadByte()) << 48
00000153  mov         eax,dword ptr [ebp-14h] 
00000156  mov         edx,dword ptr [ebp-10h] 
00000159  mov         dword ptr [ebp-5Ch],eax 
0000015c  mov         dword ptr [ebp-58h],edx 
0000015f  mov         ecx,dword ptr [ebp-78h] 
00000162  mov         eax,dword ptr [ecx] 
00000164  call        dword ptr [eax+000000A0h] 
0000016a  mov         dword ptr [ebp-60h],eax 
0000016d  mov         eax,dword ptr [ebp-5Ch] 
00000170  mov         edx,dword ptr [ebp-58h] 
00000173  mov         ecx,dword ptr [ebp-60h] 
00000176  mov         ebx,ecx 
00000178  sar         ebx,1Fh 
0000017b  mov         ebx,ecx 
0000017d  shl         ebx,10h 
00000180  xor         ecx,ecx 
00000182  or          eax,ecx 
00000184  or          edx,ebx 
00000186  mov         dword ptr [ebp-14h],eax 
00000189  mov         dword ptr [ebp-10h],edx 
         result = result Or CLng(stream.ReadByte()) << 56
0000018c  mov         eax,dword ptr [ebp-14h] 
0000018f  mov         edx,dword ptr [ebp-10h] 
00000192  mov         dword ptr [ebp-68h],eax 
00000195  mov         dword ptr [ebp-64h],edx 
00000198  mov         ecx,dword ptr [ebp-78h] 
0000019b  mov         eax,dword ptr [ecx] 
0000019d  call        dword ptr [eax+000000A0h] 
000001a3  mov         dword ptr [ebp-6Ch],eax 
000001a6  mov         eax,dword ptr [ebp-68h] 
000001a9  mov         edx,dword ptr [ebp-64h] 
000001ac  mov         ecx,dword ptr [ebp-6Ch] 
000001af  mov         ebx,ecx 
000001b1  sar         ebx,1Fh 
000001b4  mov         ebx,ecx 
000001b6  shl         ebx,18h 
000001b9  xor         ecx,ecx 
000001bb  or          eax,ecx 
000001bd  or          edx,ebx 
000001bf  mov         dword ptr [ebp-14h],eax 
000001c2  mov         dword ptr [ebp-10h],edx 

         Return BitConverter.Int64BitsToDouble(result)
000001c5  push        dword ptr [ebp-10h] 
000001c8  push        dword ptr [ebp-14h] 
000001cb  call        7626D8E8 
000001d0  fstp        qword ptr [ebp-74h] 
000001d3  fld         qword ptr [ebp-74h] 
000001d6  lea         esp,[ebp-4] 
000001d9  pop         ebx  
000001da  pop         ebp  
000001db  ret    


Lots of Read-After-Write, and some calculations that are overwritten without making any use of them first, no in-lining (BitConverter.Int64BitsToDouble call), etc.

Now I of course knew that the disassembly window had some sort of unreality because the addresses are hardly real, but I was expecting to see some kind of quality yet...

Any idea how to make VS2008 show a more approximate x86 assembly representation of what will actually be executed in a real environment? Even the MSIL code looks more optimal Confused
Code:
method public static float64  readDouble(class [mscorlib]System.IO.FileStream 'stream') cil managed
{
  // Code size       105 (0x69)
  .maxstack  3
  .locals init ([0] float64 readDouble,
           [1] int64 result)
  IL_0000:  ldarg.0
  IL_0001:  callvirt   instance int32 [mscorlib]System.IO.FileStream::ReadByte()
  IL_0006:  conv.i8
  IL_0007:  stloc.1
  IL_0008:  ldloc.1
  IL_0009:  ldarg.0
  IL_000a:  callvirt   instance int32 [mscorlib]System.IO.FileStream::ReadByte()
  IL_000f:  conv.i8
  IL_0010:  ldc.i4.8
  IL_0011:  shl
  IL_0012:  or
  IL_0013:  stloc.1
  IL_0014:  ldloc.1
  IL_0015:  ldarg.0
  IL_0016:  callvirt   instance int32 [mscorlib]System.IO.FileStream::ReadByte()
  IL_001b:  conv.i8
  IL_001c:  ldc.i4.s   16
  IL_001e:  shl
  IL_001f:  or
  IL_0020:  stloc.1
  IL_0021:  ldloc.1
  IL_0022:  ldarg.0
  IL_0023:  callvirt   instance int32 [mscorlib]System.IO.FileStream::ReadByte()
  IL_0028:  conv.i8
  IL_0029:  ldc.i4.s   24
  IL_002b:  shl
  IL_002c:  or
  IL_002d:  stloc.1
  IL_002e:  ldloc.1
  IL_002f:  ldarg.0
  IL_0030:  callvirt   instance int32 [mscorlib]System.IO.FileStream::ReadByte()
  IL_0035:  conv.i8
  IL_0036:  ldc.i4.s   32
  IL_0038:  shl
  IL_0039:  or
  IL_003a:  stloc.1
  IL_003b:  ldloc.1
  IL_003c:  ldarg.0
  IL_003d:  callvirt   instance int32 [mscorlib]System.IO.FileStream::ReadByte()
  IL_0042:  conv.i8
  IL_0043:  ldc.i4.s   40
  IL_0045:  shl
  IL_0046:  or
  IL_0047:  stloc.1
  IL_0048:  ldloc.1
  IL_0049:  ldarg.0
  IL_004a:  callvirt   instance int32 [mscorlib]System.IO.FileStream::ReadByte()
  IL_004f:  conv.i8
  IL_0050:  ldc.i4.s   48
  IL_0052:  shl
  IL_0053:  or
  IL_0054:  stloc.1
  IL_0055:  ldloc.1
  IL_0056:  ldarg.0
  IL_0057:  callvirt   instance int32 [mscorlib]System.IO.FileStream::ReadByte()
  IL_005c:  conv.i8
  IL_005d:  ldc.i4.s   56
  IL_005f:  shl
  IL_0060:  or
  IL_0061:  stloc.1
  IL_0062:  ldloc.1
  IL_0063:  call       float64 [mscorlib]System.BitConverter::Int64BitsToDouble(int64)
  IL_0068:  ret
} // end of method RecordReader::readDouble    



Anyway, I just wanted to post this to warn you that if you want to measure .net JIT quality, using the VS2008 disassembly window is a very bad place to start with.... (The assembly code dumped by OllyDbg it is still sucking a bit of course)

PS: Note that this is not the code I'm particularly interested to have properly optimized as you probably noticed by the multiple ReadByte calls instead of reading into an array. Arrays, OTOH, have an per access bounds check which even calls code to do the check instead of doing it in-line if I recall correctly, but still that would be faster than reading multiple times.
Post 09 Mar 2010, 05:44
View user's profile Send private message Reply with quote
edemko



Joined: 18 Jul 2009
Posts: 549
edemko
Code:
00D20AA1    8BD9            MOV EBX,ECX 
00D20AA3    8BCB            MOV ECX,EBX
    

that is alredy curious
Post 09 Mar 2010, 09:19
View user's profile Send private message Reply with quote
zhak



Joined: 12 Apr 2005
Posts: 490
Location: Belarus
zhak
didn't go deep into that piece of code, but could
00D20AA3 8BCB MOV ECX,EBX
be an entry point to some jump in a loop where EBX stores initial value of ECX?
Post 09 Mar 2010, 09:58
View user's profile Send private message Reply with quote
ouadji



Joined: 24 Dec 2008
Posts: 1081
Location: Belgium
ouadji

serfasm wrote:
Code:
...... (A)
00D20AA1    8BD9            MOV EBX,ECX
00D20AA3    8BCB            MOV ECX,EBX ; (B)
    

that is alredy curious

I can not stand this kind of thing.
Probably remnants of older versions, uncleaned, not optimized.
how horrible ! It's the kind of code that prevents me from sleeping.

edit : only solution ...
a jump from other portion of code on the second opcode.
1) from "A" mov ecx,ecx ; don't change "ecx"
2) Jump to "B" (from anywhere) ... mov ecx,ebx

_________________
I am not young enough to know everything (Oscar Wilde)- Image


Last edited by ouadji on 09 Mar 2010, 11:26; edited 4 times in total
Post 09 Mar 2010, 11:04
View user's profile Send private message Send e-mail Reply with quote
Fanael



Joined: 03 Jul 2009
Posts: 168
Fanael
.NET JIT disables certain optimizations when process is being debugged, so checking disassembly using debugger isn't very bright idea.
Post 09 Mar 2010, 11:06
View user's profile Send private message Reply with quote
vid
Verbosity in development


Joined: 05 Sep 2003
Posts: 7105
Location: Slovakia
vid
Hmm, can VS2008 display disassembly window in release mode at all? Aren't you getting debug mode display (or something like that) by any chance?

It's a long time since I used that whale.
Post 09 Mar 2010, 11:30
View user's profile Send private message Visit poster's website AIM Address MSN Messenger ICQ Number Reply with quote
edfed



Joined: 20 Feb 2006
Posts: 4240
Location: 2018
edfed
Quote:

how horrible ! It's the kind of code that prevents me from sleeping.

it prevents me to use HLL compilers, and then, i can sleep well and deep
Post 09 Mar 2010, 11:39
View user's profile Send private message Visit poster's website Reply with quote
Fanael



Joined: 03 Jul 2009
Posts: 168
Fanael
vid wrote:
Hmm, can VS2008 display disassembly window in release mode at all?
It can. Debugging symbols aren't required for disassembly.
Post 09 Mar 2010, 11:49
View user's profile Send private message Reply with quote
edemko



Joined: 18 Jul 2009
Posts: 549
edemko
Have you noticed the first proc presented:
-it uses registers only thus optimized
-
Code:
00D20A98    55              PUSH EBP                    ; entered once
00D20A99    8BEC            MOV EBP,ESP                 ; entered once
00D20A9B    57              PUSH EDI                    ; entered once
00D20A9C    56              PUSH ESI                    ; entered once
00D20A9D    53              PUSH EBX                    ; entered once
00D20A9E    83EC 08         SUB ESP,8                   ; entered once as...
00D20AA1    8BD9            MOV EBX,ECX                 ; ...this being accepted...
00D20AA3    8BCB            MOV ECX,EBX                 ; ...makes this redundant so it could be ret-point
00D20AA5    8B01            MOV EAX,DWORD PTR DS:[ECX]  ; it must be an array...
00D20AA7    FF90 A0000000   CALL DWORD PTR DS:[EAX+0A0] ; ...you have to process part a part
    

-etc
-LocoDelAssembly, could you put c++ etc sources?
-is being done just for fun
Post 09 Mar 2010, 15:58
View user's profile Send private message Reply with quote
edemko



Joined: 18 Jul 2009
Posts: 549
edemko
Quote:

00D20AA7 FF90 A0000000 CALL DWORD PTR DS:[EAX+0A0]

?*?, proc array?
Sources needed.
Answering give your name transcription, please.
Post 09 Mar 2010, 16:03
View user's profile Send private message Reply with quote
Fanael



Joined: 03 Jul 2009
Posts: 168
Fanael
Looks like virtual function call for me.
Post 09 Mar 2010, 16:22
View user's profile Send private message Reply with quote
edfed



Joined: 20 Feb 2006
Posts: 4240
Location: 2018
edfed
looks like function pointer in item for me.

Code:
itemarray:
dd item1
dd item2
dd item3
...
item1:
params rb 160
functionptr dd function
...
mov ecx,itemarray
call this
...
this:
...
mov ebx,ecx ;save item
;then, an atomic code copied many times.
mov ecx,ebx ;restore item
mov eax,[ecx]
call dword[eax+160]
...
mov ecx,ebx ;restore item
mov eax,[ecx]
call dword[eax+160]
...
mov ecx,ebx ;restore item
mov eax,[ecx]
call dword[eax+160]
...
    

i do something like this with fool. Very Happy
Post 09 Mar 2010, 16:36
View user's profile Send private message Visit poster's website Reply with quote
Fanael



Joined: 03 Jul 2009
Posts: 168
Fanael
If someone didn't know that before, virtual functions are usually implemented as function pointers (the object holds a pointer to the vtable - an array of pointers to the virtual functions), as in this example (I know it's pretty sloppy, but I'm not in mood to make anything better):
Code:
format PE console
entry start
include 'win32a.inc'

; "class" foo
struct foo
  vtable dd ?
  field dd ?
ends

; "class" bar (inherits from foo)
struct bar
  parent foo
  field2 dd ?
ends

section '.text' code readable executable

start:
  mov ecx, fooobj
  call print_anything_what_inherits_from_foo
  mov ecx, barobj
  call print_anything_what_inherits_from_foo
  invoke ExitProcess, 0
  
;; @brief Prints an object of class which inherits from foo
;;
;; @param ecx This pointer.
align 16
print_anything_what_inherits_from_foo:
  ; fetch pointer to the vtable
  mov eax, [ecx + foo.vtable]
  ; call the method
  call [eax + FooVTable.printMethod]
  ; ok, maybe jmp should be used here instead of call/ret
  ret
 
; a virtual method printing foo object
align 16
foo_print:
  cinvoke printf, fooprintfmt, [ecx + foo.field]
  ret
 
; a virtual method printing bar object
align 16
bar_print:
  cinvoke printf, barprintfmt, [ecx + bar.parent.field], [ecx + bar.field2]
  ret 
  
section '.data' data readable writeable

; declare object of foo
fooobj foo foo_vtable, 666
; and of bar
barobj bar <bar_vtable, 69>, 666

section '.rdata' data readable

struct FooVTable
  printMethod dd ?
ends

foo_vtable FooVTable foo_print
bar_vtable FooVTable bar_print
  
fooprintfmt db "foo, field1: %d", 10, 0
barprintfmt db "bar, field1: %d, field2: %d", 10, 0

section '.idata' import data readable writeable

library\
  kernel32, 'kernel32.dll',\
  msvcrt, 'msvcrt.dll'
  
include 'api/kernel32.inc'

import msvcrt,\
  printf, 'printf'
    
Post 09 Mar 2010, 17:04
View user's profile Send private message Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4633
Location: Argentina
LocoDelAssembly
Guys, the source is already available in the disassembly output of VS2008 (the Assembly code is between HLL lines). The code is VB.NET, not C++. The virtual call is the stream.ReadByte() call.

serfasm, there are more interesting sequences in the OllyDbg dump, like: this one:
Code:
00D20AE0    0BC6            OR EAX,ESI
00D20AE2    0BD7            OR EDX,EDI
00D20AE4    8BF0            MOV ESI,EAX
00D20AE6    8BFA            MOV EDI,EDX     


vid, it is in release mode, and contrary to C++ (native) where I get decent results in the disassembly output (and AFAIK, the real one), here I don't.
Code:
------ Build started: Project: xyzw, Configuration: Release Any CPU ------    
That is the message I get when I compile&run the code.

Fanael, OK, will find another method to defer OllyDbg existence.
Post 09 Mar 2010, 17:06
View user's profile Send private message Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4633
Location: Argentina
LocoDelAssembly
Well, modifications were not needed, DebugBreak call already interrupts the program and allows me to fire up OllyDbg (I though that DebugBreak was a "nop" when running outside a debugger here).

Results: same output.

The firing code:
Code:
Imports System.Runtime.InteropServices
Imports System.IO

Module Module1

   <DllImport("KERNEL32.DLL", EntryPoint:="DebugBreak", _
     SetLastError:=False, CharSet:=CharSet.Unicode, _
     ExactSpelling:=True, _
     CallingConvention:=CallingConvention.StdCall)> _
     Public Sub DebugBreak()
   End Sub

   Sub Main()
      Dim buffer(200) As Byte
      Dim stream As New MemoryStream(buffer)

      Console.WriteLine(RecordReader.readDouble(stream))
      DebugBreak()
      RecordReader.readDouble(stream)
   End Sub

End Module    

Disassembly of it (OllyDbg):
Code:
00D10070   55               PUSH EBP
00D10071   8BEC             MOV EBP,ESP
00D10073   57               PUSH EDI
00D10074   56               PUSH ESI
00D10075   BA C9000000      MOV EDX,0C9
00D1007A   B9 02410C79      MOV ECX,790C4102
00D1007F   E8 9821C6FF      CALL 0097221C
00D10084   8BF8             MOV EDI,EAX
00D10086   B9 E4D53279      MOV ECX,7932D5E4
00D1008B   E8 E7841779      CALL mscorwks.79E88577
00D10090   8BF0             MOV ESI,EAX
00D10092   8BD7             MOV EDX,EDI
00D10094   8BCE             MOV ECX,ESI
00D10096   E8 B5405378      CALL mscorlib.79244150
00D1009B   8BCE             MOV ECX,ESI
00D1009D   FF15 34319800    CALL DWORD PTR DS:[983134]               ; First time the pointer points to something different (the JIT compiler?) and then control is transfered to readDouble.
00D100A3   DDD8             FSTP ST
00D100A5   E8 72BFC7FF      CALL 0098C01C                            ; Must be the DebugBreak() call. OllyDbg enters here.
00D100AA   8BCE             MOV ECX,ESI
00D100AC   FF15 34319800    CALL DWORD PTR DS:[983134]               ; Second call to readDouble. This time, execution is transfered directly to the readDouble compiled code.
00D100B2   DDD8             FSTP ST
00D100B4   5E               POP ESI
00D100B5   5F               POP EDI
00D100B6   5D               POP EBP
00D100B7   C3               RETN    


PS: I've changed readDouble to accept an Stream object instead of a FileStream because of two reasons, one that it allows me to use a MemoryStream and second is that the function does not really has a mandatory need of using a file, any stream is OK.
Post 09 Mar 2010, 17:45
View user's profile Send private message Reply with quote
f0dder



Joined: 19 Feb 2004
Posts: 3170
Location: Denmark
f0dder
LocoDelAssembly wrote:
PS: Note that this is not the code I'm particularly interested to have properly optimized as you probably noticed by the multiple ReadByte calls instead of reading into an array. Arrays, OTOH, have an per access bounds check which even calls code to do the check instead of doing it in-line if I recall correctly, but still that would be faster than reading multiple times.
I don't know if .NET does this, but at least theoretically for some code constructs, it would be possible hoisting the bounds-checking out of the loop.

And you could always use an unsafe block and do pointer manipulation if you really want to Smile

The generated code above looks weird for a non-debug build. Perhaps the JITer has decided that this isn't a hotspot, and thus used a quick rather than thorough JIT?
Post 10 Mar 2010, 07:55
View user's profile Send private message Visit poster's website Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4633
Location: Argentina
LocoDelAssembly
Quote:

And you could always use an unsafe block and do pointer manipulation if you really want to
The class will be used in an ASP.NET project so I don't really want to force the admin to allow unmanaged code Wink (Will be used in a per application loading basis, so the inefficiencies from mine and the compiler are unimportant here)

I'll try with a loop later, but it looks to me that it won't go much farther, application loading can't take shit loads of time to start so I don't think it can really match the optimizations from the C++ (native) compiler.
Post 10 Mar 2010, 16:19
View user's profile Send private message Reply with quote
f0dder



Joined: 19 Feb 2004
Posts: 3170
Location: Denmark
f0dder
LocoDelAssembly wrote:
I'll try with a loop later, but it looks to me that it won't go much farther, application loading can't take shit loads of time to start so I don't think it can really match the optimizations from the C++ (native) compiler.
I've heard that the Java VM and .NET VM supposedly look a bit at "hit count" at runtime, and will optimize hotspots more agressively... but never looked into the issue myself, nor seen official documentation Smile
Post 10 Mar 2010, 17:07
View user's profile Send private message Visit poster's website Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4633
Location: Argentina
LocoDelAssembly
Quote:

I don't know if .NET does this, but at least theoretically for some code constructs, it would be possible hoisting the bounds-checking out of the loop.

Just checked ECMA-335, in Annex F - Imprecise faults, it says that if a method is marked "relaxed" then optimizations like moving bounds check outside the loop is possible. Something interesting I've seen is that .Net has some provisions for autothreading a loop (again, if the method is "relaxed").

Here how to enable this: http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.compilationrelaxationsattribute.aspx
Post 10 Mar 2010, 17:35
View user's profile Send private message Reply with quote
godomega



Joined: 21 Jun 2005
Posts: 8
godomega
Quote:
I've heard that the Java VM and .NET VM supposedly look a bit at "hit count" at runtime, and will optimize hotspots more agressively... but never looked into the issue myself, nor seen official documentation.

Java runtime also byte interprets small methods directly if it thinks the compiling overhead is too high and/or uses a call counter to see when it's eligible to do real compilation. I've never heard about it optimizing with multiple passes. It's an interesting idea though.
I'm very sure ms-JIT doesn't inhibit any such behavior though and compiles single-pass only.

It's sad how JIT screws up its complete potential. I mean it doesn't dare to touch any sse instructions. They haven't any good reason to do so, they create code DYNAMICLY which means they can check compatibility of instruction sets and even can make it completely processor specific if they wanted to.
Post 12 Mar 2010, 23:58
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  
Goto page 1, 2  Next

< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You can attach files in this forum
You can download files in this forum


Copyright © 1999-2020, Tomasz Grysztar. Also on YouTube, Twitter.

Website powered by rwasa.