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

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

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

如果它在64位上运行,则调用约定不是cdecl,而是sys V。 - Macmade
1
尝试在你的二进制文件上运行“lipo -info”以列出实际构架。 - Macmade
你的堆栈对齐存在问题,因此导致了分段错误。 - Macmade
@Macmade,你能否重写代码以使其对齐堆栈? - mcandre
我不知道“-f macho”是什么意思。根据我的经验,如果它是64位的话,你会收到关于“push ebx”的投诉。我认为你不应该这样做,但在push之前尝试“mov ebx,[ebx]”。 最新版本的Nasm可在http://www.nasm.us上获得,但我怀疑它会有所帮助... - Frank Kotler
显示剩余3条评论
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

解释:

我们首先将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库函数,一切都会没问题的。

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


即使使用这些宏,我仍然遇到了对齐错误。你能为我重写原始代码吗? - mcandre
@JaggedO'Neill 你说得对。还有性能方面的原因。 - Macmade
@mcandre 请查看编辑:)现在应该可以正常运行了。 - Macmade

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接