Search code examples
linuxassembly64-bityasm

Segmentation fault ASM on linux at printf


The following is a program from a book (Introduction to 64 Bit Intel Assembly Language Programming for Linux, by Seyfarth, 2012), chap 9. The fault (in gdb) is:

Program received signal SIGSEGV, Segmentation fault. 0x00007ffff7aa10a5 in __printf_size (fp=0x400400, info=0x0, args=) at printf_size.c:199 199 printf_size.c: No such file or directory.

Until this chapter, I successfully used the following to "produce an object file", as recommended,

yasm -f elf64 -g dwarf2 -l exit.lst exit.asm

and then,

ld -o prgm prgm.o

This is the program as copied from the book(l 10 push rbp; I had firstly rem'd the ; but had the same result):

    segment .text
    global  main
    extern  printf

;   void print_max  ( long a, long b )
;   {
a   equ 0
b   equ 8
print_max:
    push    rbp;     ;normal stack frame
    mov     rbp, rsp
;   leave space for a, b and max
    sub     rsp, 32
;   int max;
    max equ 16
    mov [rsp+a], rdi ; save a
    mov [rsp+b], rsi ; save b
;   max = a;
    mov [rsp+max], rdi
;   if ( b > max ) max = b;
    cmp rsi, rdi
    jng skip
    mov [rsp+max], rsi
skip:
    ;   printf ( "max(%1d,%1d ) = %1d\n",
    ;                a, b, max );
    segment .data
fmt db  'max(%1d,%1d) = %1d',0xa,0
    segment .text
    lea rdi, [fmt]
    mov rsi, [rsp+a]
    mov rdx, [rsp+b]
    mov rcx, [rsp+max]
    call printf
 ; }
    leave
    ret

main:
    push    rbp
    mov     rbp, rsp
;   print_max ( 100, 200 );
    mov     rdi, 100    ;first parameter
    mov     rsi, 200    ;second parameter
    call    print_max
    xor     eax, eax    ;to return 0
    leave
    ret

After a similar segmentation fault with a previous program in this chap ("Hello World" example), I used

gcc -o prgm prgm.o

which had worked until this program.


Solution

  • using gcc to link is the easiest way to go if you are going to use functions from the C Library, since gcc takes care of a few things for you "behind the scenes".

    To use just ld, you need to link against ld-linux-x86-64.so.2 and pass it -lc to link to the C Library.

    Next, you are using printf wrong. If you are not using floating point registers (which you are not) you need to "zero out" rax.

    Also, since you are linking against the C Library, you cannot just ret from the main but call exit.

    lea     rdi, [fmt]
    mov     rsi, [rsp+a]
    mov     rdx, [rsp+b]
    mov     rcx, [rsp+max]
    xor     rax, rax                      ; # of floating point registers used.
    call    printf
    

    and:

    ;   print_max ( 100, 200 );
    mov     rdi, 100    ;first parameter
    mov     rsi, 200    ;second parameter
    call    print_max
    xor     eax, eax    ;to return 0
    leave
    
    xor     rdi, rdi
    call    exit
    

    ld -o $(APP) $(APP).o -lc -I/lib64/ld-linux-x86-64.so.2

    and the output:

    max(100,200) = 200