如何在 NASM 中打印 argv[0]? [英] How to print argv[0] in NASM?
问题描述
我想将 argv[0]
存储在寄存器中然后打印它,但是当我运行我的汇编程序时出现了段错误.
I want to store argv[0]
in a register and then print it, but I'm getting a segfault when I run my assembly program.
跟踪:
$ 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
推荐答案
分段错误来自错误的堆栈对齐 (misaligned_stack_error
).
当您遇到此类问题时,请始终尝试使用 GDB 运行您的程序.它通常会为您提供更多信息.
The segmentation fault comes from a bad stack alignment (misaligned_stack_error
).
When you have such an issue, always try running your program with GDB. It will usually provide you with more information.
但要继续,当您从 C 库调用函数时,堆栈需要在 16 字节边界上对齐.
这是 Mac OS X 32 位 ABI 的要求(请注意,64 位 ABI 也是如此,它使用 SYS V 调用约定).
But to resume, as you are calling functions from the C library, the stack needs to be aligned on 16 bytes boundaries.
This is a requirement for the Mac OS X 32 bits ABI (note this is also the case for the 64 bits ABI, which uses the SYS V calling convention).
所以这是你的程序的一个工作版本,它将打印可执行文件的名称,以及 CLI 参数的数量(解释就在后面):
So here's a working version of your program, that will print the executable name, as well as the number of CLI arguments (explanation is just after that):
[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
存储在一些寄存器中:
We first store argc
and argv
in some registers:
pop eax
pop ebx
然后我们在 16 字节的边界上对齐堆栈:
And then we align the stack on a 16 bytes boundary:
mov ebp, esp
and esp, 0xFFFFFFF0
假设您在为局部变量创建空间时保持堆栈对齐,您只能在 start
的开头执行此操作.
You can do this only once, at the beginning of start
, assuming you keep the stack aligned, when creating space for your local variables.
然后我们为局部变量创建必要的空间,确保堆栈保持对齐.
在这里,我们只需要 3 个堆栈参数的空间,但我们为 4 个创建了空间,以保持堆栈对齐.
Then we create the necessary space for local variables, ensuring the stack is kept aligned.
Here, we only need room for 3 stack arguments, but we create space for 4, to keep the stack aligned.
sub esp, 16
然后您可以移动该空间上的值,为调用准备参数:
You can then move values on that space, to prepare arguments for the call:
mov dword[ esp ], hello
mov dword[ esp + 4 ], ebx
mov dword[ esp + 8 ], eax
然后只需调用 C 库函数,就可以了.
Then simply call the C library function, and you'll be OK.
请注意,您还可以在此答案(Mac 上的 x86 程序集)中找到一些有用的信息.
Note you may also find some useful informations in this answer (x86 Assembly on a Mac).
这篇关于如何在 NASM 中打印 argv[0]?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!