我有以下代码,它假设是使用CoreFoundation函数打印Hello World。然而,每当我看起来有一个正确的对齐堆栈它不起作用,seg faulting。但是当我终于让它工作时,堆栈没有对齐?!?!?!
global _main
align 4, db 0x90
extern _CFStringCreateWithCString
extern _CFShow
section .data
hw: db 'Hello World!' ,0xA,0
section .text
_main: ; entering a new function stack must be balanced right?
push ebp ; saving ebp (esp + 4)
mov ebp, esp ; moving registers around
; align stack as calling pushed a 4 byte address on to the stack
sub esp, 12 ; balancing the stack back to mod 16 (4 + 12 = 16)
push 8 ; 4 bytes
push hw ; 4 bytes
push 0 ; 4 bytes
call _CFStringCreateWithCString ; 4 bytes
; stack still balanced
sub esp, 12 ; 12 bytes
push eax ; 4 bytes
call _CFShow ; 4 bytes
; that is 20 bytes?!?!? yet when I change the 12 to an 8 it doesn't run and instead segfaults! When I have the stack balanced!
mov eax, 99 ; return value
mov esp, ebp ; restore stack for function that called us
pop ebp
ret ; return
当它运行时它起作用,但是我找不到它为什么会这样做。我必须从esp中减去12作为一个参数函数。不应该是8,不推动已经处理递增堆栈的参数?
答案 0 :(得分:1)
我不确定为什么原始函数在没有使用堆栈上分配的空间的情况下从堆栈中进行额外的减法。堆栈在x86上增长。在这种情况下,如果你这样做:
sub esp, NUMBER
您正在堆栈中分配(提供)NUMBER
个字节以用于某种目的。
我假设库遵循C调用约定:
1) Push the parameters (in reverse order) onto the stack
2) Call the function
3) Restore the stack based upon the amount of space used by the prior pushes.
考虑到这些事情,以下是我编写函数的方法:
global _main
align 4, db 0x90
extern _CFStringCreateWithCString
extern _CFShow
section .data
hw: db 'Hello World!' ,0xA,0
section .text
_main: ; entering a new function stack must be balanced right?
push ebp ; saving ebp (esp + 4)
mov ebp, esp ; set stack frame pointer
push 8 ; String encoding - 4 bytes
push hw ; String pointer - 4 bytes
push 0 ; Allocator [0 for default] - 4 bytes
call _CFStringCreateWithCString
add esp, 12 ; restore the stack [pop the 12 bytes back off]
push eax ; Address of string to show (returned by prior call) - 4 bytes
call _CFShow
add esp, 4 ; restore the stack [pop the 4 bytes back off] NOT NEEDED with
mov eax, 99 ; return value
mov esp, ebp ; restore stack for function that called us
pop ebp
ret
请注意,由于最后一条mov
指令会恢复堆栈,因此可以省略最后一个add esp,4
,但这是为了完整性。
MacOS要求/保证函数调用的堆栈指针的16字节对齐。要做到这一点:
global _main
align 4, db 0x90
extern _CFStringCreateWithCString
extern _CFShow
section .data
hw: db 'Hello World!' ,0xA,0
section .text
_main:
; ESP was aligned before the call instruction pushed a return address
; now the nearest alignment boundaries are ESP+4 and ESP-12
push ebp ; saving ebp (esp + 4)
mov ebp, esp ; set stack frame pointer
; ESP-8 is 16-byte aligned; not enough room for 12 bytes of args
sub esp,12 ; So we have to go past that to aim for the *next* alignment boundary
push 8 ; String encoding - 4 bytes
push hw ; String pointer - 4 bytes
push 0 ; Allocator [0 for default] - 4 bytes
call _CFStringCreateWithCString
;add esp, 12+12 - 4 ; pop the padding and args, then sub 4 for 16-byte alignment on next call (after push)
;push eax ; Address of string to show (returned by prior call) - 4 bytes
mov [esp], eax ; reuse the stack reservation; ESP is still aligned
call _CFShow
add esp, 12+12 ; restore the stack [pop the args + padding back off]
mov eax, 99 ; return value
mov esp, ebp ; restore stack for function that called us
pop ebp
ret
与第一种情况一样,最后add esp,24
可以省略。