Christoph Conrads
2018-10-18 18:38:37 UTC
My goal is to create a shared library without dead code linking only
against other needed libraries.
The situation is as follows:
I want to make my code, let us call it "Alpha", available as a shared
library. Alpha depends on "Beta". The source code for Beta is
available, I must link statically against Beta, and I cannot modify Beta
but I can compile and link as needed. Beta depends on the shared library
Gamma. Let us call this library `libgamma.so`.
Alpha has an API exposed via functions with default visibility. All of
Beta's functions have hidden visibility. To minimize the size of the
Alpha shared library (let us call it "libalpha.so"), I pass
* `-fPIC -ffunction-sections` to the compiler when compiling Alpha and
Beta,
* `--gc-sections` to the linker when linking `libalpha.so`.
This has the desired effect of removing all dead code from
`libalpha.so`. As a side-effect, linking against `libgamma.so` is not
necessary anymore but ld will still add a `DT_NEEDED` tag for
`libgamma.so`, even in the presence of `--as-needed`.
line but this is error prone, tedious, and might not work with the next
release of Beta.
I concluded that ld must be computing `DT_NEEDED` tags before performing
garbage collection. A relocatable object file seemed to solve my problem:
* Compile an Alpha static library, pass `-fPIC -ffunction-sections` to
the compiler, ensure all API symbols have default visibility, hidden
otherwise.
* Compile a Beta static library, pass `-fPIC -ffunction-sections` to the
compiler, ensure all symbols have hidden visibility.
* Create a relocatable object from the Alpha static library and the Beta
static library with `--gc-sections --gc-keep-exported`. All dead code
is removed in this step.
* Create a shared library from the relocatable object, pass
`--as-needed` to the linker.
Unfortunately, the creation of the relocatable object does not work as I
had planned because one has to pass all of Alpha's symbols with default
visibility with the linker option `--entry`. Luckily I misspelt the
symbol names once. Lo and behold, ld simply ignored the non-existent
symbol and created the relocatable object containing all symbols with
default visibility and without dead code just as I had envisioned it.
against other needed libraries.
The situation is as follows:
I want to make my code, let us call it "Alpha", available as a shared
library. Alpha depends on "Beta". The source code for Beta is
available, I must link statically against Beta, and I cannot modify Beta
but I can compile and link as needed. Beta depends on the shared library
Gamma. Let us call this library `libgamma.so`.
Alpha has an API exposed via functions with default visibility. All of
Beta's functions have hidden visibility. To minimize the size of the
Alpha shared library (let us call it "libalpha.so"), I pass
* `-fPIC -ffunction-sections` to the compiler when compiling Alpha and
Beta,
* `--gc-sections` to the linker when linking `libalpha.so`.
This has the desired effect of removing all dead code from
`libalpha.so`. As a side-effect, linking against `libgamma.so` is not
necessary anymore but ld will still add a `DT_NEEDED` tag for
`libgamma.so`, even in the presence of `--as-needed`.
Is there a way to have ld detect and ignore unused `DT_NEEDED` tags
due to garbage collection?
This can be done manually by omitting `libgamma.so` from the commanddue to garbage collection?
line but this is error prone, tedious, and might not work with the next
release of Beta.
I concluded that ld must be computing `DT_NEEDED` tags before performing
garbage collection. A relocatable object file seemed to solve my problem:
* Compile an Alpha static library, pass `-fPIC -ffunction-sections` to
the compiler, ensure all API symbols have default visibility, hidden
otherwise.
* Compile a Beta static library, pass `-fPIC -ffunction-sections` to the
compiler, ensure all symbols have hidden visibility.
* Create a relocatable object from the Alpha static library and the Beta
static library with `--gc-sections --gc-keep-exported`. All dead code
is removed in this step.
* Create a shared library from the relocatable object, pass
`--as-needed` to the linker.
Unfortunately, the creation of the relocatable object does not work as I
had planned because one has to pass all of Alpha's symbols with default
visibility with the linker option `--entry`. Luckily I misspelt the
symbol names once. Lo and behold, ld simply ignored the non-existent
symbol and created the relocatable object containing all symbols with
default visibility and without dead code just as I had envisioned it.
Is there a way to create a relocatable object with `--gc-sections
--gc-keep-exported` and without `--entry` on the command line?
Assuming, a relocatable object with `--gc-sections
--gc-keep-exported` must also be built using `--entry`, can I rely on
the behavior of ld if the symbol name passed to `--entry` does not
exist? That is, ld will still create a relocatable object?
--gc-keep-exported` and without `--entry` on the command line?
Assuming, a relocatable object with `--gc-sections
--gc-keep-exported` must also be built using `--entry`, can I rely on
the behavior of ld if the symbol name passed to `--entry` does not
exist? That is, ld will still create a relocatable object?