• Mark Rutland's avatar
    arm64: Force position-independent veneers · 9abe390e
    Mark Rutland authored
    Certain portions of code always need to be position-independent
    regardless of CONFIG_RELOCATABLE, including code which is executed in an
    idmap or which is executed before relocations are applied. In some
    kernel configurations the LLD linker generates position-dependent
    veneers for such code, and when executed these result in early boot-time
    failures.
    
    Marc Zyngier encountered a boot failure resulting from this when
    building a (particularly cursed) configuration with LLVM, as he reported
    to the list:
    
      https://lore.kernel.org/linux-arm-kernel/86wmjwvatn.wl-maz@kernel.org/
    
    In Marc's kernel configuration, the .head.text and .rodata.text sections
    end up more than 128MiB apart, requiring a veneer to branch between the
    two:
    
    | [mark@lakrids:~/src/linux]% usekorg 14.1.0 aarch64-linux-objdump -t vmlinux | grep -w _text
    | ffff800080000000 g       .head.text     0000000000000000 _text
    | [mark@lakrids:~/src/linux]% usekorg 14.1.0 aarch64-linux-objdump -t vmlinux | grep -w primary_entry
    | ffff8000889df0e0 g       .rodata.text   000000000000006c primary_entry,
    
    ... consequently, LLD inserts a position-dependent veneer for the branch
    from _stext (in .head.text) to primary_entry (in .rodata.text):
    
    | ffff800080000000 <_text>:
    | ffff800080000000:       fa405a4d        ccmp    x18, #0x0, #0xd, pl     // pl = nfrst
    | ffff800080000004:       14003fff        b       ffff800080010000 <__AArch64AbsLongThunk_primary_entry>
    ...
    | ffff800080010000 <__AArch64AbsLongThunk_primary_entry>:
    | ffff800080010000:       58000050        ldr     x16, ffff800080010008 <__AArch64AbsLongThunk_primary_entry+0x8>
    | ffff800080010004:       d61f0200        br      x16
    | ffff800080010008:       889df0e0        .word   0x889df0e0
    | ffff80008001000c:       ffff8000        .word   0xffff8000
    
    ... and as this is executed early in boot before the kernel is mapped in
    TTBR1 this results in a silent boot failure.
    
    Fix this by passing '--pic-veneer' to the linker, which will cause the
    linker to use position-independent veneers, e.g.
    
    | ffff800080000000 <_text>:
    | ffff800080000000:       fa405a4d        ccmp    x18, #0x0, #0xd, pl     // pl = nfrst
    | ffff800080000004:       14003fff        b       ffff800080010000 <__AArch64ADRPThunk_primary_entry>
    ...
    | ffff800080010000 <__AArch64ADRPThunk_primary_entry>:
    | ffff800080010000:       f004e3f0        adrp    x16, ffff800089c8f000 <__idmap_text_start>
    | ffff800080010004:       91038210        add     x16, x16, #0xe0
    | ffff800080010008:       d61f0200        br      x16
    
    I've opted to pass '--pic-veneer' unconditionally, as:
    
    * In addition to solving the boot failure, these sequences are generally
      nicer as they require fewer instructions and don't need to perform
      data accesses.
    
    * While the position-independent veneer sequences have a limited +/-2GiB
      range, this is not a new restriction. Even kernels built with
      CONFIG_RELOCATABLE=n are limited to 2GiB in size as we have several
      structues using 32-bit relative offsets and PPREL32 relocations, which
      are similarly limited to +/-2GiB in range. These include extable
      entries, jump table entries, and alt_instr entries.
    
    * GNU LD defaults to using position-independent veneers, and supports
      the same '--pic-veneer' option, so this change is not expected to
      adversely affect GNU LD.
    
    I've tested with GNU LD 2.30 to 2.42 inclusive and LLVM 13.0.1 to 19.1.0
    inclusive, using the kernel.org binaries from:
    
    * https://mirrors.edge.kernel.org/pub/tools/crosstool/
    * https://mirrors.edge.kernel.org/pub/tools/llvm/Signed-off-by: default avatarMark Rutland <mark.rutland@arm.com>
    Reported-by: default avatarMarc Zyngier <maz@kernel.org>
    Cc: Ard Biesheuvel <ardb@kernel.org>
    Cc: Nathan Chancellor <nathan@kernel.org>
    Cc: Nick Desaulniers <ndesaulniers@google.com>
    Cc: Will Deacon <will@kernel.org>
    Acked-by: default avatarArd Biesheuvel <ardb@kernel.org>
    Reviewed-by: default avatarNathan Chancellor <nathan@kernel.org>
    Link: https://lore.kernel.org/r/20240927101838.3061054-1-mark.rutland@arm.comSigned-off-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
    9abe390e
Makefile 8.06 KB