1

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.

user3043627
  • 15
  • 1
  • 6
  • Are those `%1d` (one d) format specifiers supposed to be `%ld` (ell d)? – lurker Jan 25 '14 at 12:38
  • @mbratch Yes, looks that way. Kindle differentiates between ell and one very mildly, although I ought to have noted that. Thank you. When the format specifier is replaced with long, in the original program, without implementing the amendments as suggested by Gunner a segmentation fault still occurs. – user3043627 Jan 26 '14 at 13:13

2 Answers2

1

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

Gunner
  • 5,780
  • 2
  • 25
  • 40
  • After adding exit to the extern instruction, with your suggestions, the program did not fault. Thank you. – user3043627 Jan 25 '14 at 03:57
  • to zero out rax, before printf, would it be feasible to xor eax, eax instead of xor rax, rax? It seems to work in the program. – user3043627 Jan 30 '14 at 21:43
  • @user3043627: `ret` from main works unless you clobbered `main`'s return address or something higher up the stack. Not sure why this faulted, but you only need to exit manually from `_start`. You *can* call `exit` from main, but you if `ret` doesn't work that's a sign of a bug. – Peter Cordes Jun 11 '18 at 18:16
0

Gunner gave an excellent summary. The program should have placed a 0 in rax. This can be done using "xor eax, eax" which is the normal way to zero out a register in x86-64 mode. The top half of the register is zeroed out with xor with a 32 bit register and the lower half depends on the the bits of the 2 registers used (with eax, eax the result is 0).