Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -19,6 +19,7 @@ namespace lld { namespace elf { +class LocCounterEvaluator; class ScriptParser; template class InputSectionBase; @@ -54,6 +55,9 @@ template bool isDiscarded(InputSectionBase *S); template bool shouldKeep(InputSectionBase *S); int compareSections(StringRef A, StringRef B); + uint64_t getSectionVA(StringRef Name, uint64_t VA); + + bool Exist = false; private: template SectionRule *find(InputSectionBase *S); @@ -67,6 +71,9 @@ // Section fill attribute for each section. llvm::StringMap> Filler; + // Contains the tokens for calculating VA of an output section. + llvm::StringMap> SecLoc; + llvm::BumpPtrAllocator Alloc; }; Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -28,7 +28,44 @@ using namespace lld; using namespace lld::elf; +class elf::LocCounterEvaluator { +public: + void setLocationCounter(uint64_t VA) { Values["."] = VA; } + + // Evaluates the expression given by list of tokens. + uint64_t evaluate(std::vector &Tokens) { + uint64_t Result = 0; + for (size_t I = 0, E = Tokens.size(); I < E; ++I) { + // Each second token should be '+' as this is the + // only operator we support now + if (I % 2 == 1) { + if (Tokens[I] == "+") + continue; + error("error in location counter expression"); + return 0; + } + Result += getValue(Tokens[I]); + } + return Result; + } + + uint64_t getValue(StringRef V) { + uint64_t Val; + if (!V.getAsInteger(0, Val)) + return Val; + auto I = Values.find(V); + if (I != Values.end()) + return I->second; + error("undeclared variable " + V); + return 0; + } + +protected: + std::map Values; +}; + LinkerScript *elf::Script; +LocCounterEvaluator Eval; template SectionRule *LinkerScript::find(InputSectionBase *S) { @@ -73,6 +110,15 @@ return I < J ? -1 : 1; } +uint64_t LinkerScript::getSectionVA(StringRef Name, uint64_t VA) { + auto It = SecLoc.find(Name); + if (It == SecLoc.end()) + return VA; + + Eval.setLocationCounter(VA); + return Eval.evaluate(It->second); +} + // Returns true if S matches T. S can contain glob meta-characters. // The asterisk ('*') matches zero or more characacters, and the question // mark ('?') matches one character. @@ -137,6 +183,8 @@ void readOutputSectionDescription(); void readSectionPatterns(StringRef OutSec, bool Keep); + std::vector readLocationCounterValue(); + std::vector parseHex(StringRef S); StringSaver Saver; @@ -145,6 +193,8 @@ size_t Pos = 0; bool IsUnderSysroot; bool Error = false; + + std::vector LocCounterTokens; }; const StringMap elf::ScriptParser::Cmd = { @@ -427,7 +477,27 @@ return Hex; } +std::vector ScriptParser::readLocationCounterValue() { + expect("."); + expect("="); + + std::vector ExpList; + while (!Error) { + StringRef Tok = next(); + if (Tok == ";") + break; + ExpList.push_back(Tok); + } + return ExpList; +} + void ScriptParser::readOutputSectionDescription() { + StringRef Tok = peek(); + if (Tok == ".") { + LocCounterTokens = readLocationCounterValue(); + return; + } + StringRef OutSec = next(); Script->SectionOrder.push_back(OutSec); expect(":"); @@ -445,7 +515,7 @@ setError("unknown command " + Tok); } } - StringRef Tok = peek(); + Tok = peek(); if (Tok.startswith("=")) { if (!Tok.startswith("=0x")) { setError("filler should be a hexadecimal value"); @@ -455,6 +525,9 @@ Script->Filler[OutSec] = parseHex(Tok); next(); } + + if (!LocCounterTokens.empty()) + Script->SecLoc[OutSec] = std::move(LocCounterTokens); } static bool isUnderSysroot(StringRef Path) { @@ -470,6 +543,7 @@ void LinkerScript::read(MemoryBufferRef MB) { StringRef Path = MB.getBufferIdentifier(); ScriptParser(&Alloc, MB.getBuffer(), isUnderSysroot(Path)).run(); + Exist = true; } template StringRef LinkerScript::getOutputSection(InputSectionBase *); Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -71,6 +71,7 @@ void createPhdrs(); void assignAddresses(); void assignAddressesRelocatable(); + void assignAddressesScript(); void fixAbsoluteSymbols(); bool openFile(); void writeHeader(); @@ -210,12 +211,17 @@ addReservedSymbols(); if (!createSections()) return; - if (!Config->Relocatable) { + + if (!Config->Relocatable) createPhdrs(); - assignAddresses(); - } else { + + if (Script->Exist) + assignAddressesScript(); + else if (Config->Relocatable) assignAddressesRelocatable(); - } + else + assignAddresses(); + fixAbsoluteSymbols(); if (!openFile()) return; @@ -1407,6 +1413,72 @@ } } +template void Writer::assignAddressesScript() { + Out::ElfHeader->setSize(sizeof(Elf_Ehdr)); + size_t PhdrSize = sizeof(Elf_Phdr) * Phdrs.size(); + Out::ProgramHeaders->setSize(PhdrSize); + + uintX_t ThreadBssOffset = 0; + uintX_t VA = 0; + uintX_t FileOff = 0; + + for (OutputSectionBase *Sec : OutputSections) { + uintX_t Align = Sec->getAlign(); + if (Sec->getType() != SHT_NOBITS) + FileOff = alignTo(FileOff, Align); + Sec->setFileOffset(FileOff); + if (Sec->getType() != SHT_NOBITS) + FileOff += Sec->getSize(); + + VA = Script->getSectionVA(Sec->getName(), VA); + + // We only assign VAs to allocated sections. + if (needsPtLoad(Sec)) { + VA = alignTo(VA, Align); + Sec->setVA(VA); + VA += Sec->getSize(); + } else if (Sec->getFlags() & SHF_TLS && Sec->getType() == SHT_NOBITS) { + uintX_t TVA = VA + ThreadBssOffset; + TVA = alignTo(TVA, Align); + Sec->setVA(TVA); + ThreadBssOffset = TVA - VA + Sec->getSize(); + } + } + + // Add space for section headers. + SectionHeaderOff = alignTo(FileOff, sizeof(uintX_t)); + FileSize = SectionHeaderOff + getNumSections() * sizeof(Elf_Shdr); + + // Update "_end" and "end" symbols so that they + // point to the end of the data segment. + ElfSym::End.st_value = VA; + + for (Phdr &PHdr : Phdrs) { + Elf_Phdr &H = PHdr.H; + if (PHdr.First) { + OutputSectionBase *Last = PHdr.Last; + H.p_filesz = Last->getFileOff() - PHdr.First->getFileOff(); + if (Last->getType() != SHT_NOBITS) + H.p_filesz += Last->getSize(); + H.p_memsz = Last->getVA() + Last->getSize() - PHdr.First->getVA(); + H.p_offset = PHdr.First->getFileOff(); + H.p_vaddr = PHdr.First->getVA(); + } + if (H.p_type == PT_LOAD) + H.p_align = Target->PageSize; + else if (H.p_type == PT_GNU_RELRO) + H.p_align = 1; + H.p_paddr = H.p_vaddr; + + // The TLS pointer goes after PT_TLS. At least glibc will align it, + // so round up the size to make sure the offsets are correct. + if (H.p_type == PT_TLS) { + Out::TlsPhdr = &H; + H.p_memsz = alignTo(H.p_memsz, H.p_align); + } + } +} + static uint32_t getMipsEFlags() { // FIXME: In fact ELF flags depends on ELF flags of input object files // and selected emulation. For now just use hard coded values. Index: test/ELF/end.s =================================================================== --- test/ELF/end.s +++ test/ELF/end.s @@ -36,13 +36,13 @@ // NOBSS-NEXT: SHF_ALLOC // NOBSS-NEXT: SHF_WRITE // NOBSS-NEXT: ] -// NOBSS-NEXT: Address: 0x12000 +// NOBSS-NEXT: Address: 0x159 // NOBSS-NEXT: Offset: // NOBSS-NEXT: Size: 2 // NOBSS: ] // NOBSS: Symbols [ // NOBSS: Name: _end -// NOBSS-NEXT: Value: 0x12002 +// NOBSS-NEXT: Value: 0x15B // NOBSS: ] // If the layout of the sections is changed, "_end" should point to the end of allocated address space. @@ -60,13 +60,13 @@ // TEXTATEND-NEXT: SHF_ALLOC // TEXTATEND-NEXT: SHF_EXECINSTR // TEXTATEND-NEXT: ] -// TEXTATEND-NEXT: Address: 0x12000 +// TEXTATEND-NEXT: Address: 0x160 // TEXTATEND-NEXT: Offset: // TEXTATEND-NEXT: Size: 1 // TEXTATEND: ] // TEXTATEND: Symbols [ // TEXTATEND: Name: _end -// TEXTATEND-NEXT: Value: 0x12001 +// TEXTATEND-NEXT: Value: 0x161 // TEXTATEND: ] .global _start,_end Index: test/ELF/linkerscript-locationcounter.s =================================================================== --- test/ELF/linkerscript-locationcounter.s +++ test/ELF/linkerscript-locationcounter.s @@ -0,0 +1,67 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t +# RUN: echo "SECTIONS { \ +# RUN: . = 0x12341; \ +# RUN: .data : { *(.data) } \ +# RUN: . = . + 0x10000; \ +# RUN: .text : { *(.text) } \ +# RUN: }" > %t.script + +# RUN: ld.lld %t --script %t.script -o %t2 +# RUN: llvm-readobj -s %t2 | FileCheck %s + +# CHECK: Sections [ +# CHECK-NEXT: Section { +# CHECK-NEXT: Index: 0 +# CHECK-NEXT: Name: (0) +# CHECK-NEXT: Type: SHT_NULL +# CHECK-NEXT: Flags [ +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x0 +# CHECK-NEXT: Offset: 0x0 +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Link: 0 +# CHECK-NEXT: Info: 0 +# CHECK-NEXT: AddressAlignment: 0 +# CHECK-NEXT: EntrySize: 0 +# CHECK-NEXT: } +# CHECK-NEXT: Section { +# CHECK-NEXT: Index: 1 +# CHECK-NEXT: Name: .data +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: SHF_WRITE +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x12341 +# CHECK-NEXT: Offset: 0x158 +# CHECK-NEXT: Size: 8 +# CHECK-NEXT: Link: 0 +# CHECK-NEXT: Info: 0 +# CHECK-NEXT: AddressAlignment: 1 +# CHECK-NEXT: EntrySize: 0 +# CHECK-NEXT: } +# CHECK-NEXT: Section { +# CHECK-NEXT: Index: 2 +# CHECK-NEXT: Name: .text +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: SHF_EXECINSTR +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x2234C +# CHECK-NEXT: Offset: 0x160 +# CHECK-NEXT: Size: 1 +# CHECK-NEXT: Link: 0 +# CHECK-NEXT: Info: 0 +# CHECK-NEXT: AddressAlignment: 4 +# CHECK-NEXT: EntrySize: 0 +# CHECK-NEXT: } + +.globl _start; +_start: +nop + +.section .data +.quad 0 + Index: test/ELF/linkerscript-sections-keep.s =================================================================== --- test/ELF/linkerscript-sections-keep.s +++ test/ELF/linkerscript-sections-keep.s @@ -12,8 +12,8 @@ # SECGC: Sections: # SECGC-NEXT: Idx Name Size Address Type # SECGC-NEXT: 0 00000000 0000000000000000 -# SECGC-NEXT: 1 .text 00000007 0000000000011000 TEXT DATA -# SECGC-NEXT: 2 .temp 00000004 0000000000012000 DATA +# SECGC-NEXT: 1 .text 00000007 0000000000000158 TEXT DATA +# SECGC-NEXT: 2 .temp 00000004 000000000000015f DATA ## Now apply KEEP command to preserve the section. # RUN: echo "SECTIONS { \ @@ -26,9 +26,9 @@ # SECNOGC: Sections: # SECNOGC-NEXT: Idx Name Size Address Type # SECNOGC-NEXT: 0 00000000 0000000000000000 -# SECNOGC-NEXT: 1 .text 00000007 0000000000011000 TEXT DATA -# SECNOGC-NEXT: 2 .keep 00000004 0000000000012000 DATA -# SECNOGC-NEXT: 3 .temp 00000004 0000000000012004 DATA +# SECNOGC-NEXT: 1 .text 00000007 0000000000000158 TEXT DATA +# SECNOGC-NEXT: 2 .keep 00000004 000000000000015f DATA +# SECNOGC-NEXT: 3 .temp 00000004 0000000000000163 DATA ## A section name matches two entries in the SECTIONS directive. The ## first one doesn't have KEEP, the second one does. If section that have @@ -42,9 +42,9 @@ # KEEP-AT-FIRST: Sections: # KEEP-AT-FIRST-NEXT: Idx Name Size Address Type # KEEP-AT-FIRST-NEXT: 0 00000000 0000000000000000 -# KEEP-AT-FIRST-NEXT: 1 .keep 00000004 0000000000010120 DATA -# KEEP-AT-FIRST-NEXT: 2 .temp 00000004 0000000000010124 DATA -# KEEP-AT-FIRST-NEXT: 3 .text 00000007 0000000000011000 TEXT DATA +# KEEP-AT-FIRST-NEXT: 1 .keep 00000004 0000000000000120 DATA +# KEEP-AT-FIRST-NEXT: 2 .temp 00000004 0000000000000124 DATA +# KEEP-AT-FIRST-NEXT: 3 .text 00000007 0000000000000128 TEXT DATA # KEEP-AT-FIRST-NEXT: 4 .symtab 00000060 0000000000000000 # KEEP-AT-FIRST-NEXT: 5 .shstrtab 0000002d 0000000000000000 # KEEP-AT-FIRST-NEXT: 6 .strtab 00000012 0000000000000000 @@ -63,8 +63,8 @@ # KEEP-AT-SECOND: Sections: # KEEP-AT-SECOND-NEXT: Idx Name Size Address Type # KEEP-AT-SECOND-NEXT: 0 00000000 0000000000000000 -# KEEP-AT-SECOND-NEXT: 1 .temp 00000004 0000000000010120 DATA -# KEEP-AT-SECOND-NEXT: 2 .text 00000007 0000000000011000 TEXT DATA +# KEEP-AT-SECOND-NEXT: 1 .temp 00000004 0000000000000120 DATA +# KEEP-AT-SECOND-NEXT: 2 .text 00000007 0000000000000124 TEXT DATA # KEEP-AT-SECOND-NEXT: 3 .symtab 00000048 0000000000000000 # KEEP-AT-SECOND-NEXT: 4 .shstrtab 00000027 0000000000000000 # KEEP-AT-SECOND-NEXT: 5 .strtab 0000000d 0000000000000000 Index: test/ELF/wildcards.s =================================================================== --- test/ELF/wildcards.s +++ test/ELF/wildcards.s @@ -10,10 +10,10 @@ # SEC-DEFAULT: Sections: # SEC-DEFAULT-NEXT: Idx Name Size Address Type # SEC-DEFAULT-NEXT: 0 00000000 0000000000000000 -# SEC-DEFAULT-NEXT: 1 .text 00000008 0000000000011000 TEXT DATA -# SEC-DEFAULT-NEXT: 2 .abcd 00000004 0000000000011008 TEXT DATA -# SEC-DEFAULT-NEXT: 3 .ad 00000004 000000000001100c TEXT DATA -# SEC-DEFAULT-NEXT: 4 .ag 00000004 0000000000011010 TEXT DATA +# SEC-DEFAULT-NEXT: 1 .text 00000008 0000000000000120 TEXT DATA +# SEC-DEFAULT-NEXT: 2 .abcd 00000004 0000000000000128 TEXT DATA +# SEC-DEFAULT-NEXT: 3 .ad 00000004 000000000000012c TEXT DATA +# SEC-DEFAULT-NEXT: 4 .ag 00000004 0000000000000130 TEXT DATA # SEC-DEFAULT-NEXT: 5 .symtab 00000030 0000000000000000 # SEC-DEFAULT-NEXT: 6 .shstrtab 0000002f 0000000000000000 # SEC-DEFAULT-NEXT: 7 .strtab 00000008 0000000000000000 @@ -34,9 +34,9 @@ # SEC-ALL: Sections: # SEC-ALL-NEXT: Idx Name Size Address Type # SEC-ALL-NEXT: 0 00000000 0000000000000000 -# SEC-ALL-NEXT: 1 .text 0000000c 0000000000011000 TEXT DATA -# SEC-ALL-NEXT: 2 .ad 00000004 000000000001100c TEXT DATA -# SEC-ALL-NEXT: 3 .ag 00000004 0000000000011010 TEXT DATA +# SEC-ALL-NEXT: 1 .text 0000000c 0000000000000120 TEXT DATA +# SEC-ALL-NEXT: 2 .ad 00000004 000000000000012c TEXT DATA +# SEC-ALL-NEXT: 3 .ag 00000004 0000000000000130 TEXT DATA # SEC-ALL-NEXT: 4 .symtab 00000030 0000000000000000 # SEC-ALL-NEXT: 5 .shstrtab 00000029 0000000000000000 # SEC-ALL-NEXT: 6 .strtab 00000008 0000000000000000 @@ -50,7 +50,7 @@ # SEC-NO: Sections: # SEC-NO-NEXT: Idx Name Size Address Type # SEC-NO-NEXT: 0 00000000 0000000000000000 -# SEC-NO-NEXT: 1 .text 00000014 0000000000011000 TEXT DATA +# SEC-NO-NEXT: 1 .text 00000014 0000000000000120 TEXT DATA # SEC-NO-NEXT: 2 .symtab 00000030 0000000000000000 # SEC-NO-NEXT: 3 .shstrtab 00000021 0000000000000000 # SEC-NO-NEXT: 4 .strtab 00000008 0000000000000000