2

I want to call printf in assembly and link it using gcc -l option with standard library, But it says:

  Symbol `printf' causes overflow in R_X86_64_PC32 relocation
  Segmentation fault (core dumped)

this is How i compile:

   gcc mod.s -l:libc.so -o mod

when I replace libc.so with libc.a, It still shows Sementation fault

 .file  "mod.c"
.text
.section    .rodata
.LC0: 
   .string  "%d"
.text
.globl  main
.type   main, @function
main:
pushq   %rbp
movq    %rsp, %rbp
subq    $16, %rsp
movl    $3, -8(%rbp)
movl    $2, -4(%rbp)
movl    -8(%rbp), %eax
cltd
idivl   -4(%rbp)
movl    %edx, -4(%rbp)
movl    -4(%rbp), %eax
movl    %eax, %esi
leaq    .LC0(%rip), %rdi
movl    $0, %eax
call    printf
movl    $0, %eax
leave
ret
.size   main, .-main
.ident  "GCC: (Ubuntu 7.4.0-1ubuntu1~18.04) 7.4.0"
.section    .note.GNU-stack,"",@progbits

When I add @PLT after printf it goes right, But I just want to use -l in gcc

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
lizhengxian
  • 69
  • 12

1 Answers1

3

You don't need -llibc, gcc already links that by default.

The problem here is that modern GCC defaults to making a PIE executable (position-independent), which is an ELF "shared object". The linker treats it more like a library and doesn't automatically create PLT stubs for calls to undefined symbol names. (I don't think this behaviour is necessary, ld could let you do this.)

The easy solution here is gcc -no-pie -fno-pie -o mod mod.s

Then you can write call printf and it Just Works.

With that command line, you'll create a dynamically-linked ELF executable. The linker rewrites your call printf to call printf@plt for you (disassemble it and see, with objdump -drwC to print relocations.). The offset between the libc load address and your code's address is not a link-time constant. (And could be larger than 2^32 anyway).

If you use -static, the call printf resolves to the actual address of the printf definition copied into your executable from libc.a.


I'm guessing that the option of building a static or dynamic executable from the same source is why ld is willing to rewrite calls to PLT stubs for ELF executables but not ELF shared objects (like PIE executables).

See 32-bit absolute addresses no longer allowed in x86-64 Linux? for more about PIE.

The other way to call shared library functions is call *printf@GOTPCREL(%rip), like gcc does if you compile with -fno-plt. This bypasses the PLT entirely, just doing a call through the function pointer in the GOT (which you access with a RIP-relative addressing mode).

The NASM version of this is call [rel printf wrt ..got]
as an alternative to call printf wrt ..plt. Can't call C standard library function on 64-bit Linux from assembly (yasm) code

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847