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