Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -36,7 +36,7 @@ class OutputSection; class OutputSectionFactory; class InputSectionBase; - +template class ThunkSection; // This represents an expression in the linker script. // ScriptParser::readExpr reads an expression and returns an Expr. // Later, we evaluate the expression by calling the function @@ -253,6 +253,7 @@ void adjustSectionsBeforeSorting(); void adjustSectionsAfterSorting(); + void addInlineThunks(StringRef OSName, ArrayRef *> Thunks); std::vector createPhdrs(); bool ignoreInterpSection(); @@ -295,6 +296,8 @@ MemoryRegion *findMemoryRegion(OutputSectionCommand *Cmd, OutputSection *Sec); + void resetAddressState(); + uintX_t Dot; std::function LMAOffset; OutputSection *CurOutSec = nullptr; Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -23,6 +23,7 @@ #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" +#include "Thunks.h" #include "Writer.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" @@ -549,6 +550,21 @@ return nullptr; } +// Reset the members associated with address assigment to their initial values +// this permits addressAssignment to be run again. +template void LinkerScript::resetAddressState() { + LMAOffset = 0; + CurOutSec = nullptr; + CurMemRegion = nullptr; + ThreadBssOffset = 0; + for (auto &MRI : Opt.MemoryRegions) { + MemoryRegion &MR = MRI.second; + MR.Offset = MR.Origin; + } + AlreadyOutputOS.clear(); + AlreadyOutputIS.clear(); +} + // This function assigns offsets to input sections and an output section // for a single sections command (e.g. ".text { *(.text); }"). template @@ -668,6 +684,52 @@ removeEmptyCommands(); } +// Thunks are generated after sections are assigned to InputSectionDescriptions +// as Mips LA25 Thunks precede their target section we must insert them in the +// right place in the InputSectionDescription to make sure that the script +// assigns the Thunk the correct address. +template +void LinkerScript::addInlineThunks( + StringRef OSName, ArrayRef *> Thunks) { + auto OutCmdPos = std::find_if( + Opt.Commands.begin(), Opt.Commands.end(), + [=](const std::unique_ptr &Cmd) { + if (auto *OSCmd = dyn_cast(Cmd.get())) + return (OSCmd->Name == OSName); + return false; + }); + if (OutCmdPos == Opt.Commands.end()) + // Script does not describe the Output Section + return; + auto *OutCmd = cast(OutCmdPos->get()); + // Step through the InputSectionDescriptions of this OutputSection and merge + // the Thunk into the correct position. + auto ThunkIter = Thunks.begin(); + for (std::unique_ptr &Base : OutCmd->Commands) { + auto *Cmd = dyn_cast(Base.get()); + if (!Cmd || Cmd->Sections.empty()) + continue; + + if (ThunkIter == Thunks.end()) + // No more additions to InputSectionDescriptions needed. + break; + + std::vector Tmp; + for (auto *ISD : Cmd->Sections) { + auto *IS = cast(ISD); + if (ThunkIter != Thunks.end() && + (*ThunkIter)->getTargetInputSection() == IS) { + // At most one Thunk precedes a target section + Tmp.push_back(*ThunkIter); + (*ThunkIter)->Assigned = true; + ++ThunkIter; + } + Tmp.push_back(IS); + } + Cmd->Sections = std::move(Tmp); + } +} + // When placing orphan sections, we want to place them after symbol assignments // so that an orphan after // begin_foo = .; @@ -770,9 +832,9 @@ template void LinkerScript::assignAddresses(std::vector &Phdrs) { + Script::X->resetAddressState(); // Assign addresses as instructed by linker script SECTIONS sub-commands. Dot = 0; - // A symbol can be assigned before any section is mentioned in the linker // script. In an DSO, the symbol values are addresses, so the only important // section values are: Index: ELF/Relocations.cpp =================================================================== --- ELF/Relocations.cpp +++ ELF/Relocations.cpp @@ -43,6 +43,7 @@ #include "Relocations.h" #include "Config.h" +#include "LinkerScript.h" #include "Memory.h" #include "OutputSections.h" #include "Strings.h" @@ -868,6 +869,11 @@ }; std::stable_sort(Thunks.begin(), Thunks.end(), ThunkCmp); + // We need to insert the sections into the linker script input section + // commands for the correct output order + if (Config->EMachine == EM_MIPS && ScriptConfig->HasSections) + Script::X->addInlineThunks(OS->Name, Thunks); + // Merge sorted vectors of Thunks and InputSections by OutSecOff std::vector Tmp; Tmp.reserve(OS->Sections.size() + Thunks.size()); Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -1147,9 +1147,13 @@ // Some architectures use small displacements for jump instructions. // It is linker's responsibility to create thunks containing long // jump instructions if jump targets are too far. Create thunks. - if (Target->NeedsThunks) + if (Target->NeedsThunks) { + if (ScriptConfig->HasSections) + // Assign addresses to sections so that Mips LA25 Thunks can be placed + // before the + Script::X->assignAddresses(Phdrs); createThunks(OutputSections); - + } // Fill other section headers. The dynamic table is finalized // at the end because some tags like RELSZ depend on result // of finalizing other sections. Index: test/ELF/mips-npic-call-pic-script.s =================================================================== --- /dev/null +++ test/ELF/mips-npic-call-pic-script.s @@ -0,0 +1,141 @@ +# REQUIRES: mips +# Check LA25 stubs creation. This stub code is necessary when +# non-PIC code calls PIC function. +# RUN: echo "SECTIONS { .out 0x20000 : { *(.text.*) . = . + 0x100 ; *(.text) } }" > %t1.script +# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ +# RUN: %p/Inputs/mips-fpic.s -o %t-fpic.o +# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ +# RUN: %p/Inputs/mips-fnpic.s -o %t-fnpic.o +# RUN: ld.lld -r %t-fpic.o %t-fnpic.o -o %t-sto-pic.o +# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ +# RUN: %p/Inputs/mips-pic.s -o %t-pic.o +# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t-npic.o +# RUN: ld.lld --script %t1.script %t-npic.o %t-pic.o %t-sto-pic.o -o %t.exe --Map=m.txt +# RUN: llvm-objdump -d %t.exe | FileCheck %s + +# CHECK: Disassembly of section .out: +# CHECK-NEXT: __LA25Thunk_foo1a: +# CHECK-NEXT: 20000: 3c 19 00 02 lui $25, 2 +# CHECK-NEXT: 20004: 08 00 80 08 j 131104 +# CHECK-NEXT: 20008: 27 39 00 20 addiu $25, $25, 32 +# CHECK-NEXT: 2000c: 00 00 00 00 nop +# CHECK: __LA25Thunk_foo1b: +# CHECK-NEXT: 20010: 3c 19 00 02 lui $25, 2 +# CHECK-NEXT: 20014: 08 00 80 09 j 131108 +# CHECK-NEXT: 20018: 27 39 00 24 addiu $25, $25, 36 +# CHECK-NEXT: 2001c: 00 00 00 00 nop +# CHECK: foo1a: +# CHECK-NEXT: 20020: 00 00 00 00 nop +# CHECK: foo1b: +# CHECK-NEXT: 20024: 00 00 00 00 nop +# CHECK: __LA25Thunk_foo2: +# CHECK-NEXT: 20028: 3c 19 00 02 lui $25, 2 +# CHECK-NEXT: 2002c: 08 00 80 10 j 131136 +# CHECK-NEXT: 20030: 27 39 00 40 addiu $25, $25, 64 +# CHECK-NEXT: 20034: 00 00 00 00 nop +# CHECK-NEXT: 20038: 00 00 00 00 nop +# CHECK-NEXT: 2003c: 00 00 00 00 nop +# CHECK: foo2: +# CHECK-NEXT: 20040: 00 00 00 00 nop +# CHECK-NEXT: 20044: 00 00 00 00 nop +# CHECK-NEXT: 20048: 00 00 00 00 nop +# CHECK-NEXT: 2004c: 00 00 00 00 nop +# CHECK-NEXT: 20050: 00 00 00 00 nop +# CHECK-NEXT: 20054: 00 00 00 00 nop +# CHECK-NEXT: 20058: 00 00 00 00 nop +# CHECK-NEXT: 2005c: 00 00 00 00 nop +# CHECK-NEXT: 20060: 00 00 00 00 nop +# CHECK-NEXT: 20064: 00 00 00 00 nop +# CHECK-NEXT: 20068: 00 00 00 00 nop +# CHECK-NEXT: 2006c: 00 00 00 00 nop +# CHECK-NEXT: 20070: 00 00 00 00 nop +# CHECK-NEXT: 20074: 00 00 00 00 nop +# CHECK-NEXT: 20078: 00 00 00 00 nop +# CHECK-NEXT: 2007c: 00 00 00 00 nop +# CHECK-NEXT: 20080: 00 00 00 00 nop +# CHECK-NEXT: 20084: 00 00 00 00 nop +# CHECK-NEXT: 20088: 00 00 00 00 nop +# CHECK-NEXT: 2008c: 00 00 00 00 nop +# CHECK-NEXT: 20090: 00 00 00 00 nop +# CHECK-NEXT: 20094: 00 00 00 00 nop +# CHECK-NEXT: 20098: 00 00 00 00 nop +# CHECK-NEXT: 2009c: 00 00 00 00 nop +# CHECK-NEXT: 200a0: 00 00 00 00 nop +# CHECK-NEXT: 200a4: 00 00 00 00 nop +# CHECK-NEXT: 200a8: 00 00 00 00 nop +# CHECK-NEXT: 200ac: 00 00 00 00 nop +# CHECK-NEXT: 200b0: 00 00 00 00 nop +# CHECK-NEXT: 200b4: 00 00 00 00 nop +# CHECK-NEXT: 200b8: 00 00 00 00 nop +# CHECK-NEXT: 200bc: 00 00 00 00 nop +# CHECK-NEXT: 200c0: 00 00 00 00 nop +# CHECK-NEXT: 200c4: 00 00 00 00 nop +# CHECK-NEXT: 200c8: 00 00 00 00 nop +# CHECK-NEXT: 200cc: 00 00 00 00 nop +# CHECK-NEXT: 200d0: 00 00 00 00 nop +# CHECK-NEXT: 200d4: 00 00 00 00 nop +# CHECK-NEXT: 200d8: 00 00 00 00 nop +# CHECK-NEXT: 200dc: 00 00 00 00 nop +# CHECK-NEXT: 200e0: 00 00 00 00 nop +# CHECK-NEXT: 200e4: 00 00 00 00 nop +# CHECK-NEXT: 200e8: 00 00 00 00 nop +# CHECK-NEXT: 200ec: 00 00 00 00 nop +# CHECK-NEXT: 200f0: 00 00 00 00 nop +# CHECK-NEXT: 200f4: 00 00 00 00 nop +# CHECK-NEXT: 200f8: 00 00 00 00 nop +# CHECK-NEXT: 200fc: 00 00 00 00 nop +# CHECK-NEXT: 20100: 00 00 00 00 nop +# CHECK-NEXT: 20104: 00 00 00 00 nop +# CHECK-NEXT: 20108: 00 00 00 00 nop +# CHECK-NEXT: 2010c: 00 00 00 00 nop +# CHECK-NEXT: 20110: 00 00 00 00 nop +# CHECK-NEXT: 20114: 00 00 00 00 nop +# CHECK-NEXT: 20118: 00 00 00 00 nop +# CHECK-NEXT: 2011c: 00 00 00 00 nop +# CHECK-NEXT: 20120: 00 00 00 00 nop +# CHECK-NEXT: 20124: 00 00 00 00 nop +# CHECK-NEXT: 20128: 00 00 00 00 nop +# CHECK-NEXT: 2012c: 00 00 00 00 nop +# CHECK-NEXT: 20130: 00 00 00 00 nop +# CHECK-NEXT: 20134: 00 00 00 00 nop +# CHECK-NEXT: 20138: 00 00 00 00 nop +# CHECK-NEXT: 2013c: 00 00 00 00 nop +# CHECK-NEXT: 20140: 00 00 00 00 nop +# CHECK-NEXT: 20144: 00 00 00 00 nop +# CHECK-NEXT: 20148: 00 00 00 00 nop +# CHECK-NEXT: 2014c: 00 00 00 00 nop +# CHECK: __start: +# CHECK-NEXT: 20150: 0c 00 80 00 jal 131072 <__LA25Thunk_foo1a> +# CHECK-NEXT: 20154: 00 00 00 00 nop +# CHECK-NEXT: 20158: 0c 00 80 0a jal 131112 <__LA25Thunk_foo2> +# CHECK-NEXT: 2015c: 00 00 00 00 nop +# CHECK-NEXT: 20160: 0c 00 80 04 jal 131088 <__LA25Thunk_foo1b> +# CHECK-NEXT: 20164: 00 00 00 00 nop +# CHECK-NEXT: 20168: 0c 00 80 0a jal 131112 <__LA25Thunk_foo2> +# CHECK-NEXT: 2016c: 00 00 00 00 nop +# CHECK-NEXT: 20170: 0c 00 80 60 jal 131456 <__LA25Thunk_fpic> +# CHECK-NEXT: 20174: 00 00 00 00 nop +# CHECK-NEXT: 20178: 0c 00 80 68 jal 131488 +# CHECK-NEXT: 2017c: 00 00 00 00 nop +# CHECK: __LA25Thunk_fpic: +# CHECK-NEXT: 20180: 3c 19 00 02 lui $25, 2 +# CHECK-NEXT: 20184: 08 00 80 64 j 131472 +# CHECK-NEXT: 20188: 27 39 01 90 addiu $25, $25, 400 +# CHECK-NEXT: 2018c: 00 00 00 00 nop +# CHECK: fpic: +# CHECK-NEXT: 20190: 00 00 00 00 nop +# CHECK-NEXT: 20194: 00 00 00 00 nop +# CHECK-NEXT: 20198: 00 00 00 00 nop +# CHECK-NEXT: 2019c: 00 00 00 00 nop +# CHECK: fnpic: +# CHECK-NEXT: 201a0: 00 00 00 00 nop + + .text + .globl __start +__start: + jal foo1a + jal foo2 + jal foo1b + jal foo2 + jal fpic + jal fnpic