Search code examples
macosassemblygnu-assembler

Getting stack alignment error in x86 Assembly on MacOS when making sequential C calls?


I'm currently learning x86 assembly on MacOS, and I am getting a stack misalignment error whenever making two C calls.

I have already tried using proper stack padding, making sure to have a stack size of 12 Bytes to satisfy the 16-byte stack alignment when MacOS tacks on its extra push.

I've googled making calls C calls in mac x86 assembly, but I can't seem to find examples that are more than just a call, then exit. I believe there is some stack cleanup that I'm not doing properly after the call that is leaving the stack misaligned, but I can't seem to figure it out.

    _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

This should theoretically just open and close a file descriptor, and works when I just open it, but as soon as I add the code to close it (or just the printf code, it fails).

This is the full error that I get from 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_

Does anyone see what exactly I am doing wrong here?


Solution

  • The problem is that you are assuming the stack is 16-byte aligned again after a call to a C function returns. It's not. It's the same as it was before your call instruction, 4 bytes off.

    _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
        ...