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

Reply via email to