commit 4b12e104932c799881b917fc4c15b9508cfe64d1 Author: Brandon Bergren Date: Thu Nov 7 18:27:48 2019 -0600 WIP, FINISH ME AND SEND: Disable TOC optimization in kernel modules. diff --git a/contrib/llvm/tools/lld/ELF/Arch/PPC64.cpp b/contrib/llvm/tools/lld/ELF/Arch/PPC64.cpp index 0f382dcd6b3..f95e2e35e03 100644 --- a/contrib/llvm/tools/lld/ELF/Arch/PPC64.cpp +++ b/contrib/llvm/tools/lld/ELF/Arch/PPC64.cpp @@ -171,6 +171,7 @@ bool elf::tryRelaxPPC64TocIndirection(RelType type, const Relocation &rel, config->isLE ? getRelaTocSymAndAddend(tocISB, rel.addend) : getRelaTocSymAndAddend(tocISB, rel.addend); + // XXX Figure out why linker sets in kernel modules aren't triggering this! // Only non-preemptable defined symbols can be relaxed. if (!d || d->isPreemptible) return false; diff --git a/contrib/llvm/tools/lld/ELF/Writer.cpp b/contrib/llvm/tools/lld/ELF/Writer.cpp index 10b171e8c0d..6d012655fd5 100644 --- a/contrib/llvm/tools/lld/ELF/Writer.cpp +++ b/contrib/llvm/tools/lld/ELF/Writer.cpp @@ -2006,6 +2006,8 @@ void Writer::addStartStopSymbols(OutputSection *sec) { StringRef s = sec->name; if (!isValidCIdentifier(s)) return; + // XXX Allow programs to define STV_DEFAULT visibility, FreeBSD needs + // this for the vnet and dpcpu linker sets! addOptionalRegular(saver.save("__start_" + s), sec, 0, STV_PROTECTED); addOptionalRegular(saver.save("__stop_" + s), sec, -1, STV_PROTECTED); } diff --git a/sys/conf/kmod.mk b/sys/conf/kmod.mk index 5443f1ce2a2..24e70e8fedc 100644 --- a/sys/conf/kmod.mk +++ b/sys/conf/kmod.mk @@ -175,6 +175,27 @@ CFLAGS+= -funwind-tables .if ${MACHINE_CPUARCH} == powerpc CFLAGS+= -mlongcall -fno-omit-frame-pointer +# Don't apply TOC optimizations in kernel modules. +# +# As per ELFv2 ABI spec section 3.6, the linker is allowed to perform several +# optimizations during link to reduce indirection. We explicitly rely on +# being able to relocate linker sets separately from the rest of the program +# by applying relocations to the TOC directly. +# LLD 9 and above assume that the relative displacement of "local" symbols +# will not change, and relax GOT-indirect access to be TOC-relative +# from r2 when the target address is in displacement range. +# Unfortunately, this does not hold true for the set_vnet and set_pcpu +# linker_sets, which both are manually processed by the in-kernel linker +# to be assigned offsets dynamically, and as such, references to symbols in +# these sections MUST continue to be via the TOC. +# +# XXX REWORD THIS BEFORE SUBMITTING! (Figure out where I mean to say GOT instead of TOC!) +# +# As such, disable toc optimization on modules until we have a more targeted +# method for preserving the indirection for these linker sets. +. if ${LINKER_TYPE} == "lld" && ${LINKER_VERSION} >= 90000 +LDFLAGS+= --no-toc-optimize +. endif .endif .if ${MACHINE_CPUARCH} == mips diff --git a/sys/kern/link_elf.c b/sys/kern/link_elf.c index 5975f13b9fd..97aa56c18d0 100644 --- a/sys/kern/link_elf.c +++ b/sys/kern/link_elf.c @@ -424,6 +424,7 @@ link_elf_init(void* arg) ef = (elf_file_t) linker_kernel_file; ef->preloaded = 1; #ifdef __powerpc__ +/* XXX double check */ ef->address = (caddr_t) (__startkernel - KERNBASE); #else ef->address = 0; @@ -436,6 +437,7 @@ link_elf_init(void* arg) if (dp != NULL) parse_dynamic(ef); #ifdef __powerpc__ +/* XXX double check */ linker_kernel_file->address = (caddr_t)__startkernel; linker_kernel_file->size = (intptr_t)(__endkernel - __startkernel); #else diff --git a/sys/sys/linker_set.h b/sys/sys/linker_set.h index 9f49b802887..72e703d46e6 100644 --- a/sys/sys/linker_set.h +++ b/sys/sys/linker_set.h @@ -42,8 +42,9 @@ * For ELF, this is done by constructing a separate segment for each set. */ -#if defined(__powerpc64__) +#if defined(__powerpc64__) && (!defined(_CALL_ELF) || _CALL_ELF == 1) /* + * ELFv1 pointers to functions are actaully pointers to function descriptors. * Move the symbol pointer from ".text" to ".data" segment, to make * the GCC compiler happy: */