How does gcc `-shared` option affect the output?

10,258

Solution 1

Shared libraries and executables use the same format: they are both loadable images. However,

  1. Shared libraries are usually position-independent, executables are often not. This affects code generation: for position-independent, you have to load globals or jump to functions using relative addresses.

  2. Executables have an "entry point" which is where execution starts. This is usually not main(), because main() is a function, and functions return, but execution should never return from the entry point.

Now, this doesn't answer the question about what -shared does. You can ask GCC by using the -v flag. Here are the differences on my system between an invocation without and with -shared.

Parameters for collect2 without -shared:

-dynamic-linker
/lib64/ld-linux-x86-64.so.2
/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu/crt1.o
/usr/lib/gcc/x86_64-linux-gnu/4.7/crtbegin.o
/usr/lib/gcc/x86_64-linux-gnu/4.7/crtend.o

Parameters for collect2 with -shared:

-shared
/usr/lib/gcc/x86_64-linux-gnu/4.7/crtbeginS.o
/usr/lib/gcc/x86_64-linux-gnu/4.7/crtendS.o

Observations

It looks like code generation is not affected: you still have to use -fpic or -fPIC.

You can see that crt1.o (the "C runtime") is only included when linking the executable. Using nm, we can find out what it contains:

$ nm /usr/lib/x86_64-linux-gnu/crt1.o
0000000000000000 R _IO_stdin_used
0000000000000000 D __data_start
                 U __libc_csu_fini
                 U __libc_csu_init
                 U __libc_start_main
0000000000000000 T _start
0000000000000000 W data_start
                 U main

So you can see it seems to define something to do with stdin, as well as _start (which is the entry point), and it has an undefined reference to main.

I'm not sure what the rest of the files are, but at least you know how to find them and you can poke around, or look at the source code if you like.

Solution 2

As per https://gcc.gnu.org/onlinedocs/gcc/Link-Options.html#Link-Options -shared option does the following

  • Produce a shared object which can then be linked with other objects to form an executable.

  • Not all systems support this option.

  • For predictable results, you must also specify the same set of options used for compilation (-fpic, -fPIC, or model suboptions) when you specify this linker option.

As per Difference between -shared and -Wl,-shared of the GCC options Passing -shared to GCC may enable or disable other flags at link time.

As per my understanding if an executable has shared library, size of executable is very less. The executable will not run until the shared library is present and correctly linked. Advantage of using shared library is that if we have a very big code base, we need not build the entire code always every time. We just need to rebuild the .so file and link it to executable. This saves a lot of time.

And in case for an executabe without shared library, executable size will be very large. For every code change entire code needs to be builded, which can be very time consuming.

Share:
10,258
Dale Z
Author by

Dale Z

Updated on July 19, 2022

Comments

  • Dale Z
    Dale Z almost 2 years

    Technically, in terms of file content, what is the difference between the output of gcc -fPIC -shared src.c and gcc -fPIC src.c?

    Assume that int main(int, char**) is defined in src.c so that both compilations succeed. But executing the a.out generated by gcc -shared src.c, as expected, gave the following error:

    -bash: ./a_shared.out: cannot execute binary file

    Even if there is a main function it it.

    Also, how can I inspect the difference in the output files using tools like otool or objdump?

    Thanks a lot.