问题
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
回答1:
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
来源:https://stackoverflow.com/questions/56404855/how-can-i-call-printf-normally-in-assembly-without-plt-but-just-call-printf-wit