Search code examples
assemblynasmgnu-assemblerparamdebian-based

GAS read argument of program encounter "segmentation fault"


I'm starting to learn Assembly, and my choosen compiler is GNU AS. The only terrible thing with it is that there's little documentation about AS, it's syntax and it's user guide.

I've coded a hello world program which read a text file (file path is 1st parameter of program) and display its content to stdout. But when I run the program, it's always say "segment fault". Atfer a bit of modifying source code, I found that I encountered problem in reading input argument of the program. If I put file path in source code, there's no problem, but if I read it from input argument, "segmentation fault" occurs.

This is my source code about reading input argument

# get file name from argument and put in to ebx
movl 8(%esp), %ebx

# open the file
# movl $path, %ebx
movl $5, %eax
movl $0, %ecx
movl $0666, %edx
int $0x80

I've searched a lot of ton about reading input argument in GAS but what I only found is this, a very nice article: NASM - Linux Getting command line parameters. I copied the code and change a bit to x64 (my machine is kali x64). The interesting thing was that I re-encountered "segmentation fault". What's a sadly day!!!

So if there's anyone who have worked with assemby in Linux, especially with GAS or NASM, please help me solving this problem.

A 1000+ thanks (, if it's possible) for your help

Cong.

update1: this is my full source code

.global main
.text
main:
# get file name from parameter and put in to ebx
movl 8(%esp), %ebx
# read path in source code
# movl $path, %ebx

# open the file
# movl $path, %ebx
movl $5, %eax
movl $0, %ecx
movl $0666, %edx
int $0x80

# read the file
movl %eax, %ebx
movl $3, %eax
movl $buf, %ecx
movl $bufSize, %edx
int $0x80

# write to stdout
movl %ebx, %ebp
movl $4, %eax
movl $1, %ebx
movl $buf, %ecx
int $0x80

# close the file
movl $6, %eax
movl %ebp, %ebx
int $0x80

exit:
movl $1, %eax
movl $0, %ebx
int $0x80

.data
path:
.asciz "./hello_world.c"
.bss
.equ bufSize, 1024
.lcomm buf, bufSize

update 2: my os is x86_64, and that's the root of a lot of problems I encountered when programming assembly in x86_64. with the help of @user35443 and @Jester, I can finally have some workaround: compile to x86 elf file, instead of x64 elf. the source code is the same as above, with a bit of changing main to _start. And because I compile x86 on x86_64, I need something: apt-get install gcc-multilib, after that, the compiling is straight forward: as --32 readfile.s -o readfile.o && ld -m elf_i386 readfile.o -o readfile && ./readfile some_text_file (ps: I don't know why gcc -m32 readfile.s encouter error )

.global _start
.text
_start:
# get file name from parameter and put in to ebx
movl 8(%esp), %ebx
# movl $path, %ebx

# open the file
# movl $path, %ebx
movl $5, %eax
movl $0, %ecx
movl $0666, %edx 
int $0x80

# read the file
movl %eax, %ebx
movl $3, %eax
movl $buf, %ecx
movl $bufSize, %edx
int $0x80

# write to stdout
movl %ebx, %ebp
movl $4, %eax
movl $1, %ebx
movl $buf, %ecx
# size of write is %edx
int $0x80

# close the file
movl $6, %eax
movl %ebp, %ebx
int $0x80

exit:
movl $1, %eax
movl $0, %ebx
int $0x80

.data
path:
.asciz "./hello_world.c"
.bss
.equ bufSize, 1024
.lcomm buf, bufSize

because I focus on x86_64, I will let the question open for a few days, and this is my source code for x84_64 that I can not find root of the problem (maybe I mis-used x86_64 call convention).

.global main
.text
main:
# get file name from parameter and put in to rbx
movq 16(%rsp), %rbx
#movq $path, %rbx

# open the file
# movq $path, %rbx
movq $5, %rax
movq $0, %rcx
movq $0666, %rdx 
int $0x80

# read the file
movq %rax, %rbx
movq $3, %rax
movq $buf, %rcx
movq $bufSize, %rdx
int $0x80

# write to stdout
movq %rbx, %rbp
movq $4, %rax
movq $1, %rbx
movq $buf, %rcx
# size of write is %rdx
int $0x80

# close the file
movq $6, %rax
movq %rbp, %rbx
int $0x80

exit:
movq $1, %rax
movq $0, %rbx
int $0x80

.data
path:
.asciz "./hello_world.c"
.bss
.equ bufSize, 1024
.lcomm buf, bufSize

Solution

  • Here is a 64 bit port of the code:

    .global main
    .text
    main:
    push %rbx           # save rbx
    # get file name from parameter and put in to rdi
    # argv in rsi
    # open the file
    movq 8(%rsi), %rdi  # path
    movl $0, %esi       # flags
    movl $0666, %edx    # mode
    movl $2, %eax       # SYS_OPEN
    syscall
    movl %eax, %ebx     # save fd
    
    # read the file
    movl %eax, %edi     # fd
    leaq buf, %rsi      # buf
    movl $bufSize, %edx # count
    movl $0, %eax       # SYS_READ
    syscall
    
    # write to stdout
    movl $1, %edi       # stdout
    leaq buf, %rsi      # buf
    movl %eax, %edx     # count
    movl $1, %eax       # SYS_WRITE
    
    syscall
    
    # close the file
    movl %ebx, %esi     # fd
    movl $3, %eax       # SYS_CLOSE
    syscall
    
    exit:
    xor %eax, %eax      # return 0
    pop %rbx            # restore rbx
    ret
    
    .data
    path:
    .asciz "./hello_world.c"
    .bss
    .equ bufSize, 1024
    .lcomm buf, bufSize
    

    Note, it is not a good idea to use raw system calls from a program that's using libc. It's particularly bad to use the exit system call because that leaves no chance for the c library to shut down. I have removed the exit system call, but left the others intact. The system call numbers and calling convention is different for 64 bit. You can get a quick overview at wikipedia or read the ABI docs for the full picture.