The following example grabs and displays the TickCount:
;nasm -f macho -o tick.o tick.asm
;ld -e _main -lc -framework ApplicationServices -o tick tick.o
;tick.asm
[section .data]
Ticks db 'Tick Count: %i',10,0
[SECTION .text]
global _main
extern _TickCount
extern _printf
extern _exit
_main:
push ebp
mov ebp,esp
push ebx
mov ebx,esp
and esp,0xFFFFFFF0
call _TickCount
mov esp,ebx
mov ebx,esp
and esp,0xFFFFFFF0
sub esp,8
push eax
push Ticks
call _printf
mov esp,ebx
mov ebx,esp
and esp,0xFFFFFFF0
sub esp,12
push DWORD 0
call _exit
mov esp,ebx
pop ebx
mov esp,ebp
pop ebp
ret
In the above code, you have three different examples of stack alignment prior to a function call.
The first one, TickCount, has no arguments and thus the initial 16-byte stack alignment (and esp,0xFFFFFFF0) is sufficient.
The second one, printf, takes at least one argument. In this case, %i in Tick indicates that a second argument should be on the stack. Each of these arguments is 4 bytes in size, totaling 8 bytes for this example. After the initial 16-byte stack alignment, we subtract 8 more bytes from esp prior to pushing the two 4-byte arguments, thus realigning the stack to a known safe 16-byte boundary prior to executing call.
The third one, exit, takes one argument. After the initial 16-byte stack alignment, we subtract 12 more bytes from esp prior to pushing the 4-byte exit code argument, thus realigning the stack to a known safe 16-byte boundary prior to executing call.
Here's one alternative way of looking at the above:
;nasm -f macho -o tick.o tick.asm
;ld -e _main -lc -framework ApplicationServices -o tick tick.o
;tick.asm
[section .data]
Ticks db 'Tick Count: %i',10,0
[SECTION .text]
global _main
extern _TickCount
extern _printf
extern _exit
_main:
push ebp
mov ebp,esp
push ebx
mov ebx,esp
and esp,0xFFFFFFF0
call _TickCount
mov esp,ebx
mov ebx,esp
and esp,0xFFFFFFF0
sub esp,16
mov DWORD[esp+4],eax
mov DWORD[esp],Ticks
call _printf
mov esp,ebx
mov ebx,esp
and esp,0xFFFFFFF0
sub esp,16
mov DWORD[esp],0
call _exit
mov esp,ebx
pop ebx
mov esp,ebp
pop ebp
ret
Notice we align the stack first to a known good 16-byte boundary and then simply use esp directly with mov instead of push.
Key Concept: Ensure the stack is aligned to a 16-byte boundary on Mac OS X immediately prior to executing a function call.