如何在 NASM 中打印 argv[0]?

mca*_*dre 3 macos assembly nasm argv

我想存储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
Run Code Online (Sandbox Code Playgroud)

脚本名.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
Run Code Online (Sandbox Code Playgroud)

眼镜:

  • LD 64-134.9
  • 纳斯姆 0.98.40
  • Xcode 4.5
  • Mac OS X 10.8.2
  • MacBook Pro 2009

Mac*_*ade 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
Run Code Online (Sandbox Code Playgroud)

使用以下命令编译它:

nasm -f macho -o test.o test.asm
ld -o test test.o -arch i386 -lc -macosx_version_min 10.6
Run Code Online (Sandbox Code Playgroud)

解释:

我们首先在一些寄存器中存储argcargv

    pop     eax
    pop     ebx
Run Code Online (Sandbox Code Playgroud)

然后我们在 16 字节边界上对齐堆栈:

    mov     ebp,                esp
    and     esp,                0xFFFFFFF0
Run Code Online (Sandbox Code Playgroud)

您只能在 开始时执行此操作start,假设您为局部变量创建空间时保持堆栈对齐

然后我们为局部变量创建必要的空间,确保堆栈保持对齐。
在这里,我们只需要 3 个堆栈参数的空间,但我们为 4 个创建了空间,以保持堆栈对齐。

    sub     esp,                16
Run Code Online (Sandbox Code Playgroud)

然后,您可以移动该空间上的值,为调用准备参数:

    mov     dword[ esp ],       hello
    mov     dword[ esp + 4 ],   ebx
    mov     dword[ esp + 8 ],   eax
Run Code Online (Sandbox Code Playgroud)

然后只需调用 C 库函数,就可以了。

请注意,您还可以在此答案(Mac 上的 x86 程序集)中找到一些有用的信息。