进行连续C调用时,在MacOS上的x86 Assembly中获得堆栈对齐错误吗?

时间:2019-07-16 15:44:07

标签: macos assembly gas

我目前正在MacOS上学习x86汇编,并且每当进行两次C调用时都会遇到堆栈未对齐错误。

我已经尝试使用适当的堆栈填充,确保MacOS额外推动时确保堆栈大小为12字节,以满足16字节的堆栈对齐。

我已经在Mac x86汇编中谷歌进行了C调用,但是我似乎找不到除调用之外的示例,然后退出。我相信在进行一些导致堆栈未对齐的调用后,我无法正常进行堆栈清理,但是我似乎无法弄清楚。

    _main:

        # First open the file?
        # int open(const char *path, int flags, ...)
        subl $0x04, %esp            # Pad the stack
        pushl $0x0                  # This is the flag for O_RDONLY
        pushl $path                 # Then add the path

        call _open                  # Make the call to open
        movl %eax, fd               # Put the file descriptor into the fd variable

        # Let's just close the file
        # int close(int fd);
        subl $0x08, %esp            # Stack padding
        pushl $fd                   # Push the file descriptor onto the stack
        call _close                 # Close that bitch

        # Display a nice message and leave
        subl $0x08, %esp            # Buffer da stackaroo
        pushl $end_message          # Put our message on da stack
        call _printf                # Print the message

        # Goodbye :)
        call _exit

从理论上讲,这应该只是打开和关闭文件描述符,并且在我刚打开它时就可以使用,但是一旦我添加了关闭它的代码(或者只是printf代码,它就会失败)。

这是我从lldb得到的完整错误:

* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
    frame #0: 0xa7aa6bd0 libdyld.dylib`misaligned_stack_error_

有人在这里看到我到底在做什么错吗?

1 个答案:

答案 0 :(得分:1)

问题是您假设在对C函数的调用返回后,堆栈再次按16字节对齐。不是。与您的call指令之前相同,但减少了4个字节。

_main:
# on entry, %esp is 0x...0 (last digit is 0, 16-byte aligned)
    subl $0x04, %esp            # Pad the stack
# %esp is 0x...c
    pushl $0x0                  # This is the flag for O_RDONLY
# %esp is 0x...8
    pushl $path                 # Then add the path
# %esp is 0x...4
# call will push 4-byte return address, making %esp on entry to open() 0x...0
    call _open                  # Make the call to open
# open()'s ret will pop the 4-byte return address, putting %esp back to 0x...4
    movl %eax, fd               # Put the file descriptor into the fd variable
    subl $0x08, %esp            # Stack padding
# %esp is 0x...c
    pushl $fd                   # Push the file descriptor onto the stack
# %esp is 0x...8
# call will push 4-byte return address, making %esp on entry to close() 0x...4
# that's mis-aligned
    call _close                 # Close that bitch
    ...