代码段错误,除非esp递增

时间:2013-09-06 19:01:38

标签: macos assembly x86 cfstring

我有以下代码,它假设是使用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,不推动已经处理递增堆栈的参数?

1 个答案:

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