Reputation: 285
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
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 mov
s to set the arguments instead of push
es.
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
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