Skip to content
Advertisement

Calling libc functions from another shared library in AT&T syntax?

i was trying to assemble codes below to shared library via gcc.

JavaScript

i used command below in terminal and got errors.

JavaScript

Then i googled the question and got a seemingly feasible answer in undefined-reference-to-main-for-shared-library. Then i added option -no-pie, used commands below and got another error.

JavaScript

It seems that the order of options matters. But i used codes in 32-bits like this.

JavaScript

gcc works perfectly and libzzz.so generated in current directory. Sorry if i asked a simple question. I’m totally new in this region.

Advertisement

Answer

You only get undefined reference to `main' with -no-pie.

I think -no-pie is overriding -shared, so you’re telling GCC to link a position-dependent executable, not a shared-library at all. (ELF shared libraries aka “shared objects” always have to be position-independent, there’s no such thing as a non-PIC .so. Fun fact: PIE executables are another type of ELF shared object.)


Unlike when linking a non-PIE executable, ld rewrites call printf into a call through the PLT for you. But when linking a PIE or shared library, you have to do it manually. (Newer ld might do this for you, at least in a PIE, but this was a recent change.)

In 32-bit code, call printf likely assembles and links with a runtime fixup that rewrites the call rel32 instruction at runtime to be printf‘s actual address in libc, once it’s loaded to a randomized base address. But that doesn’t work for 64-bit code because it might be more than +-2GiB away. Similar to why 32-bit absolute addresses no longer allowed in x86-64 Linux? after distros made PIE executables the default GCC config.

Your options for 64-bit code are:

  • call *printf@GOTPCREL(%rip), like gcc -fno-plt would emit when compiling C.
  • call printf@plt like compilers have historically used.
  • non-PIE executable isn’t an option; you’re making a -shared library.

For a NASM-syntax version of this with more detail about what this means, and the machine code, see Can’t call C standard library function on 64-bit Linux from assembly (yasm) code. Also has some examples at the bottom which include AT&T syntax, of how the linker “relaxes” this to a call rel32 if you do call *foobar@GOTPCREL(%rip) but then foobar is defined in the same shared library after all (with “hidden” visibility, not global, so symbol interposition isn’t necessary).

See Unexpected value of a function pointer local variable for some examples of compiler output for a PIE vs. non-PIE executable (the PIE executable code will also work in a shared library.)

-fno-plt style of code-gen is probably not worth it in 32-bit mode, where you don’t have efficient EIP-relative addressing to reach the GOT, unless you already needed a GOT pointer for something else in this funciton.

User contributions licensed under: CC BY-SA
4 People found this is helpful
Advertisement