Before I start if we have something like
typedef void Fptr(void);
struct S1 {
Fptr* fp1;
Fptr* fp2;
};
struct S2 {
Fptr* fp1;
};
extern void fn();
extern Fptr *init_fn();
// Initialized via .init_array calling _GLOBAL__sub_I_fp.cpp
// If init_fn() could be via PLT
S1 s1 = { &fn, init_fn() };
// Initialized via relocation.
S2 s2 = { &fn };
// Initialized via relocation.
Fptr *global_ptr = &fn;
In a structure protection world, I’m assuming that the ifunc initialization would only be used for S2. We would want to avoid a call to the PLT from within an ifunc resolver as that can crash if the dynamic loader hasn’t processed the PLT relocation yet.
For the case where fn
in the example is an ifunc. IIUC, your proposed change to LLD would mean that instead of the structure field being redirected to the iPLT entry for fn
the ifunc resolver writes directly into the place. At the moment this would happen for global variables like global_ptr
in my example, as well as fields like S2::fp1
from s2
.
In the ifunc_resolver for s2’s S2::fp1 field, I thought that a possible alternative to your suggestion could be for the static linker to indirect via an iPLT entry if the target fn1
in my example is an ifunc. The address of the iPLT entry is known at static link time so if that is “locked” and returned by the initializer then it should be independent of whatever the ifunc resolver for fn
returns. However this would not compare equal to a non structure field global_ptr
as that no longer indirects via a PLT entry (assuming your LLD change). I’m guessing this could be resolved by using a different relocation directive for the structure field initializer, for example R_AARCH64_ADDRINIT_ABS64
which if targeting an ifunc does not generate an iPLT entry, leaving the regular R_AARCH64_ABS64
relocations to behave as it does today with GNU ld and LLD. The advantage of indirecting via an iPLT is that we don’t need to call the iFunc resolver via a BL, potentially running it twice (or more) if there are other uses of the ifunc.
Hope that makes some kind of sense. I find it difficult to keep all the corner cases for ifuncs in my head.
Another possibility, assuming we can successfully detect when this happens at static link time, is to just give an “unsupported error” message and abort. My guess is that this case is very rare.