0

It is unclear to me why final shared .so library calls functions from the static .a library as:

callq  1050 <add@plt>

I expect to see there something like:

callq  115b <add>

Let me explain by example.

Suppose we have following files.

  • static_library.c
int add(int a, int b)
{
    return a+b;
}
  • shared_library.c
extern int add(int a, int b);

int use_add_from_shared_library_1(int a, int b)
{
    return add(a, b);
}

int main() { return 0; }

Lets compile static library (for the convenience):

CC=gcc;
${CC} -c -fPIC static_library.c -o static_library.o;
ar rcs libstatic_library.a static_library.o;

Now lets compile shared library and link to it previously compiled static library:

CC=gcc;
${CC} -c -fPIC shared_library.c -o shared_library.o;
${CC} -shared shared_library.o -L./ -lstatic_library -o shared_library.so;

There will be no errors. However, "objdump" of the shared library will contain the disassembler code:

$ objdump -dS shared_library.so | grep "callq" | grep "add";
    1135:   e8 16 ff ff ff          callq  1050 <add@plt>

P.S. Single-shell example:

echo '
int add(int a, int b)
{
    return a+b;
}
' \
  > static_library.c; \
\
echo '
extern int add(int a, int b);

int use_add_from_shared_library_1(int a, int b)
{
    return add(a, b);
}

int main() { return 0; }
' \
  > shared_library.c; \
\
CC=gcc; \
\
${CC} -c -fPIC static_library.c -o static_library.o; \
ar rcs libstatic_library.a static_library.o; \
\
${CC} -c -fPIC shared_library.c -o shared_library.o; \
${CC} -shared shared_library.o -L./ -lstatic_library -o shared_library.so; \
\
objdump -dS shared_library.so | grep "callq" | grep "add";
lol lol
  • 319
  • 3
  • 18
  • Essentially, the declaration for `add` makes it also accessible to users of the shared library. As a result, it is exposed via the `plt`, I think. – TSG Jan 28 '22 at 16:07
  • It seems to me that you want `add` to be treated as a static function. Unfortunately, being part of a (static) library, it is essentially available for linking, and is not `static`. – TSG Jan 28 '22 at 16:09
  • There will be no problem (will get "callq 115b ") if I will link static library to the final binary executable (instead of creating shared library), i.e. without "-shared": (${CC} shared_library.o -L./ -lstatic_library -o executable.elf; \). However it is not clear to me why do we have such a difference in this case. – lol lol Jan 28 '22 at 16:14
  • For that, you have to understand the difference between a binary and a shared library. A binary runs directly, and a call to `add` can be implemented without the `plt`. In contrast, a shared library is dynamically linked into a different program's address space, and then gets an address there. The binary into which the shared lib gets linked needs to know the address of the shared library's functions (`add` and `use_add_from_shared_library_1`) and therefore require the `plt` – TSG Jan 28 '22 at 17:39
  • Your dissonance seems to arise from expecting only `use_add_from_shared_library_1` to be part of the shared library's interface but not `add`. Unless declared `static`, `add` will be part of the interface. Also, the only way to make `add` static is the object file at compile time, not the static library. – TSG Jan 28 '22 at 17:42
  • I believe, theoretically, it is also possible to embed "add" function inside of the "use_add_from_shared_library_1" on the linker stage into final shared library. I see no technical problems to do this. – lol lol Jan 28 '22 at 20:33

1 Answers1

1

Shared libraries and static libraries are very different beasts.

A static library is literally an archive file, similar to a .tar file, whose contents are object files. Typically these are augmented with an index of the external symbols defined in the object files. During static linking, the linker extracts some or all of those object files from the library and links those with any other specified objects, pretty much as if the extracted object files had been specified directly. There is no inherent distinction between external symbols based on which object provided them, or on whether that object was drawn from a (static) library.

Shared libraries are integrated objects, very much along the lines of programs. They can be executable programs. There are no individual object files within. In shared-library formats that feature position-independent code, all external symbols provided by the library must be position-independent.

When you link a static library into a shared one, you are asking the linker to include the contents of some or all of the object files from the static library in the resulting shared library. That's the only way it can work. The external symbols resolved from the static library will be external symbols in the shared one, too, so references to them need to be relative, including from other functions in the shared lib.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
  • 1
    I think the key line in your answer is "The external symbols resolved from the static library will be external symbols in the shared one". Apart from writing a linker script, is there a way to tell the compiler to not have `add` as a external symbol in the shared library? – TSG Jan 28 '22 at 17:43
  • @TSG, that would be a function of your toolchain. Though it's dated, [Limiting visibility of symbols when linking shared libraries](https://stackoverflow.com/q/435352/2402272) discusses some of the options available via the GNU toolchain. However, I am uncertain whether engaging any of those alternatives will get you what you asked in the original question. – John Bollinger Jan 28 '22 at 18:57
  • @TSG Your question clearly expressed the real question of this thread. – lol lol Jan 28 '22 at 20:36
  • @JohnBollinger Thanks for your reply. I think this is basically the answer to my initial question. Sure, I'd like to know the answer to TSG's question "... is there a way to tell the compiler to not have add as a external symbol in the shared library?". However, I agree that this is a matter of another question. – lol lol Jan 28 '22 at 20:41