I have a function defined in assembly that is calling a libc function (swapcontext). I invoke that function from my C code. For the purpose of creating a reproducible example, I'm using 'puts' instead:
foo.S:
.globl foo
foo:
call puts
ret
test.c:
void foo(char *str);
int main() {
foo("Hello World\n");
return 0;
}
Compile:
gcc test.c foo.S -o test
This compiles fine. Dis-assembling the result binary however shows that a valid call instruction wasn't inserted by the linker:
objdump -dR:
0000000000000671 <foo>:
671: e8 00 00 00 00 callq 676 <foo+0x5>
672: R_X86_64_PC32 puts@GLIBC_2.2.5-0x4
676: c3 retq
677: 66 0f 1f 84 00 00 00 nopw 0x0(%rax,%rax,1)
67e: 00 00
0000000000000530 <puts@plt>:
530: ff 25 9a 0a 20 00 jmpq *0x200a9a(%rip) # 200fd0 <puts@GLIBC_2.2.5>
536: 68 00 00 00 00 pushq $0x0
53b: e9 e0 ff ff ff jmpq 520 <.plt>
Execution:
./test1: Symbol `puts' causes overflow in R_X86_64_PC32 relocation
Segmentation fault
Any ideas why?
For your updated totally separate question, which replaced your question about disassembling a .o
:
semi-related: Unexpected value of a function pointer local variable mentions the fact that the linker transforms references to puts
to puts@plt
for you in a non-PIE (because that lets you get efficient code if statically linking), but not in a PIE.
libc gets mapped more than 2GiB away from the main executable so a call rel32
can't reach it.
See also Can't call C standard library function on 64-bit Linux from assembly (yasm) code, which shows AT&T and NASM syntax for calling libc functions from a PIE executable, either via the PLT call puts@plt
or gcc -fno-plt
style with call *puts@gotpcrel(%rip)
.