我想将argv[0]
存储在寄存器中,然后将其打印出来,但是当我运行汇编程序时,我遇到了段错误。
跟踪:
$ 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
规格:
答案 0 :(得分:4)
分段错误来自错误的堆栈对齐(misaligned_stack_error
)
当您遇到此类问题时,请始终尝试使用GDB运行您的程序。它通常会为您提供更多信息。
但要恢复,当您从C库调用函数时,堆栈需要在 16字节边界上对齐。
这是 Mac OS X 32位ABI 的要求(请注意,64位ABI也使用SYS V调用约定)。
所以这是程序的工作版本,它将打印可执行文件名称,以及CLI参数的数量(解释就在此之后):
[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
使用以下方式编译:
nasm -f macho -o test.o test.asm
ld -o test test.o -arch i386 -lc -macosx_version_min 10.6
<强>解释强>
我们首先将argc
和argv
存储在某些寄存器中:
pop eax
pop ebx
然后我们将堆栈对齐在16字节边界上:
mov ebp, esp
and esp, 0xFFFFFFF0
在start
开始时,您只能在为局部变量创建空间保持堆栈对齐时执行此操作。
然后我们为局部变量创建必要的空间,确保堆栈保持对齐。
在这里,我们只需要3个堆栈参数的空间,但我们为4创建空间,以保持堆栈对齐。
sub esp, 16
然后,您可以移动该空间的值,为该调用准备参数:
mov dword[ esp ], hello
mov dword[ esp + 4 ], ebx
mov dword[ esp + 8 ], eax
然后只需调用C库函数,就可以了。
请注意,您还可以在this answer (x86 Assembly on a Mac)中找到一些有用的信息。