diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index 3fcf70305cdc..13aa337ded24 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -53,6 +53,7 @@ private: void forEachRelSec(llvm::function_ref Fn); void sortSections(); void resolveShfLinkOrder(); + void maybeAddThunks(); void sortInputSections(); void finalizeSections(); void setReservedSymbolSections(); @@ -1461,6 +1462,46 @@ template void Writer::resolveShfLinkOrder() { } } +// For most RISC ISAs, we need to generate content that depends on the address +// of InputSections. For example some architectures such as AArch64 use small +// displacements for jump instructions that is the linker's responsibility for +// creating range extension thunks for. As the generation of the content may +// also alter InputSection addresses we must converge to a fixed point. +template void Writer::maybeAddThunks() { + if (!Target->NeedsThunks && !Config->AndroidPackDynRelocs && + !Config->RelrPackDynRelocs) + return; + + ThunkCreator TC; + AArch64Err843419Patcher A64P; + + for (;;) { + bool Changed = false; + + Script->assignAddresses(); + + if (Target->NeedsThunks) + Changed |= TC.createThunks(OutputSections); + + if (Config->FixCortexA53Errata843419) { + if (Changed) + Script->assignAddresses(); + Changed |= A64P.createFixes(); + } + + if (In.MipsGot) + In.MipsGot->updateAllocSize(); + + Changed |= In.RelaDyn->updateAllocSize(); + + if (In.RelrDyn) + Changed |= In.RelrDyn->updateAllocSize(); + + if (!Changed) + return; + } +} + static void finalizeSynthetic(SyntheticSection *Sec) { if (Sec && !Sec->empty() && Sec->getParent()) Sec->finalizeContents(); @@ -1693,33 +1734,17 @@ template void Writer::finalizeSections() { // needs to be resolved before any other address dependent operation. resolveShfLinkOrder(); - // Some architectures need to generate content that depends on the address - // of InputSections. For example some architectures use small displacements - // for jump instructions that is the linker's responsibility for creating - // range extension thunks for. As the generation of the content may also - // alter InputSection addresses we must converge to a fixed point. - if (Target->NeedsThunks || Config->AndroidPackDynRelocs || - Config->RelrPackDynRelocs) { - ThunkCreator TC; - AArch64Err843419Patcher A64P; - bool Changed; - do { - Script->assignAddresses(); - Changed = false; - if (Target->NeedsThunks) - Changed |= TC.createThunks(OutputSections); - if (Config->FixCortexA53Errata843419) { - if (Changed) - Script->assignAddresses(); - Changed |= A64P.createFixes(); - } - if (In.MipsGot) - In.MipsGot->updateAllocSize(); - Changed |= In.RelaDyn->updateAllocSize(); - if (In.RelrDyn) - Changed |= In.RelrDyn->updateAllocSize(); - } while (Changed); - } + // Jump instructions in many ISAs have small displacements, and therefore they + // cannot jump to arbitrary addresses in memory. For example, RISC-V JAL + // instruction can target only +-1 MiB from PC. It is a linker's + // responsibility to create and insert small pieces of code between sections + // to extend the ranges if jump targets are out of range. Such code pieces are + // called "thunks". + // + // We add thunks at this stage. We couldn't do this before this point because + // this is the earliest point where we know sizes of sections and their + // layouts (that are needed to determine if jump targets are in range). + maybeAddThunks(); // createThunks may have added local symbols to the static symbol table finalizeSynthetic(In.SymTab);