flat assembler
Message board for the users of flat assembler.

Index > Main > without macro's?

Goto page 1, 2  Next
Author
Thread Post new topic Reply to topic
bitshifter



Joined: 04 Dec 2007
Posts: 764
Location: Massachusetts, USA
bitshifter
Hello, since i have learned assembly i have only used macro's for procedure arguments and local variables.
Can someone show me how to get this done without macro's.

edit:
This is my attempt at a solution.
I am not sure if it right and i wont run it unless people agree it is correct.
Code:
;-------------------------------------------------
; DWORD stdcall uint32_add(DWORD a, DWORD b)
;-------------------------------------------------

uint32_add:

        push    ebp
        mov     ebp,esp

        sub     esp,8 ; adjust the stack for 2 local dwords

        mov     eax,[ebp+8]
        add     eax,[ebp+12]

        mov     esp,ebp
        pop     ebp

        retn    8
    


Last edited by bitshifter on 06 Apr 2009, 02:38; edited 1 time in total
Post 03 Apr 2009, 21:22
View user's profile Send private message Reply with quote
Mac2004



Joined: 15 Dec 2003
Posts: 313
Mac2004
bitshifter: If I understood your question correctly, you can pass arguments
through registers like this:

Code:
 
mov eax,1         ;X coordinate
mov ebx, 2        ;Y coordinate
mov ecx, 100      ;length
mov edx, 2000     ;color
call MyProcedure

    


There are some other methods as well.

regards,
mac2004
Post 04 Apr 2009, 03:57
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
If you want the preprocessor out of this you can still make it somewhat readable. Here an example:
Code:
uint32_add:
virtual at ebp-.local.size
 ; Using dot at the beginning of every symbol to make them local to the function
  .dummyByte db ?    ; [EBP-5]
  .dummy dd ?        ; [EBP-4]
.local.size = $ - $$
  .oldEBP dd ?       ; [EBP]
  .retAddr dd ?      ; [EBP+4]
  .a dd ?            ; [EBP+8]
  .b dd ?            ; [EBP+12]
end virtual

; Prologue
      push ebp
      mov  ebp, esp
      sub  esp, (.local.size + 3) and -4

; User code
      mov edx, [.dummy]
      mov cl, [.dummyByte]

      mov eax, [.a]
      add eax, [.b]

; Epilogue
      leave
      retn 8
uint32_add_end: ; Closing local scope    


PS: Note that the proc macro does this in a different way so for instance locals and parameters are never available outside while with this method you could still access them (uint32_add.dummyByte for example).


Last edited by LocoDelAssembly on 04 Apr 2009, 04:28; edited 1 time in total
Post 04 Apr 2009, 04:17
View user's profile Send private message Reply with quote
bitshifter



Joined: 04 Dec 2007
Posts: 764
Location: Massachusetts, USA
bitshifter
Hmm, very interesting.
But does my version look safe to use?
Or would it just blow up in my face...
Post 04 Apr 2009, 04:27
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
Your code is correct. If you prefer to do it by hand then you could still go even further and not use an EBP-based frame on leaf functions (like your example). Not sure what is the proper advice for non-leaf functions though, for code safety and debugging I think EBP-based is preferred, but for speed I'm not sure.
Post 04 Apr 2009, 04:34
View user's profile Send private message Reply with quote
bitshifter



Joined: 04 Dec 2007
Posts: 764
Location: Massachusetts, USA
bitshifter
You mean not to use ebp for stack when stack not used inside function?
(I included a local variable in my example only for practice, it does nothing.)

Like this?
Code:
uint32_add:
    mov eax,[esp+8]
    add eax,[esp+12]
    retn 8
    
Post 04 Apr 2009, 04:42
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
You could discard EBP even in cases where you have local variables.

Code:
uint32_add:
      sub     esp, 8 ; Reserving 7 bytes but aligned to 4

      mov     edx, [esp+4]
      mov     dx, [esp+2]
      mov     dl, [esp+1]


      mov     eax, [esp+4+8]
      add     eax, [esp+8+8]

      add     esp, 8
      retn    8    
Post 04 Apr 2009, 04:48
View user's profile Send private message Reply with quote
manfred



Joined: 28 Feb 2009
Posts: 43
Location: Racibórz, Poland
manfred
But using locals without setting stack frame makes code bit unreadable...

_________________
Sorry for my English...
Post 04 Apr 2009, 14:29
View user's profile Send private message Visit poster's website Reply with quote
vid
Verbosity in development


Joined: 05 Sep 2003
Posts: 7105
Location: Slovakia
vid
In all optimized 64-bit code I saw, compilers tend to drop RBP based frame completely and only use RSP frame. It is caused by the nature of fastcall64 convention to some extent, but same can be easily done for 32 bit code just as well, without any danger or whatever. It is just a bit harder to implement, and you can't debug such code very well.
Post 05 Apr 2009, 10:10
View user's profile Send private message Visit poster's website AIM Address MSN Messenger ICQ Number Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4633
Location: Argentina
LocoDelAssembly
Well on 64-bit world perhaps the choice is easy because you don't code for a 80486 or a Pentium old series processors, but on 32-bit land what happens on situations like this?
Code:
      sub     esp, 64 ; 64 bytes of local variables (just an example)
      push    ebx

; ...

.loop:
      push    dword [esp+64+4+4*1] ; Caller's first argument; Callee's second argument
      push    dword [esp+4*2]      ; Caller's local variable; Callee's first argument
      call    stdcall_function

      lea     eax, [esp]
      push    eax
      call    another_function_that_modifies_local_var

      ; ...

      dec     ebx
      jnz     .loop

; ...

      pop     ebx
      add     esp, 64
      retn    


There are no memory address generation stalls there even on PentiumMMX, PentiumII and PentiumIII (and lets count AMD's equivalents too)?
Post 05 Apr 2009, 22:37
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 17279
Location: In your JS exploiting you and your system
revolution
bitshifter wrote:
You mean not to use ebp for stack when stack not used inside function?
(I included a local variable in my example only for practice, it does nothing.)

Like this?
Code:
uint32_add:
    mov eax,[esp+8]
    add eax,[esp+12]
    retn 8
    
Almost, the positions of the offset need to change because EBP has not been pushed onto the stack. So use this:
Code:
uint32_add:
    mov eax,[esp+4] ;+4 to skip the return address on the stack
    add eax,[esp+8] ;+4 (return address) +4 (to get to the second parameter)
    retn 8    
Post 06 Apr 2009, 01:42
View user's profile Send private message Visit poster's website Reply with quote
bitshifter



Joined: 04 Dec 2007
Posts: 764
Location: Massachusetts, USA
bitshifter
revolution:
i am confused, doesnt 'call' push 2 dwords internally?
if i push 2 dwords as arguments first, and then 'call' pushes 2 more, shouldnt the first argument be found at at esp+8?
Post 06 Apr 2009, 02:11
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 17279
Location: In your JS exploiting you and your system
revolution
call pushes EIP, a single 32bit dword, onto the stack.
Post 06 Apr 2009, 02:17
View user's profile Send private message Visit poster's website Reply with quote
bitshifter



Joined: 04 Dec 2007
Posts: 764
Location: Massachusetts, USA
bitshifter
ok i get it, my first attempt (at top of page) is implemented correctly but the comments were not correct.
I see the magic 4 byes came from pushing ebp.
Thanks for clarifying this situation.
(and for putting up with my ignorance)
Post 06 Apr 2009, 02:25
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
Seems that I've corrected your code when I was showing you the ESP-based frame with local vars but forgot to warn you about that Embarassed
Post 06 Apr 2009, 02:32
View user's profile Send private message Reply with quote
bitshifter



Joined: 04 Dec 2007
Posts: 764
Location: Massachusetts, USA
bitshifter
So the only difference between stdcall and ccall is the retn value?

stdcall: retn sizeof args (removes arguments from stack)

ccall: retn nothing (leaves arguments on stack)


Last edited by bitshifter on 06 Apr 2009, 03:06; edited 1 time in total
Post 06 Apr 2009, 03:00
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 17279
Location: In your JS exploiting you and your system
revolution
bitshifter wrote:
So the only difference between stdcall and ccall is the retn value?

stdcall: retn sizeof args

ccall: retn 0
Yes, although it is more common to write just retn. Caller restores the stack for ccall
Post 06 Apr 2009, 03:05
View user's profile Send private message Visit poster's website Reply with quote
bitshifter



Joined: 04 Dec 2007
Posts: 764
Location: Massachusetts, USA
bitshifter
So if i truly understand this...
Code:
;------------------------------------------------
; DWORD stdcall uint32_add(DWORD a, DWORD b)
;------------------------------------------------

uint32_add:

        ; esp     -> callers eip
        ; esp + 4 -> argument a
        ; esp + 8 -> argument b

        push ebp

        ; esp      -> saved ebp
        ; esp + 4  -> callers eip
        ; esp + 8  -> argument a
        ; esp + 12 -> argument b

        mov ebp,esp

        ; ebp      -> saved ebp
        ; ebp + 4  -> callers eip
        ; ebp + 8  -> argument a
        ; ebp + 12 -> argument b

        sub esp,8 ; make 2 local dwords

        ; esp      -> second local dword
        ; esp + 4  -> first local dword
        ; esp + 8  -> saved ebp
        ; esp + 12 -> callers eip
        ; esp + 16 -> argument a
        ; esp + 20 -> argument b

        ; ebp based access
        ;
        mov eax,[ebp+8]
        add eax,[ebp+12]

        ; esp based access
        ;
        ; mov eax,[esp+16]
        ; add eax,[esp+20]

        mov esp,ebp

        ; esp -> saved ebp

        pop ebp

        ; esp -> callers eip

        retn 8
    
Post 06 Apr 2009, 06:32
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 17279
Location: In your JS exploiting you and your system
revolution
Yes.
Post 06 Apr 2009, 06:39
View user's profile Send private message Visit poster's website Reply with quote
vid
Verbosity in development


Joined: 05 Sep 2003
Posts: 7105
Location: Slovakia
vid
LocoDelAssembly wrote:
Well on 64-bit world perhaps the choice is easy because you don't code for a 80486 or a Pentium old series processors, but on 32-bit land what happens on situations like this? ...

Your code doesn't exactly reflect way used in funcs with omitted stack frames. You never "push" in such procs. You just reserve enough place on stack for arguments of every function you call, and then you MOVe arguments to stack. So the value of ESP doesn't change over all the procedure.
Post 06 Apr 2009, 08:06
View user's profile Send private message Visit poster's website AIM Address MSN Messenger ICQ Number 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 cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2020, Tomasz Grysztar.

Powered by rwasa.