I want to store argv[0]
in a register and then print it, but I'm getting a segfault when I run my assembly program.
Trace:
$ nasm -f macho -o scriptname.o --prefix _ scriptname.asm
$ ld -o scriptname scriptname.o -arch i386 -lc -macosx_version_min 10.6 -e _start -no_pie
$ ./scriptname
Segmentation fault: 11
scriptname.asm:
[bits 32]
section .data
program: db "Program: %s", 0
section .text
global start
extern printf
extern exit
start:
; skip argc
add esp, 4
; ebx := argv[0]
pop ebx
push ebx
push program
call printf
add esp, 8
push 0
call exit
Specs:
- ld 64-134.9
- nasm 0.98.40
- Xcode 4.5
- Mac OS X 10.8.2
- MacBook Pro 2009
The segmentation fault comes from a bad stack alignment (misaligned_stack_error
).
When you have such an issue, always try running your program with GDB. It will usually provide you with more information.
But to resume, as you are calling functions from the C library, the stack needs to be aligned on 16 bytes boundaries.
This is a requirement for the Mac OS X 32 bits ABI (note this is also the case for the 64 bits ABI, which uses the SYS V calling convention).
So here's a working version of your program, that will print the executable name, as well as the number of CLI arguments (explanation is just after that):
[bits 32]
section .data
hello db "Program name: %s (%i CLI args)", 10, 0
section .text
global start
extern _exit
extern _printf
start:
; Store 'argc' into EAX
pop eax
; Store 'argv' into EBX
pop ebx
; Align stack on a 16 bytes boundary,
; as we'll use C library functions
mov ebp, esp
and esp, 0xFFFFFFF0
; Stack space for local variables
; A little more space than needed, but that will
; ensure the stack is still aligned
sub esp, 16
; Call 'printf': printf( hello, ebx, eax );
mov dword[ esp ], hello
mov dword[ esp + 4 ], ebx
mov dword[ esp + 8 ], eax
call _printf
; Call 'exit': exit( 0 );
mov dword[ esp ], 0
call _exit
Compile it using:
nasm -f macho -o test.o test.asm
ld -o test test.o -arch i386 -lc -macosx_version_min 10.6
Explanation:
We first store argc
and argv
in some registers:
pop eax
pop ebx
And then we align the stack on a 16 bytes boundary:
mov ebp, esp
and esp, 0xFFFFFFF0
You can do this only once, at the beginning of start
, assuming you keep the stack aligned, when creating space for your local variables.
Then we create the necessary space for local variables, ensuring the stack is kept aligned.
Here, we only need room for 3 stack arguments, but we create space for 4, to keep the stack aligned.
sub esp, 16
You can then move values on that space, to prepare arguments for the call:
mov dword[ esp ], hello
mov dword[ esp + 4 ], ebx
mov dword[ esp + 8 ], eax
Then simply call the C library function, and you'll be OK.
Note you may also find some useful informations in this answer (x86 Assembly on a Mac).
来源:https://stackoverflow.com/questions/12678230/how-to-print-argv0-in-nasm