flat assembler
Message board for the users of flat assembler.

Index > Windows > VisualC++ ASM output

Author
Thread Post new topic Reply to topic
denial



Joined: 12 Sep 2004
Posts: 98
denial
Hello!

For learning purposes, I wanted to take a look at the ASM code generated by a compiler like VisualC++.... I put in a very simple console-application that declares an integer (int x) and makes some operations with it like x=100; x=x/3; and so on. Here's what I got:

Code:
3:    void main()
4:    {
00401010   push        ebp
00401011   mov         ebp,esp
00401013   sub         esp,44h
00401016   push        ebx
00401017   push        esi
00401018   push        edi
00401019   lea         edi,[ebp-44h]
0040101C   mov         ecx,11h
00401021   mov         eax,0CCCCCCCCh
00401026   rep stos    dword ptr [edi]
5:        int x;
6:        x=100;
00401028   mov         dword ptr [ebp-4],64h
7:        x=x+5;
0040102F   mov         eax,dword ptr [ebp-4]
00401032   add         eax,5
00401035   mov         dword ptr [ebp-4],eax
8:        x=x/3;
00401038   mov         eax,dword ptr [ebp-4]
0040103B   cdq
0040103C   mov         ecx,3
00401041   idiv        eax,ecx
00401043   mov         dword ptr [ebp-4],eax
9:        getch();
00401046   call        _getch (0040b7a0)
10:   }
0040104B   pop         edi
0040104C   pop         esi
0040104D   pop         ebx
0040104E   add         esp,44h
00401051   cmp         ebp,esp
00401053   call        __chkesp (00401130)
00401058   mov         esp,ebp
0040105A   pop         ebp
0040105B   ret
    


I wondered how it works - I guess the stuff with edi, esi, esp at the beginning and ending of the main function are for handling local data. But how does it work? To be honest, until now I used FASMs macros to handle local data, but I'm interested how it works in pure Assembler.
And what about that function call "__chkesp"?

And here, something else: Why gets 100 asigned through hexadecimal value? Is it faster than decimal?

Code:
mov         dword ptr [ebp-4],64h
    


Sorry if I have silly questions, but I'm still learning. Smile
Thank you
Post 25 May 2005, 15:58
View user's profile Send private message Reply with quote
shaolin007



Joined: 03 Sep 2004
Posts: 65
shaolin007
The 1st part
Code:
00401010   push        ebp 
00401011   mov         ebp,esp   [color=red] this is a stack frame setup[/red]
00401013   sub         esp,44h    [color=red]Allocate 68bytes for local variables[/red]
00401016   push        ebx 
00401017   push        esi           [color=red]saving state of these registers[/red]
00401018   push        edi 
00401019   lea         edi,[ebp-44h] [color=red]getting address of ebp-44h for
                                                    rep stos instruction
0040101C   mov         ecx,11h        [color=red] This is the count for rep stos or write 68 bytes[/red]
00401021   mov         eax,0CCCCCCCCh [color=red]??? I have no idea why this value is written to 68 bytes[/red]
00401026   rep stos    dword ptr [edi][color=red]mov eax into contents of [edi] [/red]
    


The second part is self explanatory. The 3rd part though...

Code:
[color=red] restore registers and destroy stack frame[/red]
0040104B   pop         edi 
0040104C   pop         esi          
0040104D   pop         ebx 
0040104E   add         esp,44h [color=red]unallocate 68 bytes used[/red]
00401051   cmp         ebp,esp 
00401053   call        __chkesp (00401130)[color=red] maybe double checking
to see if stack is corrupted?[/red] 
00401058   mov         esp,ebp 
0040105A   pop         ebp 
0040105B   ret 
    


[color=green]
And here, something else: Why gets 100 asigned through hexadecimal value? Is it faster than decimal?
[/green]

Usually when you debug/disassemble its going to show in hex.
Post 25 May 2005, 16:46
View user's profile Send private message Reply with quote
Nikolay Petrov



Joined: 22 Apr 2004
Posts: 101
Location: Bulgaria
Nikolay Petrov
__chkesp is a runtime check function.
I don't remember, but I think that you will turn off it with
#pragma runtime_checks ...
or
/RTC "cl" compiler option
by the way bcc32 generate this:
Code:
_main   proc    near
?live1@0:
   ;
   ;    main()
   ;
        push      ebp
        mov       ebp,esp
        push      ebx
   ;
   ;    {
   ;     int x;
   ;     x=100;
   ;
@1:
        mov       ebx,100
   ;
   ;     x=x+5;
   ;
?live1@32: ; EBX = x
        add       ebx,5
   ;
   ;     x=x/3;
   ;
        mov       eax,ebx
        mov       ecx,3
        cdq
        idiv      ecx
        mov       ebx,eax
   ;
   ;     getch();
   ;
        call      _getch
   ;
   ;     return x;
   ;
        mov       eax,ebx
   ;
   ;    }
   ;
?live1@96: ;
@3:
@2:
        pop       ebx
        pop       ebp
        ret
_main   endp    


Last edited by Nikolay Petrov on 25 May 2005, 18:17; edited 1 time in total
Post 25 May 2005, 18:01
View user's profile Send private message Reply with quote
denial



Joined: 12 Sep 2004
Posts: 98
denial
Thank you for your answers.
So if I read it right, BCC compiler doesn't generate a place for local data at all, is that correct?
So I may guess that BCC recognizes that there isnt much local data to declare, so EBX can be used to get faster results. Correct me if I am wrong.

Anyway, I don't understand why VC++ allocated 68 bytes as I am just using one DWORD value. I heard that most compilers allocate more data while debug-mode for security. Maybe it is about that?
Post 25 May 2005, 18:06
View user's profile Send private message Reply with quote
shaolin007



Joined: 03 Sep 2004
Posts: 65
shaolin007
"by the way bcc32 generate this" Nickolay

"So if I read it right, BCC compiler doesn't generate a place for local data at all, is that correct?" denial

Looks like Nickolay is using _fastcall calling convention where as the other uses _cedecl.
Post 25 May 2005, 18:19
View user's profile Send private message Reply with quote
Nikolay Petrov



Joined: 22 Apr 2004
Posts: 101
Location: Bulgaria
Nikolay Petrov
denial wrote:
... BCC compiler doesn't generate a place for local data at all, is that correct?
Not always - it rests from the programe. It's a TASM compatible code. Linker generate similar code from obj file, not at 100% identical like from the "clear" assebler programe.

denial wrote:
So I may guess that BCC recognizes that there isnt much local data to declare, so EBX can be used to get faster results. Correct me if I am wrong.
i don't know about it. May be you right.
denial wrote:
Anyway, I don't understand why VC++ allocated 68 bytes as I am just using one DWORD value. I heard that most compilers allocate more data while debug-mode for security. Maybe it is about that?
Finaly "machine" code will be similar not like debug-mode.
Post 25 May 2005, 19:09
View user's profile Send private message Reply with quote
r22



Joined: 27 Dec 2004
Posts: 805
r22
When compiling with VC++ to check out it's ASM rolling make sure to compile the code in RELEASE mode this will get rid of all the debugging stuff like _chkesp and also try to optimize the code for speed.

RELEASE > Build | Configurations | select release instead of debug
SPEED OPTIMIZED > Project | Settings | C/C++ tab | Optimizations (select Maximize Speed)

Compilers do a decent job of optimizing code using only the most compatible opcodes, but because their goal is portability over power they ignore simple optimizations like using MMX to unroll a loop.
Short paper I wrote: kryogeniks.com/projects/VCppVSASM.txt
Post 25 May 2005, 19:52
View user's profile Send private message AIM Address Yahoo Messenger Reply with quote
denial



Joined: 12 Sep 2004
Posts: 98
denial
The paper you wrote is very interesting - thank you for that well done work. And thank you all for your answers. Anyway, I want to learn writing assembly without those macros.
Post 26 May 2005, 08:04
View user's profile Send private message Reply with quote
denial



Joined: 12 Sep 2004
Posts: 98
denial
I'm sorry for a double-post, but it is important.
Based on your paper, I tried to write an own local function, but I don't know if everything is right. It compiles and executes fine, but I learned that not all problems in assembly can be obvious Wink
So can someone check it for me? Would be nice Smile

Code:
  start:

        call    _testlocal

        push    0
        call    [ExitProcess]

  _testlocal:
        .a equ ebp-4            ;save adress of local var
                                ;for easy handling
        push ebp
        mov ebp,esp
        sub esp,4               ;allocate space for one dword

        mov dword [.a],000030h ;set dword to MB_EXCLAMATION
        push dword[.a]          ;push in reverse order
        push _caption
        push _message
        push 0
        call [MessageBox]       ;call
        
        add esp,4               ;restore data
        mov esp,ebp
        pop ebp
        ret 0
    
Post 26 May 2005, 09:16
View user's profile Send private message Reply with quote
Torrey



Joined: 12 Oct 2003
Posts: 78
Torrey
The local function works perfectly, you could also get rid of few instructions.

Code:
  start:

        call    _testlocal

        push    0
        call    [ExitProcess]

  _testlocal:
        .a equ ebp-4            ;save adress of local var
                                ;for easy handling
        push ebp
        mov ebp,esp
        sub esp,4               ;allocate space for one dword

        mov dword [.a],000030h  ;set dword to MB_EXCLAMATION
        push _caption
        push _message
        push 0
        call [MessageBox]       ;call

        mov esp,ebp
        pop ebp
        ret
    
Post 26 May 2005, 09:35
View user's profile Send private message Visit poster's website Reply with quote
denial



Joined: 12 Sep 2004
Posts: 98
denial
Thank you..... and if I want to create local arrays / strings with bigger size? Or structures? Lets say I want two dwords, and a string of the size 35... can I just adress them like this?

.a equ ebp-35
.b equ ebp-39
.c equ ebp-43

and allocate the needed space then?

sub esp, 43?
Post 26 May 2005, 14:30
View user's profile Send private message Reply with quote
r22



Joined: 27 Dec 2004
Posts: 805
r22
If the array is short than using then using the stack to reserve space for it locally is fine. There's good amount of space on the stack for doing local allocations. but if the arrays or strings are very large ( > ~1mb) you may just want to allocate 1 dword and use an API function like VirtualAlloc and then store the return value of the API in the local space you created.

For example...
Code:
Function:
.array1 equ ebp-4
.array2 equ ebp-8
push ebp
mov ebp,esp
sub esp,8
push esi
push edi
     push 4     ;readwrite
     push 1000h ;mem commit
     push 4000000 ;1million dwords  array1[0-999,999]
     push 0
     call [VirtualAlloc]
mov [.array1],eax
     push 4     ;readwrite
     push 1000h ;mem commit
     push 4000000 ;1million dwords
     push 0
     call [VirtualAlloc]
mov [.array2],eax
; now that the large local arrays are allocated To modify values...
mov esi, [.array1]
mov edi, [.array2]
mov ecx, 999999
xor eax,eax
xor edx,edx
dec edx
;fill array1 with 0's(eax) and array2 with -1's(edx) (unoptimized)
.label1:
mov [esi+ecx*4],eax
mov [edi+ecx*4],edx
dec ecx
jns .label1 ;when ECX = -1 the loop is done
; now its the end of the function so you need to FREE alloc'd memory
     push 8000h ;mem release
     push 0
     push dword[.array1]
     call [VirtualFree]
     push 8000h ;mem release
     push 0
     push dword[.array2]
     call [VirtualFree]
pop edi
pop esi
add esp,8
mov esp,ebp
pop ebp
ret 0
    
Post 27 May 2005, 19:45
View user's profile Send private message AIM Address Yahoo Messenger Reply with quote
denial



Joined: 12 Sep 2004
Posts: 98
denial
Thank you very much fir your help. The last snipped was pretty helpful.
Post 01 Jun 2005, 12:07
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< 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 cannot attach files in this forum
You can download files in this forum


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

Website powered by rwasa.