0
votes

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?

2
objdump -dR test may be enlightening. Also, don't you need a ret in the definition of foo? Also also, swapcontext has abnormal control flow, you need to take special care to call it safely. - zwol
Appears you OBJDUMP'ed an object file that has relocations. Try OBJDUMPing the final executable or OBJDUMP a .o file using the -r option to show relocation entries. - Michael Petch
minimal reproducible example, please. This doesn't reproduce the behavior, and doesn't work when run. - S.S. Anne
... What's # 200fd0 <swapcontext@GLIBC_2.2.5>, then? - S.S. Anne
I've updated the original example to make it a valid by using puts with the argument to it stored in %rdi. I've also indicated the failure when I run it. - cradical

2 Answers

3
votes

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).

1
votes

You appear to be disassembling an object file with relocations.

Relocations are stubs for the linker to resolve when the file is loaded.

To properly view the relocations and symbol names, use objdump -dr test or objdump -dR test.

The output will be similar to this:

0000000000000000 <foo>:
   0:   e8 00 00 00 00          callq  5 <foo+0x5>
                        1: R_X86_64_PLT32       swapcontext-0x4

You may also consider adding a ret instruction at the end of foo, just in case swapcontext errors.

As shown by your objdump -dR output, both of these refer to libc functions:

            670: R_X86_64_PC32  swapcontext@GLIBC_2.2.5-0x4
        # 200fd0 <swapcontext@GLIBC_2.2.5>