Can I make shared library constructors execute before relocations?

风流意气都作罢 提交于 2019-12-04 14:54:45

Failure. If I remove all instances of the global variable bar and try to dispatch the foo() function only, then it all works.

The reason this works without global variables is that functions (by default) use lazy binding, but variables can not (for obvious reasons).

You would get the exact same failure without any global variables if your test program is linked with -Wl,-z,now (which would disable lazy binding of functions).

You could fix this by introducing an instance of every global variable referenced by your main program into the dispatch library.

Contrary to what your other answer suggests, this is not the standard way to do CPU-specific dispatch.

There are two standard ways.

The older one: use $PLATFORM as part of DT_RPATH or DT_RUNPATH. The kernel will pass in a string, such as x86_64, or i386, or i686 as part of the aux vector, and ld.so will replace $PLATFORM with that string.

This allowed distributions to ship both i386 and i686-optimized libraries, and have a program select appropriate version depending on which CPU it was running on.

Needless to say, this isn't very flexible, and (as far as I understand) doesn't allow you to distinguish between various x86_64 variants.

The new hotness is IFUNC dispatch, documented here. This is what GLIBC currently uses to provide different versions of e.g. memcpy depending on which CPU it is running on. There is also target and target_clones attribute (documented on the same page) that allows you to compile several variants of the routine, optimized for different processors (in case you don't want to code them in assembly).

I'm trying to apply this functionality to an existing, very large library, so just a recompile is the most straightforward way of implementing it.

In that case, you may have to wrap the binary in a shell script, and set LD_LIBRARY_PATH to different directories depending on the CPU. Or have the user source your script before running the program.

target_clones does look interesting; is that a recent addition to gcc

I believe the IFUNC support is about 4-5 years old, the automatic cloning in GCC is about 2 years old. So yes, quite recent.

It might not be relocations per se (-fPIC suppressess relocations), but a lazy binding through GOT (Global Offset Table), with the same effect. This is unvoidable, since Linker has to bind variables before init is called - simply because init might as well reference those symbols.

Ad for solutions... Well, once solution might be to not use (or even expose) global variables to the executable code. Instead, provide a set of functions to access them. Global variables are not welcome anyways :)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!