flat assembler
Message board for the users of flat assembler.

Index > Windows > Correct Procedures?

Author
Thread Post new topic Reply to topic
Zero



Joined: 02 Aug 2008
Posts: 16
Zero
Hello everyone,

I am a completely new assembly programmer. I've read as many tutorials as possible, but finally decided that the best way to learn is to start programming.

For my first program I tried to write a simple program to calculate ax^2 + bx + c. I quickly figured out that I would need a procedure to convert a string to an integer(positive or negative). Using snippets of code from this site, I wrote the following program and procedure,(which I put in a separate include file).

The relevant portion of program:
Code:
format PE Console

include 'win32ax.inc'
include 'stuff.inc'

entry start
section '.data' data readable writeable

    buffer:  times 512 db 0
 
    prompt  db    'Enter a number',13,10
      answer  db    'The answer is: ',13,10
 
    stdin   dd    ?
     stdout  dd    ?
     count   dd    ?

 num     dw    0
     a       dd    4
     b       dd    3
     c       dd    5
     x       dd    ?
     result  dd    0
     ;sign   db    0
     sresult: times 100 db 0    


section '.code' code readable writeable

start:
      
    ;ax^2 + bx + c

  invoke GetStdHandle, STD_INPUT_HANDLE
       mov [stdin],eax
     
    invoke GetStdHandle, STD_OUTPUT_HANDLE
      mov [stdout],eax

        invoke WriteConsole,[stdout],prompt,16,count,0
      invoke ReadConsole,[stdin],buffer,512,count,0
       
    ;calculate x^2  

        push    buffer
      stdcall a2int     


The procedure:
Code:

proc a2int uses esi ebx,lpbuffer:DWORD

locals
sign db    0
endl

mov      esi,[ebp+8]
         xor   eax,eax

           movzx ebx,byte[esi]             ;fetch a digit
      cmp   ebx,45                    ;is the first char '-'
    
    je    nega                      ;if so, set the flag
        jmp   @f                        ;otherwise its positive

nega:        inc   esi
   mov   [sign],1
      
@@:     movzx ebx,byte[esi]             ;form the number

        lea   eax,[eax*5]               
            lea   eax,[eax*2+ebx-"0"]     
                                            
            add   esi,1
         cmp   byte[esi],13              ;C.R signals end of number
          jne   @b
                                            

        cmp [sign],1                    ;if flag is set, number is
  je  flip                        ;negative so subtract from 0
        jmp  pos
flip:   neg eax
pos:     
    ret
endp    


Everything "seems" to be working right. My question is about the stack. When I check it with ollydbg, I see:

ebx..........esi..............esp...............ebp...........returnaddress................first parameter
ESP................................................EBP

So to access the parameter, I use EBP+8. Ok....that makes sense. But why is it that after the old EBP is pushed, then ESP is pushed? I'm confused as to why that is happening.

Thanks for the help. I've only been programming in assembly for a few days, and i'm really enjoying it. However, i'm sure my code is filled with tons of mistakes Embarassed
Post 02 Aug 2008, 21:12
View user's profile Send private message Reply with quote
Everhest



Joined: 26 Jun 2008
Posts: 84
Location: Russia
Everhest
Zero wrote:
But why is it that after the old EBP is pushed, then ESP is pushed? I'm confused as to why that is happening.


No. Stack as straightedge with crawler Smile, if ebp is pushed then on copied in [esp-4].

Zero wrote:

push buffer
stdcall a2int

??? easier will so

Code:
    
        stdcall a2int, buffer    


Since time shall else render my aid.

_________________
Forgive for my bad english, I from russia...
Post 03 Aug 2008, 09:33
View user's profile Send private message ICQ Number Reply with quote
Zero



Joined: 02 Aug 2008
Posts: 16
Zero
Quote:
No. Stack as straightedge with crawler Smile, if ebp is pushed then on copied in [esp-4].


Right, I understand this, and maybe i'm wrong, but when I look at the values on the stack....after EBP I see ESP. So for my procedure, there are a total of 6 values that are pushed on the stack, but in my head i'm only expecting 5 (esi,ebx,ebp,ret, and buffer).

Also, if anyone notices any other mistakes i've made, or maybe has suggestions on how to optimize or improve the procedure, i'd appreciate the help. I'm really new to all of this and i'm trying my best to learn.
Post 03 Aug 2008, 20:02
View user's profile Send private message Reply with quote
asmcoder



Joined: 02 Jun 2008
Posts: 784
asmcoder
[content deleted]


Last edited by asmcoder on 14 Aug 2009, 14:56; edited 1 time in total
Post 03 Aug 2008, 20:28
View user's profile Send private message Reply with quote
Madis731



Joined: 25 Sep 2003
Posts: 2140
Location: Estonia
Madis731
Zero wrote:
So for my procedure, there are a total of 6 values that are pushed on the stack, but in my head i'm only expecting 5 (esi,ebx,ebp,ret, and buffer).

Good to hear that you've learned a lot in these few days. Now I tried to answer really simply what is happening.
These 6 are as follows:
1) buffer - this one you're pushing manually
2) return address - the stdcall remembers it for you
now it gets tricky because its hidden for the user convenience
3) ebp is pushed because proc wants to use it
mov ebp,esp <= this is where its overwritten
4) sub esp,4 - this is a kind of push that only preserves space i.e. nothing is stored there...yet
5) esi - it is pushed because you told it to: a2int uses esi
6) ebx - the same...

Look at #4 - the space is preserved for sign db 0, in OllyDbg you can also see that there's an instruction MOV BYTE[EBP-4],0. This instruction writes 0 to that 'sign'-variable.

Tomorrow I will teach you how to make it work (you have at least one bug) and help you optimize for readability, size and speed Smile

_________________
My updated idol Very Happy http://www.agner.org/optimize/
Post 03 Aug 2008, 22:58
View user's profile Send private message Visit poster's website Yahoo Messenger MSN Messenger Reply with quote
Zero



Joined: 02 Aug 2008
Posts: 16
Zero
Madis731 wrote:


Tomorrow I will teach you how to make it work (you have at least one bug) and help you optimize for readability, size and speed Smile


Awesome. I'm looking forward to reading what you'll have to say. I've become addicted to assembly Smile
Post 04 Aug 2008, 20:28
View user's profile Send private message Reply with quote
Madis731



Joined: 25 Sep 2003
Posts: 2140
Location: Estonia
Madis731
Try understanding this and if you have questions, just ask. Here are a few starters for you. I'm in a good mood today Very Happy
1) See how I got rid of most of the jumps and labels. Jumps are usually bad, because CPU might not predict them and have slow performance. Not that it matters in a piece of code like this, but for general knowledge, this habit should be maintained
2) You don't actually need all those "a dd 4" etc. because they seem to be constants. In the future, if you are going to ask user for these values, then the data should look like "a dd ?" and moved to the end. That's what I did with sresult, its space is only reserved, not initialized.
3) int2a is a new routine I added. Because of its behaviour I needed to shift the digits to their correct place, that is why there's movsb used.
4) The last line of ReadConsole is there to make an artificial pause. Enter, for example, exits the program.
Code:
format PE Console

include 'win32a.inc'

entry start

section '.code' code readable writeable

start:
       
        ;ax^2 + bx + c
        invoke  GetStdHandle, STD_INPUT_HANDLE
        mov     [stdin],eax
       
        invoke  GetStdHandle, STD_OUTPUT_HANDLE
        mov     [stdout],eax

        invoke  WriteConsoleA,[stdout],prompt,16,count,0
        invoke  ReadConsoleA,[stdin],buffer,512,count,0
       
        ;calculate x^2
        stdcall a2int,buffer
        mov     [x],eax
        ;Here you have the input in eax
        ;We should multiply it with itself
        mul     eax
        ; eax=x²
        mul     [a]
        ; eax=a*x²
        mov     ebx,eax
        ; ebx=a*x²
        mov     eax,[b]
        mul     [x]
        ; eax=b*x
        add     eax,ebx
        ; eax=ax²+bx
        add     eax,[c]
        ; eax=ax²+bx+c
        stdcall int2a,buffer,lenres ;eax=>buffer, len=>lenres

        invoke  WriteConsoleA,[stdout],answer,27,count,0
        invoke  WriteConsoleA,[stdout],buffer,[lenres],count,0
        invoke  ReadConsoleA,[stdin],buffer,1,count,0
        invoke  ExitProcess,0

proc a2int uses esi ebx,lpbuffer:DWORD

locals
        sign    db      0
endl
        mov     esi,[lpbuffer]          ;[ebp+8] FASM calculates this!
        xor     eax,eax

        movzx   ebx,byte[esi]           ;fetch a digit
        cmp     ebx,"-"                 ;is the first char '-'
        jne     not_negative            ;Jump over sign manipulation
                                        ;if not negative
        inc     esi
        mov     [sign],1
       
not_negative:
  @@:
        movzx   ebx,byte[esi]           ;form the number

        lea     eax,[eax*5]
        lea     eax,[eax*2+ebx-"0"]

        add     esi,1
        cmp     byte[esi]," "           ;ANY non-printable char
        jnc     @b                      ;signals the end of number

        cmp     [sign],1                ;if flag is set, number is
        jne     pos                     ;negative so subtract from 0
        neg     eax
pos:
        ret
endp

proc int2a uses esi ebx,lpbuffer:DWORD,length:DWORD

        mov     esi,[lpbuffer]
        cmp     eax,7FFFFFFFh
        jc      positive
        neg     eax
        mov     byte[esi],'-'
        add     esi,1
    positive:
        mov     edi,10          ;divide by edi=10
        mov     ecx,10          ;maximum ecx=10 digits
      @@:
        test    eax,eax
        jz      .exit           ;exit if zero
        xor     edx,edx         ;clear edx every time!
        div     edi
        add     edx,"0"         ;change one digit to ascii
        mov     [esi+ecx],dl
        sub     ecx,1
        jnz     @b              ;run until ecx=0
      .exit:
        mov     edi,esi
        lea     esi,[esi+ecx+1]
        sub     ecx,10
        neg     ecx
        rep     movsb
        sub     edi,[lpbuffer]  ;how long is the string
        mov     eax,[length]
        mov     [eax],edi
        ret
endp


section '.data' data import readable writeable

  library kernel32,'KERNEL32.DLL'

  include 'api\kernel32.inc'

        buffer:  times 512 db 0
       
        prompt  db    'Enter a number',13,10
        answer  db    'The answer (ax^2+bx+c) is: '

;        num     dw    0
        a       dd    4
        b       dd    3
        c       dd    5
        x       dd    ?
;        result  dd    0
       ;Only uninitialized data from hereon
       ;dd ? or db ? or rw 123 etc.
        stdin   dd    ?
        stdout  dd    ?
        count   dd    ?

        lenres  dd    ?
        sresult rb    100
    
Post 05 Aug 2008, 06:41
View user's profile Send private message Visit poster's website Yahoo Messenger MSN Messenger 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.