Thanks for your swift and extensive reply. Your explanations make a lot of sense. (sorry for my sloppy description - __libc_start_main invoked by *crt is the place where constructor calls happen as you did outline). I did no extensive research how glibc executes these constructor calls. At least the call stack indicates that they are partially executed in dynamic linker context - _dl_start_user () in /lib64/ld-linux-x86-64.so calling _dl_init. I will add a reference to reply to the Go ticket. Am Mi., 21. Nov. 2018 um 15:25 Uhr schrieb Rich Felker : > On Wed, Nov 21, 2018 at 02:55:19PM +0100, Gernot Reisinger wrote: > > Hi, > > I recently stumbled upon an issue with preloading a shared object into a > Go > > application (see related Go ticket > https://github.com/golang/go/issues/28909 > > ). > > > > In short - Go comes with an internal linker which will not link crt code > to > > the application. The entry point will directly execute Go standard > library > > code. As musl libc calls shared object constructors in crt code, the > shared > > I don't think this assessment of what musl does is correct. It calls > the (initially loaded) shared object constructor via > __libc_start_main. If the program is not entered via > __libc_start_main, libc is not usable. Necessary initialization will > have been bypassed. This has little to do with whether the crt code > was linked, except that *crt1.o is normally responsible for calling > __libc_start_main. If the linking process bypasses crt1, it needs to > ensure that __libc_start_main ends up getting called in some other > way. As far as I know this is also true for glibc, so I'm not sure why > it differs. > > > objects constructors subsequently will never be invoked. Things will work > > on glibc systems / processes. it It seems to be a subtle - but in this > case > > wide reaching - behavioral difference to glibc. > > > > I wonder if calling constructor functions from crt code is an intended > musl > > libc behavior. My personal - non expert - gut feeling considers glibc > > behavior "more correct". Is there a chance that musl will change this > > behavior? > > The musl behavior here is intentional. For FDPIC targets, it's > impossible to run *any* application code, in the main application or > shared libraries, before the main application's crt1 has executed, > because there are (essentially -- the equivalent of) self-relocations > performed at that stage that the dynamic linker can't see. If any > ctors were invoked directly by the dynamic linker before passing > control the the main application's entry point, they would run without > these relocations in the main application having been performed, > possibly resulting in runaway-wrong execution. > > I believe Go is doing some bad hacks here with regard to its C FFI, > but it's likely fixable in some reasonable way. We should get more > eyes looking at it. > > Rich > >