Final steps for shared library support
Johannes Pfau via D.gnu
d.gnu at puremagic.com
Sun May 22 11:41:03 PDT 2016
I've opened this pull request to finish the shared library support:
https://github.com/D-Programming-GDC/GDC/pull/214
These are the remaining problems:
1) We have to find all ModuleInfos in any shared library or in the main
executable (in the main executable even for statically linked
libdruntime). We can use a nice binutils feature for this: If we
place all symbols into a named section _not starting with a dot_
binutils will provide __start_SECTION and __stop_SECTION symbols for
us:
https://sourceware.org/binutils/docs-2.26/ld/Orphan-Sections.html#Orphan-Sections
https://github.com/jpf91/GDC/blob/shared3/libphobos/libdruntime/__dshared.c#L12
This should work for all targets using the binutils linker, not just
for linux. OTOH there are targets without binutils where we could
also output ModuleInfos into a special section and use runtime
functions to find the section (e.g. OSX):
https://github.com/dlang/druntime/blob/master/src/rt/sections_osx_x86_64.d#L131
I guess we want to keep our platform-independent C constructor based
approach for finding ModuleInfos for all targets not supported
directly by the druntime section code. So the difficult question we
have to answer now is: When does the compiler place the ModuleInfo
into a section, when does it use the generic constructor code?
I think this is the best solution: In the druntime configure script,
run a small test to check for __start/stop_minfo symbols. These
could be provided by the binutils feature or by explicit linker
scripts. Then set a variable in gcc.config accordingly.
In the compiler, search for a useModuleInfoSection manifest constant
in rt.sections. If rt.sections does not exists or
useModuleInfoSection is not defined, default to the old constructor
based code. Otherwise choose accordingly to useModuleInfoSection.
useModuleInfoSection is then set using static if & CTFE according to
information from gcc.config and OS information (= true if
gcc.config.minfoStartStop || version(OSX) ...)
2) We have to call _d_dso_registry once from every shared library and
from the main executable:
* DMD emits a weak function _d_dso_init into every object file.
Additionally it adds a weak reference to this into the .ctors
section for every object. We could probably do this manually. But
this is not really portable and I don't think we can get the
portable DECL_CONSTRUCTOR to emit weak references.
* LDC also emits the weak _d_dso_init function. It emits normal
constructors so _d_dso_init will be called multiple times. It uses
a static variable in _d_dso_init to detect repeated calls.
We could probably do this. Disadvantages: many useless
constructors, the source code for _d_dso_init is hardcoded in the
compiler and we have to hardcode the OS detection (i.e. emit
_d_dso_init for linux, freebsd, ...)
* We use the 'GCC way': The way C constructors are implemented is
using startup files. These are special object files linked once
into every shared library and executable. I've implemented &
tested this approach in the pull request:
If we link against libphobos, load
https://github.com/jpf91/GDC/blob/shared3/libphobos/libdruntime/libdruntime.spec
libdruntime.spec will then add __dshared.o to the start files, if
the file exists. This means:
* When linking with nophoboslib, __dshared.o and libdruntime.spec
are not used and do not have to exist (good for bare metal code)
* The spec can be redefined using GCCs spec file mechanism.
* If __dshared.o does not exist (maybe not needed for some OSs)
linking is done as usual.
* We can add any code we want to __dshared.o/c/d. It will be linked
once into every shared library and executable. OS detection can
be done in C or D source code instead of in the compiler.
* Main drawback: Linking needs to be done with gdc. If a user
needs to link with gcc or g++ this is still possible using
-specs=libdruntime.spec
* As we need to link phobos/druntime with -nophoboslib we also
have to use -specs=libdruntime.spec here.
3) Building the sections code triggers issue #211. I guess we have to
add a flag to ignore aggressive-loop-optimizations errors when
building libdruntime?
4) Unit tests & test suite pass for shared libraries, except for
one codegen/linker issue in the test suite. OTOH as this does not
affect static linking we can handle this even after merging the
initial shared library support code.
More information about the D.gnu
mailing list