James Parker
James Parker

Reputation: 285

BSD Stack Clean Up

I am learning Assembly language and have a question about calling conventions, and the stack clean up.

Since I am using OSX I need to use the BSD calling convention for system calls which looks like this.

SECTION .text
    push StringLen ; Push string length 
    push MyString  ; Push the string
    push 0x1       ; Push the file descriptor (stdout)
    mov eax, 4     ; Push the system call (sys_write)
    int 0x80       ; Call kernel dispatcher
    add esp, 0x10  ; Clean up stack 16 bytes for 4DWORDS

    mov eax, 1
    mov ebx, 0
    int 0x80       ; System exit

My question, is add esp, 0x10 considered good practice for cleaning up the stack? I've experimented and after the clean up it would appear the values are still on the stack, but are overwritten when another value is pushed e.g.

    add esp, 0x10  ; Clean up stack 16 bytes for 4DWORDS
    push 0x1A      ; New push overwrites the previous stack values

I'm sure this doesn't make a great deal of difference in a small program, but in a large one is it not wasted space if it never gets overwritten?

Upvotes: 1

Views: 328

Answers (2)

Igor Skochinsky
Igor Skochinsky

Reputation: 25288

Yes, this way of passing parameters and cleaning them up is fine. However, there is an issue in your code: you have only three pushes but subtract 16 bytes. The move to eax is not counted as a push since it doesn't change the esp.

It probably doesn't matter in this small program but will crash in any decently-sized one. So fix that 0x10 to 0x0C add a push eax or sub esp, 4 to make it balanced and match the requirements of the BSD calling convention.

An alternative way is to reserve stack space beforehand and use movs to set the arguments instead of pushes.

EDIT: fixed code according to the FreeBSD calling convention (extra push).

SECTION .text
    ; we only need 12 bytes (3 args) but BSD ABI needs one extra stack slot
    sub esp, 0x10  
    mov  eax, StringLen
    mov  [esp-C], eax
    mov  eax, StringLen
    mov  [esp-8], eax
    mov  dword [esp-4], 0x1 ; file descriptor (stdout)
    mov  eax, 4     ; system call number (sys_write)
    int  0x80       ; make the syscall

    mov dword [esp-4], 0 ; exit code
    mov eax, 1      ; system call number (sys_exit)
    int 0x80       ; System exit

    ; unreachable in this case but necessary for returning functions
    add esp, 0x10  ; restore the stack at the end of the function

As you can see, it avoids changing the ESP during most of the function's body but it makes the code larger and more verbose. Since you can't mov memory-to-memory you have to use a temporary register for variables.

For some reason, this way of passing arguments is default for GCC and results in quite measurable code bloat.

Upvotes: 1

NPE
NPE

Reputation: 500465

but in a large one is it not wasted space if it never gets overwritten?

No, it's not wasted space. The sixteen bytes of the stack space will get reused over and over again.

Upvotes: 1

Related Questions