Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
520 views
in Technique[技术] by (71.8m points)

macos - How to print argv[0] in NASM?

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.

Trace:

$ 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

Specs:

  • ld 64-134.9
  • nasm 0.98.40
  • Xcode 4.5
  • Mac OS X 10.8.2
  • MacBook Pro 2009
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.

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).

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

Compile it using:

nasm -f macho -o test.o test.asm
ld -o test test.o -arch i386 -lc -macosx_version_min 10.6

Explanation:

We first store argc and argv in some registers:

    pop     eax
    pop     ebx

And then we align the stack on a 16 bytes boundary:

    mov     ebp,                esp
    and     esp,                0xFFFFFFF0

You can do this only once, at the beginning of start, assuming you keep the stack aligned, when creating space for your local variables.

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

Then simply call the C library function, and you'll be OK.

Note you may also find some useful informations in this answer (x86 Assembly on a Mac).


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...