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

时间:2012-10-01 17:42:00

标签: 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

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

规格:

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

1 个答案:

答案 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

<强>解释

我们首先将argcargv存储在某些寄存器中:

    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)中找到一些有用的信息。