3

我想存储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

脚本名.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

眼镜:

  • ld 64-134.9
  • NASM 0.98.40
  • Xcode 4.5
  • Mac OS X 10.8.2
  • MacBook Pro 2009
4

1 回答 1

5

分段错误来自错误的堆栈对齐( 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 库函数,就可以了。

请注意,您还可以在此答案 (x86 Assembly on a Mac)中找到一些有用的信息。

于 2012-10-01T19:21:39.593 回答