diff options
-rw-r--r-- | lld/ELF/Writer.cpp | 96 | ||||
-rw-r--r-- | lld/test/ELF/linkerscript/output-too-large.s | 8 |
2 files changed, 56 insertions, 48 deletions
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index 094f889e897..680d8c1a144 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -38,7 +38,6 @@ namespace { // The writer writes a SymbolTable result to a file. template <class ELFT> class Writer { public: - typedef typename ELFT::uint uintX_t; typedef typename ELFT::Shdr Elf_Shdr; typedef typename ELFT::Ehdr Elf_Ehdr; typedef typename ELFT::Phdr Elf_Phdr; @@ -82,13 +81,13 @@ private: void addRelIpltSymbols(); void addStartEndSymbols(); void addStartStopSymbols(OutputSection *Sec); - uintX_t getEntryAddr(); + uint64_t getEntryAddr(); OutputSection *findSection(StringRef Name); std::vector<PhdrEntry> Phdrs; - uintX_t FileSize; - uintX_t SectionHeaderOff; + uint64_t FileSize; + uint64_t SectionHeaderOff; bool AllocateHeader = true; }; } // anonymous namespace @@ -143,24 +142,21 @@ template <class ELFT> void Writer<ELFT>::removeEmptyPTLoad() { return false; if (!P.First) return true; - uintX_t Size = P.Last->Addr + P.Last->Size - P.First->Addr; + uint64_t Size = P.Last->Addr + P.Last->Size - P.First->Addr; return Size == 0; }); Phdrs.erase(I, Phdrs.end()); } -template <class ELFT> -static typename ELFT::uint getOutFlags(InputSectionBase *S) { - return S->Flags & ~(typename ELFT::uint)(SHF_GROUP | SHF_COMPRESSED); +static uint64_t getOutputFlags(InputSectionBase *S) { + return S->Flags & ~(uint64_t)(SHF_GROUP | SHF_COMPRESSED); } // This function scans over the input sections and creates mergeable // synthetic sections. It removes MergeInputSections from array and // adds new synthetic ones. Each synthetic section is added to the // location of the first input section it replaces. -template <class ELFT> static void combineMergableSections() { - typedef typename ELFT::uint uintX_t; - +static void combineMergableSections() { std::vector<MergeSyntheticSection *> MergeSections; for (InputSectionBase *&S : InputSections) { MergeInputSection *MS = dyn_cast<MergeInputSection>(S); @@ -173,8 +169,8 @@ template <class ELFT> static void combineMergableSections() { continue; StringRef OutsecName = getOutputSectionName(MS->Name); - uintX_t Flags = getOutFlags<ELFT>(MS); - uint32_t Alignment = std::max<uintX_t>(MS->Alignment, MS->Entsize); + uint64_t Flags = getOutputFlags(MS); + uint32_t Alignment = std::max<uint32_t>(MS->Alignment, MS->Entsize); auto I = llvm::find_if(MergeSections, [=](MergeSyntheticSection *Sec) { @@ -216,7 +212,7 @@ template <class ELFT> void Writer<ELFT>::run() { // Create linker-synthesized sections such as .got or .plt. // Such sections are of type input section. createSyntheticSections(); - combineMergableSections<ELFT>(); + combineMergableSections(); if (!Config->Relocatable) combineEhFrameSections<ELFT>(); @@ -334,7 +330,7 @@ template <class ELFT> void Writer<ELFT>::createSyntheticSections() { Out::ElfHeader = make<OutputSection>("", 0, SHF_ALLOC); Out::ElfHeader->Size = sizeof(Elf_Ehdr); Out::ProgramHeaders = make<OutputSection>("", 0, SHF_ALLOC); - Out::ProgramHeaders->updateAlignment(sizeof(uintX_t)); + Out::ProgramHeaders->updateAlignment(Config->Wordsize); if (needsInterpSection<ELFT>()) { In<ELFT>::Interp = createInterpSection(); @@ -864,13 +860,13 @@ template <class ELFT> void Writer<ELFT>::addReservedSymbols() { // Sort input sections by section name suffixes for // __attribute__((init_priority(N))). -template <class ELFT> static void sortInitFini(OutputSection *S) { +static void sortInitFini(OutputSection *S) { if (S) reinterpret_cast<OutputSection *>(S)->sortInitFini(); } // Sort input sections by the special rule for .ctors and .dtors. -template <class ELFT> static void sortCtorsDtors(OutputSection *S) { +static void sortCtorsDtors(OutputSection *S) { if (S) reinterpret_cast<OutputSection *>(S)->sortCtorsDtors(); } @@ -935,10 +931,10 @@ template <class ELFT> void Writer<ELFT>::createSections() { Factory.addInputSec(IS, getOutputSectionName(IS->Name)); sortBySymbolsOrder<ELFT>(OutputSections); - sortInitFini<ELFT>(findSection(".init_array")); - sortInitFini<ELFT>(findSection(".fini_array")); - sortCtorsDtors<ELFT>(findSection(".ctors")); - sortCtorsDtors<ELFT>(findSection(".dtors")); + sortInitFini(findSection(".init_array")); + sortInitFini(findSection(".fini_array")); + sortCtorsDtors(findSection(".ctors")); + sortCtorsDtors(findSection(".dtors")); for (OutputSection *Sec : OutputSections) Sec->assignOffsets(); @@ -1266,13 +1262,12 @@ static bool needsPtLoad(OutputSection *Sec) { // linker scripts are designed for creating two PT_LOADs only, one RX and one // RW. This means that there is no alignment in the RO to RX transition and we // cannot create a PT_LOAD there. -template <class ELFT> -static typename ELFT::uint computeFlags(typename ELFT::uint F) { +static uint64_t computeFlags(uint64_t Flags) { if (Config->Omagic) return PF_R | PF_W | PF_X; - if (Config->SingleRoRx && !(F & PF_W)) - return F | PF_X; - return F; + if (Config->SingleRoRx && !(Flags & PF_W)) + return Flags | PF_X; + return Flags; } // Decide which program headers to create and which sections to include in each @@ -1292,7 +1287,7 @@ template <class ELFT> std::vector<PhdrEntry> Writer<ELFT>::createPhdrs() { AddHdr(PT_INTERP, Sec->getPhdrFlags())->add(Sec); // Add the first PT_LOAD segment for regular output sections. - uintX_t Flags = computeFlags<ELFT>(PF_R); + uint64_t Flags = computeFlags(PF_R); PhdrEntry *Load = AddHdr(PT_LOAD, Flags); for (OutputSection *Sec : OutputSections) { if (!(Sec->Flags & SHF_ALLOC)) @@ -1305,7 +1300,7 @@ template <class ELFT> std::vector<PhdrEntry> Writer<ELFT>::createPhdrs() { // Therefore, we need to create a new phdr when the next section has // different flags or is loaded at a discontiguous address using AT linker // script command. - uintX_t NewFlags = computeFlags<ELFT>(Sec->getPhdrFlags()); + uint64_t NewFlags = computeFlags(Sec->getPhdrFlags()); if (Script->hasLMA(Sec->Name) || Flags != NewFlags) { Load = AddHdr(PT_LOAD, NewFlags); Flags = NewFlags; @@ -1480,14 +1475,16 @@ template <class ELFT> void Writer<ELFT>::fixHeaders() { // Assign VAs (addresses at run-time) to output sections. template <class ELFT> void Writer<ELFT>::assignAddresses() { - uintX_t VA = Config->ImageBase; + uint64_t VA = Config->ImageBase; + uint64_t ThreadBssOffset = 0; + if (AllocateHeader) VA += getHeaderSize(); - uintX_t ThreadBssOffset = 0; + for (OutputSection *Sec : OutputSections) { uint32_t Alignment = Sec->Alignment; if (Sec->PageAlign) - Alignment = std::max<uintX_t>(Alignment, Config->MaxPageSize); + Alignment = std::max<uint32_t>(Alignment, Config->MaxPageSize); auto I = Config->SectionStartMap.find(Sec->Name); if (I != Config->SectionStartMap.end()) @@ -1499,7 +1496,7 @@ template <class ELFT> void Writer<ELFT>::assignAddresses() { Sec->Addr = VA; VA += Sec->Size; } else if (Sec->Flags & SHF_TLS && Sec->Type == SHT_NOBITS) { - uintX_t TVA = VA + ThreadBssOffset; + uint64_t TVA = VA + ThreadBssOffset; TVA = alignTo(TVA, Alignment); Sec->Addr = TVA; ThreadBssOffset = TVA - VA + Sec->Size; @@ -1511,8 +1508,7 @@ template <class ELFT> void Writer<ELFT>::assignAddresses() { // its new file offset. The file offset must be the same with its // virtual address (modulo the page size) so that the loader can load // executables without any address adjustment. -template <class ELFT, class uintX_t> -static uintX_t getFileAlignment(uintX_t Off, OutputSection *Sec) { +static uint64_t getFileAlignment(uint64_t Off, OutputSection *Sec) { OutputSection *First = Sec->FirstInPtLoad; // If the section is not in a PT_LOAD, we just have to align it. if (!First) @@ -1528,36 +1524,35 @@ static uintX_t getFileAlignment(uintX_t Off, OutputSection *Sec) { return First->Offset + Sec->Addr - First->Addr; } -template <class ELFT, class uintX_t> -static uintX_t setOffset(OutputSection *Sec, uintX_t Off) { +static uint64_t setOffset(OutputSection *Sec, uint64_t Off) { if (Sec->Type == SHT_NOBITS) { Sec->Offset = Off; return Off; } - Off = getFileAlignment<ELFT>(Off, Sec); + Off = getFileAlignment(Off, Sec); Sec->Offset = Off; return Off + Sec->Size; } template <class ELFT> void Writer<ELFT>::assignFileOffsetsBinary() { - uintX_t Off = 0; + uint64_t Off = 0; for (OutputSection *Sec : OutputSections) if (Sec->Flags & SHF_ALLOC) - Off = setOffset<ELFT>(Sec, Off); - FileSize = alignTo(Off, sizeof(uintX_t)); + Off = setOffset(Sec, Off); + FileSize = alignTo(Off, Config->Wordsize); } // Assign file offsets to output sections. template <class ELFT> void Writer<ELFT>::assignFileOffsets() { - uintX_t Off = 0; - Off = setOffset<ELFT>(Out::ElfHeader, Off); - Off = setOffset<ELFT>(Out::ProgramHeaders, Off); + uint64_t Off = 0; + Off = setOffset(Out::ElfHeader, Off); + Off = setOffset(Out::ProgramHeaders, Off); for (OutputSection *Sec : OutputSections) - Off = setOffset<ELFT>(Sec, Off); + Off = setOffset(Sec, Off); - SectionHeaderOff = alignTo(Off, sizeof(uintX_t)); + SectionHeaderOff = alignTo(Off, Config->Wordsize); FileSize = SectionHeaderOff + (OutputSections.size() + 1) * sizeof(Elf_Shdr); } @@ -1604,7 +1599,7 @@ template <class ELFT> void Writer<ELFT>::setPhdrs() { // 3. the value of the symbol start, if present; // 4. the address of the first byte of the .text section, if present; // 5. the address 0. -template <class ELFT> typename ELFT::uint Writer<ELFT>::getEntryAddr() { +template <class ELFT> uint64_t Writer<ELFT>::getEntryAddr() { // Case 1, 2 or 3. As a special case, if the symbol is actually // a number, we'll use that number as an address. if (SymbolBody *B = Symtab<ELFT>::X->find(Config->Entry)) @@ -1683,11 +1678,11 @@ template <class ELFT> void Writer<ELFT>::fixPredefinedSymbols() { if (!ElfSym::MipsGp->Value) { // Find GP-relative section with the lowest address // and use this address to calculate default _gp value. - uintX_t Gp = -1; + uint64_t Gp = -1; for (const OutputSection *OS : OutputSections) if ((OS->Flags & SHF_MIPS_GPREL) && OS->Addr < Gp) Gp = OS->Addr; - if (Gp != (uintX_t)-1) + if (Gp != (uint64_t)-1) ElfSym::MipsGp->Value = Gp + 0x7ff0; } } @@ -1749,6 +1744,11 @@ template <class ELFT> void Writer<ELFT>::writeHeader() { // Open a result file. template <class ELFT> void Writer<ELFT>::openFile() { + if (!Config->Is64 && FileSize > UINT32_MAX) { + error("output file too large: " + Twine(FileSize) + " bytes"); + return; + } + unlinkAsync(Config->OutputFile); ErrorOr<std::unique_ptr<FileOutputBuffer>> BufferOrErr = FileOutputBuffer::create(Config->OutputFile, FileSize, diff --git a/lld/test/ELF/linkerscript/output-too-large.s b/lld/test/ELF/linkerscript/output-too-large.s new file mode 100644 index 00000000000..db021eaa99e --- /dev/null +++ b/lld/test/ELF/linkerscript/output-too-large.s @@ -0,0 +1,8 @@ +# RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t.o +# RUN: echo "SECTIONS { .text : { . = 0xffffffff; *(.text*); } }" > %t.script +# RUN: not ld.lld --script %t.script %t.o -o %t 2>&1 | FileCheck %s +# CHECK: error: output file too large + +.global _start +_start: + nop |