[ELF] Always use Script::assignAddresses()
This change fabricates linker script commands for the case where there is no linker script SECTIONS to control address assignment. This permits us to have a single Script->assignAddresses() function. There is a small change in user-visible-behavior with respect to the handling of .tbss SHT_NOBITS, SHF_TLS as the Script->assignAddresses() requires setDot() to be called with monotically increasing addresses. The tls-offset.s test has been updated so that the script and non-script results match. This change should make the non-script behavior of lld closer to an equivalent linker script. Differential Revision: https://reviews.llvm.org/D31888 llvm-svn: 300687
This commit is contained in:
parent
cb89513bc7
commit
cbfe9e946f
|
@ -413,6 +413,56 @@ void LinkerScript::processCommands(OutputSectionFactory &Factory) {
|
||||||
CurOutSec = nullptr;
|
CurOutSec = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LinkerScript::fabricateDefaultCommands(bool AllocateHeader) {
|
||||||
|
std::vector<BaseCommand *> Commands;
|
||||||
|
|
||||||
|
// Define start address
|
||||||
|
uint64_t StartAddr = Config->ImageBase;
|
||||||
|
if (AllocateHeader)
|
||||||
|
StartAddr += elf::getHeaderSize();
|
||||||
|
|
||||||
|
// The Sections with -T<section> are sorted in order of ascending address
|
||||||
|
// we must use this if it is lower than StartAddr as calls to setDot() must
|
||||||
|
// be monotonically increasing
|
||||||
|
if (!Config->SectionStartMap.empty()) {
|
||||||
|
uint64_t LowestSecStart = Config->SectionStartMap.begin()->second;
|
||||||
|
StartAddr = std::min(StartAddr, LowestSecStart);
|
||||||
|
}
|
||||||
|
Commands.push_back(
|
||||||
|
make<SymbolAssignment>(".", [=] { return StartAddr; }, ""));
|
||||||
|
|
||||||
|
// For each OutputSection that needs a VA fabricate an OutputSectionCommand
|
||||||
|
// with an InputSectionDescription describing the InputSections
|
||||||
|
for (OutputSection *Sec : *OutputSections) {
|
||||||
|
if (!(Sec->Flags & SHF_ALLOC))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto I = Config->SectionStartMap.find(Sec->Name);
|
||||||
|
if (I != Config->SectionStartMap.end())
|
||||||
|
Commands.push_back(
|
||||||
|
make<SymbolAssignment>(".", [=] { return I->second; }, ""));
|
||||||
|
|
||||||
|
auto *OSCmd = make<OutputSectionCommand>(Sec->Name);
|
||||||
|
OSCmd->Sec = Sec;
|
||||||
|
if (Sec->PageAlign)
|
||||||
|
OSCmd->AddrExpr = [=] {
|
||||||
|
return alignTo(Script->getDot(), Config->MaxPageSize);
|
||||||
|
};
|
||||||
|
Commands.push_back(OSCmd);
|
||||||
|
if (Sec->Sections.size()) {
|
||||||
|
auto *ISD = make<InputSectionDescription>("");
|
||||||
|
OSCmd->Commands.push_back(ISD);
|
||||||
|
for (InputSection *ISec : Sec->Sections) {
|
||||||
|
ISD->Sections.push_back(ISec);
|
||||||
|
ISec->Assigned = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// SECTIONS commands run before other non SECTIONS commands
|
||||||
|
Commands.insert(Commands.end(), Opt.Commands.begin(), Opt.Commands.end());
|
||||||
|
Opt.Commands = std::move(Commands);
|
||||||
|
}
|
||||||
|
|
||||||
// Add sections that didn't match any sections command.
|
// Add sections that didn't match any sections command.
|
||||||
void LinkerScript::addOrphanSections(OutputSectionFactory &Factory) {
|
void LinkerScript::addOrphanSections(OutputSectionFactory &Factory) {
|
||||||
for (InputSectionBase *S : InputSections)
|
for (InputSectionBase *S : InputSections)
|
||||||
|
|
|
@ -256,6 +256,7 @@ public:
|
||||||
bool isDefined(StringRef S);
|
bool isDefined(StringRef S);
|
||||||
|
|
||||||
std::vector<OutputSection *> *OutputSections;
|
std::vector<OutputSection *> *OutputSections;
|
||||||
|
void fabricateDefaultCommands(bool AllocateHeader);
|
||||||
void addOrphanSections(OutputSectionFactory &Factory);
|
void addOrphanSections(OutputSectionFactory &Factory);
|
||||||
void removeEmptyCommands();
|
void removeEmptyCommands();
|
||||||
void adjustSectionsBeforeSorting();
|
void adjustSectionsBeforeSorting();
|
||||||
|
|
|
@ -59,7 +59,6 @@ private:
|
||||||
std::vector<PhdrEntry> createPhdrs();
|
std::vector<PhdrEntry> createPhdrs();
|
||||||
void removeEmptyPTLoad();
|
void removeEmptyPTLoad();
|
||||||
void addPtArmExid(std::vector<PhdrEntry> &Phdrs);
|
void addPtArmExid(std::vector<PhdrEntry> &Phdrs);
|
||||||
void assignAddresses();
|
|
||||||
void assignFileOffsets();
|
void assignFileOffsets();
|
||||||
void assignFileOffsetsBinary();
|
void assignFileOffsetsBinary();
|
||||||
void setPhdrs();
|
void setPhdrs();
|
||||||
|
@ -251,13 +250,11 @@ template <class ELFT> void Writer<ELFT>::run() {
|
||||||
if (Config->Relocatable) {
|
if (Config->Relocatable) {
|
||||||
assignFileOffsets();
|
assignFileOffsets();
|
||||||
} else {
|
} else {
|
||||||
if (Script->Opt.HasSections) {
|
if (!Script->Opt.HasSections) {
|
||||||
Script->assignAddresses(Phdrs);
|
|
||||||
} else {
|
|
||||||
fixSectionAlignments();
|
fixSectionAlignments();
|
||||||
assignAddresses();
|
Script->fabricateDefaultCommands(Config->MaxPageSize);
|
||||||
Script->processNonSectionCommands();
|
|
||||||
}
|
}
|
||||||
|
Script->assignAddresses(Phdrs);
|
||||||
|
|
||||||
// Remove empty PT_LOAD to avoid causing the dynamic linker to try to mmap a
|
// Remove empty PT_LOAD to avoid causing the dynamic linker to try to mmap a
|
||||||
// 0 sized region. This has to be done late since only after assignAddresses
|
// 0 sized region. This has to be done late since only after assignAddresses
|
||||||
|
@ -1509,37 +1506,6 @@ template <class ELFT> void Writer<ELFT>::fixHeaders() {
|
||||||
AllocateHeader = allocateHeaders(Phdrs, OutputSections, Min);
|
AllocateHeader = allocateHeaders(Phdrs, OutputSections, Min);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assign VAs (addresses at run-time) to output sections.
|
|
||||||
template <class ELFT> void Writer<ELFT>::assignAddresses() {
|
|
||||||
uint64_t VA = Config->ImageBase;
|
|
||||||
uint64_t ThreadBssOffset = 0;
|
|
||||||
|
|
||||||
if (AllocateHeader)
|
|
||||||
VA += getHeaderSize();
|
|
||||||
|
|
||||||
for (OutputSection *Sec : OutputSections) {
|
|
||||||
uint32_t Alignment = Sec->Alignment;
|
|
||||||
if (Sec->PageAlign)
|
|
||||||
Alignment = std::max<uint32_t>(Alignment, Config->MaxPageSize);
|
|
||||||
|
|
||||||
auto I = Config->SectionStartMap.find(Sec->Name);
|
|
||||||
if (I != Config->SectionStartMap.end())
|
|
||||||
VA = I->second;
|
|
||||||
|
|
||||||
// We only assign VAs to allocated sections.
|
|
||||||
if (needsPtLoad(Sec)) {
|
|
||||||
VA = alignTo(VA, Alignment);
|
|
||||||
Sec->Addr = VA;
|
|
||||||
VA += Sec->Size;
|
|
||||||
} else if (Sec->Flags & SHF_TLS && Sec->Type == SHT_NOBITS) {
|
|
||||||
uint64_t TVA = VA + ThreadBssOffset;
|
|
||||||
TVA = alignTo(TVA, Alignment);
|
|
||||||
Sec->Addr = TVA;
|
|
||||||
ThreadBssOffset = TVA - VA + Sec->Size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Adjusts the file alignment for a given output section and returns
|
// Adjusts the file alignment for a given output section and returns
|
||||||
// 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
|
||||||
|
|
|
@ -2,7 +2,17 @@
|
||||||
// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
|
// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
|
||||||
// RUN: ld.lld %t -o %tout
|
// RUN: ld.lld %t -o %tout
|
||||||
// RUN: llvm-readobj -s %tout | FileCheck %s
|
// RUN: llvm-readobj -s %tout | FileCheck %s
|
||||||
|
// RUN: echo "SECTIONS { \
|
||||||
|
// RUN: . = 0x201000; \
|
||||||
|
// RUN: .text : { *(.text) } \
|
||||||
|
// RUN: . = 0x202000; \
|
||||||
|
// RUN: .tdata : { *(.tdata) } \
|
||||||
|
// RUN: .tbss : { *(.tbss) } \
|
||||||
|
// RUN: .data.rel.ro : { *(.data.rel.ro) } \
|
||||||
|
// RUN: }" > %t.script
|
||||||
|
// RUN: ld.lld -T %t.script %t -o %tout2
|
||||||
|
// RUN: echo SCRIPT
|
||||||
|
// RUN: llvm-readobj -s %tout2 | FileCheck %s
|
||||||
.global _start
|
.global _start
|
||||||
_start:
|
_start:
|
||||||
retq
|
retq
|
||||||
|
@ -51,6 +61,6 @@ _start:
|
||||||
// CHECK-NEXT: SHF_ALLOC
|
// CHECK-NEXT: SHF_ALLOC
|
||||||
// CHECK-NEXT: SHF_WRITE
|
// CHECK-NEXT: SHF_WRITE
|
||||||
// CHECK-NEXT: ]
|
// CHECK-NEXT: ]
|
||||||
// CHECK-NEXT: Address: 0x202004
|
// CHECK-NEXT: Address: 0x202010
|
||||||
// CHECK-NEXT: Offset: 0x2004
|
// CHECK-NEXT: Offset: 0x2010
|
||||||
// CHECK-NEXT: Size: 4
|
// CHECK-NEXT: Size: 4
|
||||||
|
|
Loading…
Reference in New Issue