Skip to content

feat: support GOT relocations (R_AARCH64_ADR_GOT_PAGE, R_AARCH64_LD64_GOT_LO12_NC) in module loader #278

@Ynkcc

Description

@Ynkcc

Is your feature request related to a problem? Please describe.
We are developing a Rust-based KernelPatch module (KPM) that utilizes the Rust formatting system (core::fmt).
When compiling a Rust module using the official precompiled core library (which defaults to PIC for compatibility), the compiler generates GOT relocations (such as R_AARCH64_ADR_GOT_PAGE and R_AARCH64_LD64_GOT_LO12_NC) for global symbols used by core::fmt.
Currently, the KernelPatch loader throws an unsupported RELA relocation error (returning -ENOEXEC for relocation types 310, 311, 312) because it does not support GOT-related relocations.

Describe the solution you'd like
It would be highly beneficial if the KernelPatch module loader supported GOT-related relocations on ARM64, specifically:

  • R_AARCH64_LD64_GOTOFF_LO15 (310)
  • R_AARCH64_ADR_GOT_PAGE (311)
  • R_AARCH64_LD64_GOT_LO12_NC (312)

This could be achieved by allocating a Global Offset Table (GOT) dynamically for the loaded module and populating it with resolved symbol addresses, or by utilizing dynamic instruction rewriting (e.g., rewriting the LDR instruction of R_AARCH64_LD64_GOT_LO12_NC to an ADD instruction to bypass the GOT reference entirely).

Describe alternatives you've considered

  1. Recompiling core with build-std:
    We can recompile the Rust standard library (core) without PIC by using -Z build-std and -C relocation-model=static. This prevents the compiler from generating GOT relocations in the first place. However, this requires Rust nightly and increases build times significantly.
  2. Direct mapping in loader (not fully safe):
    We can locally define the GOT relocations and map them to absolute relocations in the loader. However, without allocating a real GOT or rewriting the instruction from ldr to add, the ldr instruction will load the contents at the symbol address instead of the address itself, which can lead to unexpected behaviors or crashes depending on the symbol type.

Additional context
Below are the changes we experimented with in the loader to bypass the unsupported relocation errors:

In kernel/linux/arch/arm64/include/asm/elf.h:

#define R_AARCH64_LD64_GOTOFF_LO15 310
#define R_AARCH64_ADR_GOT_PAGE 311
#define R_AARCH64_LD64_GOT_LO12_NC 312

In kernel/patch/module/relo.c:

        /* GOT relocations - treat GOT symbols as absolute addresses */
        case R_AARCH64_ADR_GOT_PAGE:  /* 0x137 = 311 */
            ovf = reloc_insn_imm(RELOC_OP_PAGE, loc, val, 12, 21, AARCH64_INSN_IMM_ADR);
            break;
        case R_AARCH64_LD64_GOT_LO12_NC:  /* 0x138 = 312 */
            overflow_check = false;
            ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 3, 9, AARCH64_INSN_IMM_12);
            break;
        case R_AARCH64_LD64_GOTOFF_LO15:  /* 0x136 = 310 */
            overflow_check = false;
            ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 3, 12, AARCH64_INSN_IMM_12);
            break;

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions