1

我有以下代码,它所要做的就是使用 CoreFoundation 函数打印 Hello World。但是,每当我似乎有一个正确对齐的堆栈时,它就不起作用,出现段错误。但是当我终于让它工作时,堆栈没有对齐?!?!?!

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,不是 push 已经处理增加参数的堆栈吗?

4

1 回答 1

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可以省略。

于 2013-09-07T01:44:59.307 回答