Hello,
Programs in kernel builds and loadable modules are relocatable ELF
files, and libs/libc/machine/arm64/arch_elf.c applies their relocations.
It does not support the GOT relocations R_AARCH64_ADR_GOT_PAGE and
R_AARCH64_LD64_GOT_LO12_NC, and returns -EINVAL for them.
GCC emits these relocations also without -fPIC, when code tests the
address of an undefined weak symbol, because the address can be 0:
extern void hook(void) __attribute__((weak));
int main(void)
{
/* adrp x0, :got:hook; ldr x0, [x0, :got_lo12:hook] */
if (hook)
{
hook();
}
return 0;
}
Such a program does not load. (apache/nuttx#20551 lets an unresolved
weak symbol have the value 0; that fixes weak references through data,
for example C++ vtables, but not this case.)
Possible directions:
1. The loader builds a small GOT: in a first pass it counts the symbols
that GOT relocations refer to, allocates one slot for each in the
module's data, stores the symbol values there, and relocates ADRP/LDR
to the slots. This is general.
2. Only for an undefined weak symbol: rewrite the pair so that the
register gets 0 (the LDR becomes mov xN, #0, the ADRP becomes a NOP).
Small, but it covers only this case.
3. Document the limit and do nothing for now.
I prefer 1. Is that acceptable, and should it be done for other
architectures too (I have tested arm64 only)?
Thanks,
Marco Casaroli