• Alan Modra's avatar
    powerpc/toc: Future proof kernel toc · a3ad84da
    Alan Modra authored
    This patch future-proofs the kernel against linker changes that might
    put the toc pointer at some location other than .got+0x8000, by
    replacing __toc_start+0x8000 with .TOC. throughout.  If the kernel's
    idea of the toc pointer doesn't agree with the linker, bad things
    happen.
    
    prom_init.c code relocating its toc is also changed so that a symbolic
    __prom_init_toc_start toc-pointer relative address is calculated
    rather than assuming that it is always at toc-pointer - 0x8000.  The
    length calculations loading values from the toc are also avoided.
    It's a little incestuous to do that with unreloc_toc picking up
    adjusted values (which is fine in practice, they both adjust by the
    same amount if all goes well).
    
    I've also changed the way .got is aligned in vmlinux.lds and
    zImage.lds, mostly so that dumping out section info by objdump or
    readelf plainly shows the alignment is 256.  This linker script
    feature was added 2005-09-27, available in FSF binutils releases from
    2.17 onwards.  Should be safe to use in the kernel, I think.
    
    Finally, put *(.got) before the prom_init.o entry which only needs
    *(.toc), so that the GOT header goes in the correct place.  I don't
    believe this makes any difference for the kernel as it would for
    dynamic objects being loaded by ld.so.  That change is just to stop
    lusers who blindly copy kernel scripts being led astray.  Of course,
    this change needs the prom_init.c changes.
    
    Some notes on .toc and .got.
    
    .toc is a compiler generated section of addresses.  .got is a linker
    generated section of addresses, generally built when the linker sees
    R_*_*GOT* relocations.  In the case of powerpc64 ld.bfd, there are
    multiple generated .got sections, one per input object file.  So you
    can somewhat reasonably write in a linker script an input section
    statement like *prom_init.o(.got .toc) to mean "the .got and .toc
    section for files matching *prom_init.o".  On other architectures that
    doesn't make sense, because the linker generally has just one .got
    section.  Even on powerpc64, note well that the GOT entries for
    prom_init.o may be merged with GOT entries from other objects.  That
    means that if prom_init.o references, say, _end via some GOT
    relocation, and some other object also references _end via a GOT
    relocation, the GOT entry for _end may be in the range
    __prom_init_toc_start to __prom_init_toc_end and if the kernel does
    something special to GOT/TOC entries in that range then the value of
    _end as seen by objects other than prom_init.o will be affected.  On
    the other hand the GOT entry for _end may not be in the range
    __prom_init_toc_start to __prom_init_toc_end.  Which way it turns out
    is deterministic but a detail of linker operation that should not be
    relied on.
    
    A feature of ld.bfd is that input .toc (and .got) sections matching
    one linker input section statement may be sorted, to put entries used
    by small-model code first, near the toc base.  This is why scripts for
    powerpc64 normally use *(.got .toc) rather than *(.got) *(.toc), since
    the first form allows more freedom to sort.
    
    Another feature of ld.bfd is that indirect addressing sequences using
    the GOT/TOC may be edited by the linker to relative addressing.  In
    many cases relative addressing would be emitted by gcc for
    -mcmodel=medium if you appropriately decorate variable declarations
    with non-default visibility.
    
    The original patch is here:
    https://lore.kernel.org/linuxppc-dev/20210310034813.GM6042@bubble.grove.modra.org/Signed-off-by: default avatarAlan Modra <amodra@au1.ibm.com>
    [aik: removed non-relocatable which is gone in 24d33ac5]
    [aik: added <=2.24 check]
    [aik: because of llvm-as, kernel_toc_addr() uses "mr" instead of global register variable]
    Signed-off-by: default avatarAlexey Kardashevskiy <aik@ozlabs.ru>
    Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
    Link: https://lore.kernel.org/r/20211221055904.555763-2-aik@ozlabs.ru
    a3ad84da
head_64.S 24.8 KB