Search code examples
cassemblyexternlibc

Call libc function from assembly


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?


Solution

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