On Mon, Jul 11, 2011 at 01:00:08PM +0100, David Gilbert wrote:
On 11 July 2011 12:30, Dave Martin dave.martin@linaro.org wrote:
On Mon, Jul 11, 2011 at 10:42:27AM +0100, Richard Sandiford wrote:
Dave Martin dave.martin@linaro.org writes:
IFUNC doesn't solve the problem because either it gets resolved lazily (violating the above principle (*)), or we have to force _all_ symbols to resolve at startup, with may have a significant impact on startup time for large programs.
IFUNCs are never resolved lazily; that's one way in which they differ from PLTs.
(BTW, in response to a comment upthread, ARM does support IFUNCs now.)
Do you know when support was merged in eglibc?
For example, Linaro binutils 2.21.0.20110327-2ubuntu3 appears to support IFUNC, but the natty version of eglibc (2.13-0ubuntu13) does not handle it correctly.
That's why I didn't try and use it; I thought it was best to wait for it to percolate through.
Richard's patch went into glibc-ports on April 26th and looks like it got imported into eglibc-ports on 5th May (svn rev 13608); there was also a fix from Joseph Myers in that area on 21st June.
Just for context, I had a quick play to get a feel for the feasibility of implementing this directly, without relying either on a VDSO or on IFUNC.
It's possible to produce something which works reasonably well: see the attachment. The result is almost the same as what IFUNC would achieve (although &__kernel_cmpxchg64 leaves something to be desired; macros could potentially fix that).
[see attached]
The various helpers are checked independently at startup if they are used, by registering the resolver functions as constructors as others have suggested. (Note that gcc/libc already fails to do this check for the older kernel helper functions; it's just that you're unlikely to observe a problem on any reasonably new kernel.)
The problem of constructor ordering is solved by pointing each indirect function pointer at the appropriate resolver function initially. Threading is not taken into account because no additional threads can exist during execution of constructors (though if more libraries are later dlopen()'d they may invoke additional constructors in the presence of threads, so this might need fixing).
The main question is the correct way to blow the program up if a needed helper function is not available. Calling exit() is possibly too gentle, whereas calling abort() may be too aggressive. libc may have some correct internal mechanism for doing this, but my knowledge falls short of that.
What to do in the case of recursive lookup failures isn't obvious: currently I just call abort(). By this point the process should be running atexit handlers or destructors, so calling exit() isn't going to help in this situation anyway.
The other question is whether and how the program can be enabled to catch the error and report something intelligible to the user. If there is a hook for catching dynamic link failures, we should maybe use the same. If this problem is not solved for dynamic linking in general, it doesn't make sense to require the kuser functions to solve it either (except that if the problem is eventually solved, we want the fix to work smoothly for both).
Of course, all of these are generic dynamic linking challenges which ld.so likely has some policy or solution for already.
Overall, this isn't a perfect solution, but it doesn't feel catastrophically bad either.
Any thoughts?
Cheers ---Dave