forked from OSchip/llvm-project
Use uint64_t to keep file size even on 32-bit machines.
If an output file is too large for 32-bit, we should report an error. llvm-svn: 299592
This commit is contained in:
parent
5c18b4406e
commit
6bd3822007
|
@ -38,7 +38,6 @@ namespace {
|
||||||
// The writer writes a SymbolTable result to a file.
|
// The writer writes a SymbolTable result to a file.
|
||||||
template <class ELFT> class Writer {
|
template <class ELFT> class Writer {
|
||||||
public:
|
public:
|
||||||
typedef typename ELFT::uint uintX_t;
|
|
||||||
typedef typename ELFT::Shdr Elf_Shdr;
|
typedef typename ELFT::Shdr Elf_Shdr;
|
||||||
typedef typename ELFT::Ehdr Elf_Ehdr;
|
typedef typename ELFT::Ehdr Elf_Ehdr;
|
||||||
typedef typename ELFT::Phdr Elf_Phdr;
|
typedef typename ELFT::Phdr Elf_Phdr;
|
||||||
|
@ -82,13 +81,13 @@ private:
|
||||||
void addRelIpltSymbols();
|
void addRelIpltSymbols();
|
||||||
void addStartEndSymbols();
|
void addStartEndSymbols();
|
||||||
void addStartStopSymbols(OutputSection *Sec);
|
void addStartStopSymbols(OutputSection *Sec);
|
||||||
uintX_t getEntryAddr();
|
uint64_t getEntryAddr();
|
||||||
OutputSection *findSection(StringRef Name);
|
OutputSection *findSection(StringRef Name);
|
||||||
|
|
||||||
std::vector<PhdrEntry> Phdrs;
|
std::vector<PhdrEntry> Phdrs;
|
||||||
|
|
||||||
uintX_t FileSize;
|
uint64_t FileSize;
|
||||||
uintX_t SectionHeaderOff;
|
uint64_t SectionHeaderOff;
|
||||||
bool AllocateHeader = true;
|
bool AllocateHeader = true;
|
||||||
};
|
};
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
@ -143,24 +142,21 @@ template <class ELFT> void Writer<ELFT>::removeEmptyPTLoad() {
|
||||||
return false;
|
return false;
|
||||||
if (!P.First)
|
if (!P.First)
|
||||||
return true;
|
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;
|
return Size == 0;
|
||||||
});
|
});
|
||||||
Phdrs.erase(I, Phdrs.end());
|
Phdrs.erase(I, Phdrs.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class ELFT>
|
static uint64_t getOutputFlags(InputSectionBase *S) {
|
||||||
static typename ELFT::uint getOutFlags(InputSectionBase *S) {
|
return S->Flags & ~(uint64_t)(SHF_GROUP | SHF_COMPRESSED);
|
||||||
return S->Flags & ~(typename ELFT::uint)(SHF_GROUP | SHF_COMPRESSED);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function scans over the input sections and creates mergeable
|
// This function scans over the input sections and creates mergeable
|
||||||
// synthetic sections. It removes MergeInputSections from array and
|
// synthetic sections. It removes MergeInputSections from array and
|
||||||
// adds new synthetic ones. Each synthetic section is added to the
|
// adds new synthetic ones. Each synthetic section is added to the
|
||||||
// location of the first input section it replaces.
|
// location of the first input section it replaces.
|
||||||
template <class ELFT> static void combineMergableSections() {
|
static void combineMergableSections() {
|
||||||
typedef typename ELFT::uint uintX_t;
|
|
||||||
|
|
||||||
std::vector<MergeSyntheticSection *> MergeSections;
|
std::vector<MergeSyntheticSection *> MergeSections;
|
||||||
for (InputSectionBase *&S : InputSections) {
|
for (InputSectionBase *&S : InputSections) {
|
||||||
MergeInputSection *MS = dyn_cast<MergeInputSection>(S);
|
MergeInputSection *MS = dyn_cast<MergeInputSection>(S);
|
||||||
|
@ -173,8 +169,8 @@ template <class ELFT> static void combineMergableSections() {
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
StringRef OutsecName = getOutputSectionName(MS->Name);
|
StringRef OutsecName = getOutputSectionName(MS->Name);
|
||||||
uintX_t Flags = getOutFlags<ELFT>(MS);
|
uint64_t Flags = getOutputFlags(MS);
|
||||||
uint32_t Alignment = std::max<uintX_t>(MS->Alignment, MS->Entsize);
|
uint32_t Alignment = std::max<uint32_t>(MS->Alignment, MS->Entsize);
|
||||||
|
|
||||||
auto I =
|
auto I =
|
||||||
llvm::find_if(MergeSections, [=](MergeSyntheticSection *Sec) {
|
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.
|
// Create linker-synthesized sections such as .got or .plt.
|
||||||
// Such sections are of type input section.
|
// Such sections are of type input section.
|
||||||
createSyntheticSections();
|
createSyntheticSections();
|
||||||
combineMergableSections<ELFT>();
|
combineMergableSections();
|
||||||
|
|
||||||
if (!Config->Relocatable)
|
if (!Config->Relocatable)
|
||||||
combineEhFrameSections<ELFT>();
|
combineEhFrameSections<ELFT>();
|
||||||
|
@ -334,7 +330,7 @@ template <class ELFT> void Writer<ELFT>::createSyntheticSections() {
|
||||||
Out::ElfHeader = make<OutputSection>("", 0, SHF_ALLOC);
|
Out::ElfHeader = make<OutputSection>("", 0, SHF_ALLOC);
|
||||||
Out::ElfHeader->Size = sizeof(Elf_Ehdr);
|
Out::ElfHeader->Size = sizeof(Elf_Ehdr);
|
||||||
Out::ProgramHeaders = make<OutputSection>("", 0, SHF_ALLOC);
|
Out::ProgramHeaders = make<OutputSection>("", 0, SHF_ALLOC);
|
||||||
Out::ProgramHeaders->updateAlignment(sizeof(uintX_t));
|
Out::ProgramHeaders->updateAlignment(Config->Wordsize);
|
||||||
|
|
||||||
if (needsInterpSection<ELFT>()) {
|
if (needsInterpSection<ELFT>()) {
|
||||||
In<ELFT>::Interp = createInterpSection();
|
In<ELFT>::Interp = createInterpSection();
|
||||||
|
@ -864,13 +860,13 @@ template <class ELFT> void Writer<ELFT>::addReservedSymbols() {
|
||||||
|
|
||||||
// Sort input sections by section name suffixes for
|
// Sort input sections by section name suffixes for
|
||||||
// __attribute__((init_priority(N))).
|
// __attribute__((init_priority(N))).
|
||||||
template <class ELFT> static void sortInitFini(OutputSection *S) {
|
static void sortInitFini(OutputSection *S) {
|
||||||
if (S)
|
if (S)
|
||||||
reinterpret_cast<OutputSection *>(S)->sortInitFini();
|
reinterpret_cast<OutputSection *>(S)->sortInitFini();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort input sections by the special rule for .ctors and .dtors.
|
// 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)
|
if (S)
|
||||||
reinterpret_cast<OutputSection *>(S)->sortCtorsDtors();
|
reinterpret_cast<OutputSection *>(S)->sortCtorsDtors();
|
||||||
}
|
}
|
||||||
|
@ -935,10 +931,10 @@ template <class ELFT> void Writer<ELFT>::createSections() {
|
||||||
Factory.addInputSec(IS, getOutputSectionName(IS->Name));
|
Factory.addInputSec(IS, getOutputSectionName(IS->Name));
|
||||||
|
|
||||||
sortBySymbolsOrder<ELFT>(OutputSections);
|
sortBySymbolsOrder<ELFT>(OutputSections);
|
||||||
sortInitFini<ELFT>(findSection(".init_array"));
|
sortInitFini(findSection(".init_array"));
|
||||||
sortInitFini<ELFT>(findSection(".fini_array"));
|
sortInitFini(findSection(".fini_array"));
|
||||||
sortCtorsDtors<ELFT>(findSection(".ctors"));
|
sortCtorsDtors(findSection(".ctors"));
|
||||||
sortCtorsDtors<ELFT>(findSection(".dtors"));
|
sortCtorsDtors(findSection(".dtors"));
|
||||||
|
|
||||||
for (OutputSection *Sec : OutputSections)
|
for (OutputSection *Sec : OutputSections)
|
||||||
Sec->assignOffsets();
|
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
|
// 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
|
// RW. This means that there is no alignment in the RO to RX transition and we
|
||||||
// cannot create a PT_LOAD there.
|
// cannot create a PT_LOAD there.
|
||||||
template <class ELFT>
|
static uint64_t computeFlags(uint64_t Flags) {
|
||||||
static typename ELFT::uint computeFlags(typename ELFT::uint F) {
|
|
||||||
if (Config->Omagic)
|
if (Config->Omagic)
|
||||||
return PF_R | PF_W | PF_X;
|
return PF_R | PF_W | PF_X;
|
||||||
if (Config->SingleRoRx && !(F & PF_W))
|
if (Config->SingleRoRx && !(Flags & PF_W))
|
||||||
return F | PF_X;
|
return Flags | PF_X;
|
||||||
return F;
|
return Flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decide which program headers to create and which sections to include in each
|
// 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);
|
AddHdr(PT_INTERP, Sec->getPhdrFlags())->add(Sec);
|
||||||
|
|
||||||
// Add the first PT_LOAD segment for regular output sections.
|
// 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);
|
PhdrEntry *Load = AddHdr(PT_LOAD, Flags);
|
||||||
for (OutputSection *Sec : OutputSections) {
|
for (OutputSection *Sec : OutputSections) {
|
||||||
if (!(Sec->Flags & SHF_ALLOC))
|
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
|
// 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
|
// different flags or is loaded at a discontiguous address using AT linker
|
||||||
// script command.
|
// script command.
|
||||||
uintX_t NewFlags = computeFlags<ELFT>(Sec->getPhdrFlags());
|
uint64_t NewFlags = computeFlags(Sec->getPhdrFlags());
|
||||||
if (Script->hasLMA(Sec->Name) || Flags != NewFlags) {
|
if (Script->hasLMA(Sec->Name) || Flags != NewFlags) {
|
||||||
Load = AddHdr(PT_LOAD, NewFlags);
|
Load = AddHdr(PT_LOAD, NewFlags);
|
||||||
Flags = NewFlags;
|
Flags = NewFlags;
|
||||||
|
@ -1480,14 +1475,16 @@ template <class ELFT> void Writer<ELFT>::fixHeaders() {
|
||||||
|
|
||||||
// Assign VAs (addresses at run-time) to output sections.
|
// Assign VAs (addresses at run-time) to output sections.
|
||||||
template <class ELFT> void Writer<ELFT>::assignAddresses() {
|
template <class ELFT> void Writer<ELFT>::assignAddresses() {
|
||||||
uintX_t VA = Config->ImageBase;
|
uint64_t VA = Config->ImageBase;
|
||||||
|
uint64_t ThreadBssOffset = 0;
|
||||||
|
|
||||||
if (AllocateHeader)
|
if (AllocateHeader)
|
||||||
VA += getHeaderSize();
|
VA += getHeaderSize();
|
||||||
uintX_t ThreadBssOffset = 0;
|
|
||||||
for (OutputSection *Sec : OutputSections) {
|
for (OutputSection *Sec : OutputSections) {
|
||||||
uint32_t Alignment = Sec->Alignment;
|
uint32_t Alignment = Sec->Alignment;
|
||||||
if (Sec->PageAlign)
|
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);
|
auto I = Config->SectionStartMap.find(Sec->Name);
|
||||||
if (I != Config->SectionStartMap.end())
|
if (I != Config->SectionStartMap.end())
|
||||||
|
@ -1499,7 +1496,7 @@ template <class ELFT> void Writer<ELFT>::assignAddresses() {
|
||||||
Sec->Addr = VA;
|
Sec->Addr = VA;
|
||||||
VA += Sec->Size;
|
VA += Sec->Size;
|
||||||
} else if (Sec->Flags & SHF_TLS && Sec->Type == SHT_NOBITS) {
|
} else if (Sec->Flags & SHF_TLS && Sec->Type == SHT_NOBITS) {
|
||||||
uintX_t TVA = VA + ThreadBssOffset;
|
uint64_t TVA = VA + ThreadBssOffset;
|
||||||
TVA = alignTo(TVA, Alignment);
|
TVA = alignTo(TVA, Alignment);
|
||||||
Sec->Addr = TVA;
|
Sec->Addr = TVA;
|
||||||
ThreadBssOffset = TVA - VA + Sec->Size;
|
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
|
// 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
|
// virtual address (modulo the page size) so that the loader can load
|
||||||
// executables without any address adjustment.
|
// executables without any address adjustment.
|
||||||
template <class ELFT, class uintX_t>
|
static uint64_t getFileAlignment(uint64_t Off, OutputSection *Sec) {
|
||||||
static uintX_t getFileAlignment(uintX_t Off, OutputSection *Sec) {
|
|
||||||
OutputSection *First = Sec->FirstInPtLoad;
|
OutputSection *First = Sec->FirstInPtLoad;
|
||||||
// If the section is not in a PT_LOAD, we just have to align it.
|
// If the section is not in a PT_LOAD, we just have to align it.
|
||||||
if (!First)
|
if (!First)
|
||||||
|
@ -1528,36 +1524,35 @@ static uintX_t getFileAlignment(uintX_t Off, OutputSection *Sec) {
|
||||||
return First->Offset + Sec->Addr - First->Addr;
|
return First->Offset + Sec->Addr - First->Addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class ELFT, class uintX_t>
|
static uint64_t setOffset(OutputSection *Sec, uint64_t Off) {
|
||||||
static uintX_t setOffset(OutputSection *Sec, uintX_t Off) {
|
|
||||||
if (Sec->Type == SHT_NOBITS) {
|
if (Sec->Type == SHT_NOBITS) {
|
||||||
Sec->Offset = Off;
|
Sec->Offset = Off;
|
||||||
return Off;
|
return Off;
|
||||||
}
|
}
|
||||||
|
|
||||||
Off = getFileAlignment<ELFT>(Off, Sec);
|
Off = getFileAlignment(Off, Sec);
|
||||||
Sec->Offset = Off;
|
Sec->Offset = Off;
|
||||||
return Off + Sec->Size;
|
return Off + Sec->Size;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class ELFT> void Writer<ELFT>::assignFileOffsetsBinary() {
|
template <class ELFT> void Writer<ELFT>::assignFileOffsetsBinary() {
|
||||||
uintX_t Off = 0;
|
uint64_t Off = 0;
|
||||||
for (OutputSection *Sec : OutputSections)
|
for (OutputSection *Sec : OutputSections)
|
||||||
if (Sec->Flags & SHF_ALLOC)
|
if (Sec->Flags & SHF_ALLOC)
|
||||||
Off = setOffset<ELFT>(Sec, Off);
|
Off = setOffset(Sec, Off);
|
||||||
FileSize = alignTo(Off, sizeof(uintX_t));
|
FileSize = alignTo(Off, Config->Wordsize);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assign file offsets to output sections.
|
// Assign file offsets to output sections.
|
||||||
template <class ELFT> void Writer<ELFT>::assignFileOffsets() {
|
template <class ELFT> void Writer<ELFT>::assignFileOffsets() {
|
||||||
uintX_t Off = 0;
|
uint64_t Off = 0;
|
||||||
Off = setOffset<ELFT>(Out::ElfHeader, Off);
|
Off = setOffset(Out::ElfHeader, Off);
|
||||||
Off = setOffset<ELFT>(Out::ProgramHeaders, Off);
|
Off = setOffset(Out::ProgramHeaders, Off);
|
||||||
|
|
||||||
for (OutputSection *Sec : OutputSections)
|
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);
|
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;
|
// 3. the value of the symbol start, if present;
|
||||||
// 4. the address of the first byte of the .text section, if present;
|
// 4. the address of the first byte of the .text section, if present;
|
||||||
// 5. the address 0.
|
// 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
|
// Case 1, 2 or 3. As a special case, if the symbol is actually
|
||||||
// a number, we'll use that number as an address.
|
// a number, we'll use that number as an address.
|
||||||
if (SymbolBody *B = Symtab<ELFT>::X->find(Config->Entry))
|
if (SymbolBody *B = Symtab<ELFT>::X->find(Config->Entry))
|
||||||
|
@ -1683,11 +1678,11 @@ template <class ELFT> void Writer<ELFT>::fixPredefinedSymbols() {
|
||||||
if (!ElfSym::MipsGp->Value) {
|
if (!ElfSym::MipsGp->Value) {
|
||||||
// Find GP-relative section with the lowest address
|
// Find GP-relative section with the lowest address
|
||||||
// and use this address to calculate default _gp value.
|
// and use this address to calculate default _gp value.
|
||||||
uintX_t Gp = -1;
|
uint64_t Gp = -1;
|
||||||
for (const OutputSection *OS : OutputSections)
|
for (const OutputSection *OS : OutputSections)
|
||||||
if ((OS->Flags & SHF_MIPS_GPREL) && OS->Addr < Gp)
|
if ((OS->Flags & SHF_MIPS_GPREL) && OS->Addr < Gp)
|
||||||
Gp = OS->Addr;
|
Gp = OS->Addr;
|
||||||
if (Gp != (uintX_t)-1)
|
if (Gp != (uint64_t)-1)
|
||||||
ElfSym::MipsGp->Value = Gp + 0x7ff0;
|
ElfSym::MipsGp->Value = Gp + 0x7ff0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1749,6 +1744,11 @@ template <class ELFT> void Writer<ELFT>::writeHeader() {
|
||||||
|
|
||||||
// Open a result file.
|
// Open a result file.
|
||||||
template <class ELFT> void Writer<ELFT>::openFile() {
|
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);
|
unlinkAsync(Config->OutputFile);
|
||||||
ErrorOr<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
|
ErrorOr<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
|
||||||
FileOutputBuffer::create(Config->OutputFile, FileSize,
|
FileOutputBuffer::create(Config->OutputFile, FileSize,
|
||||||
|
|
|
@ -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
|
Loading…
Reference in New Issue