Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -228,6 +228,8 @@ MemoryRegion *findMemoryRegion(OutputSectionCommand *Cmd, OutputSection *Sec); + void resetAddressState(); + void switchTo(OutputSection *Sec); void flush(); void output(InputSection *Sec); @@ -262,6 +264,8 @@ void adjustSectionsBeforeSorting(); void adjustSectionsAfterSorting(); + void syncWithOS(OutputSection* OS); + std::vector createPhdrs(); bool ignoreInterpSection(); Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -567,6 +567,21 @@ return nullptr; } +// Reset the members associated with address assigment to their initial values +// this permits addressAssignment to be run again. +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); }"). void LinkerScript::assignOffsets(OutputSectionCommand *Cmd) { @@ -687,6 +702,80 @@ removeEmptyCommands(); } +// Thunks are added to an OutputSection after InputSections are assigned to +// InputSectionDescriptions. We need to resynchronize the OS->Sections and the +// InputSectionDescriptions so that the Thunks are assigned the correct address +// +// The non-Thunk InputSections in OutputSection must match the order and +// OutSecOff of their counterparts in the InputSectionDescriptions. +void LinkerScript::syncWithOS(OutputSection *OS) { + // Find Commands associated with this OS + auto OutCmdPos = std::find_if( + Opt.Commands.begin(), Opt.Commands.end(), + [=](BaseCommand *Cmd) { + if (auto *OSCmd = dyn_cast(Cmd)) + return (OSCmd->Name == OS->Name); + return false; + }); + if (OutCmdPos == Opt.Commands.end()) + // LinkerScript does not describe the OS, no sync to do + return; + + // To synchonize an InputSectionDescription we find the OutSecOff of the first + // InputSection in the next InputSectionDescription. We then transfer over + // all InputSections from OS->Section with a lower OutSecOff. This makes sure + // that Thunks added after the last InputSection in an InputSectionDescription + // get assigned to that the InputSectionDescription. + // ordered OS->Sections. + + auto FindNextISDCmd = + [](std::vector::iterator Begin, + std::vector::iterator End) { + for (auto CmdIter = Begin; CmdIter != End; ++CmdIter) { + auto *Cmd = dyn_cast(*CmdIter); + if (Cmd && !Cmd->Sections.empty()) + return CmdIter; + } + return End; + }; + // Range to copy from OS->Sections + auto ISFromOSIter = OS->Sections.begin(); + auto ISFromOSEnd = OS->Sections.end(); + + // Find first InputSectionDescription for this OS + auto *OutCmd = cast(*OutCmdPos); + auto CmdIterEnd = OutCmd->Commands.end(); + auto CmdIter = FindNextISDCmd(OutCmd->Commands.begin(), CmdIterEnd); + + // Step through each InputSectionDescription, find the range + // [IsFromOsIter, ISFromOsEnd) to copy into it. + while (CmdIter != CmdIterEnd) { + auto NextCmdIter = FindNextISDCmd(CmdIter, CmdIterEnd); + if (NextCmdIter == CmdIterEnd) + // No more InputSectionDescriptions, we want all remaining InputSections + ISFromOSEnd = OS->Sections.end(); + else { + // We have another InputSectionDescription for this OS, find the + // InputSection with OutSecOff >= the OutSecOff the first + // InputSection from the next InputSectionDescription to use as our + // limit. + auto *NextCmd = cast(*NextCmdIter); + auto NextIS = cast(NextCmd->Sections.front()); + ISFromOSEnd = std::find_if(ISFromOSIter, OS->Sections.end(), + [NextIS](InputSection *IS) { + return IS->OutSecOff >= NextIS->OutSecOff; + }); + } + // Copy range from OS->Sections to InputSectionDescription + std::vector Tmp; + for (; ISFromOSIter != ISFromOSEnd; ++ISFromOSIter) + Tmp.push_back(*ISFromOSIter); + auto *Cmd = cast(*CmdIter); + Cmd->Sections = std::move(Tmp); + CmdIter = NextCmdIter; + } +} + // When placing orphan sections, we want to place them after symbol assignments // so that an orphan after // begin_foo = .; @@ -789,6 +878,7 @@ void LinkerScript::assignAddresses(std::vector &Phdrs) { // Assign addresses as instructed by linker script SECTIONS sub-commands. Dot = 0; + resetAddressState(); ErrorOnMissingSection = true; switchTo(Aether); 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" @@ -959,6 +960,11 @@ std::merge(OS->Sections.begin(), OS->Sections.end(), Thunks.begin(), Thunks.end(), std::back_inserter(Tmp), MergeCmp); OS->Sections = std::move(Tmp); + + // We need to insert the sections into the linker script input section + // commands for the correct output order + if (Script->Opt.HasSections) + Script->syncWithOS(OS); OS->assignOffsets(); } Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -1176,6 +1176,15 @@ // we need to assign addresses so that we can tell if jump instructions // are out of range. This will need to turn into a loop that converges // when no more Thunks are added + auto AddressesForThunks = [&]() { + if (Script->Opt.HasSections) + Script->assignAddresses(Phdrs); + else if (!Config->Relocatable) { + fixSectionAlignments(); + assignAddresses(); + } + }; + AddressesForThunks(); ThunkCreator TC; if (TC.createThunks(OutputSections)) applySynthetic({In::MipsGot}, 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