[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;
|
||||
}
|
||||
|
||||
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.
|
||||
void LinkerScript::addOrphanSections(OutputSectionFactory &Factory) {
|
||||
for (InputSectionBase *S : InputSections)
|
||||
|
|
|
@ -256,6 +256,7 @@ public:
|
|||
bool isDefined(StringRef S);
|
||||
|
||||
std::vector<OutputSection *> *OutputSections;
|
||||
void fabricateDefaultCommands(bool AllocateHeader);
|
||||
void addOrphanSections(OutputSectionFactory &Factory);
|
||||
void removeEmptyCommands();
|
||||
void adjustSectionsBeforeSorting();
|
||||
|
|
|
@ -59,7 +59,6 @@ private:
|
|||
std::vector<PhdrEntry> createPhdrs();
|
||||
void removeEmptyPTLoad();
|
||||
void addPtArmExid(std::vector<PhdrEntry> &Phdrs);
|
||||
void assignAddresses();
|
||||
void assignFileOffsets();
|
||||
void assignFileOffsetsBinary();
|
||||
void setPhdrs();
|
||||
|
@ -251,13 +250,11 @@ template <class ELFT> void Writer<ELFT>::run() {
|
|||
if (Config->Relocatable) {
|
||||
assignFileOffsets();
|
||||
} else {
|
||||
if (Script->Opt.HasSections) {
|
||||
Script->assignAddresses(Phdrs);
|
||||
} else {
|
||||
if (!Script->Opt.HasSections) {
|
||||
fixSectionAlignments();
|
||||
assignAddresses();
|
||||
Script->processNonSectionCommands();
|
||||
Script->fabricateDefaultCommands(Config->MaxPageSize);
|
||||
}
|
||||
Script->assignAddresses(Phdrs);
|
||||
|
||||
// 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
|
||||
|
@ -1509,37 +1506,6 @@ template <class ELFT> void Writer<ELFT>::fixHeaders() {
|
|||
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
|
||||
// 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
|
||||
|
|
|
@ -2,7 +2,17 @@
|
|||
// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
|
||||
// RUN: ld.lld %t -o %tout
|
||||
// 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
|
||||
_start:
|
||||
retq
|
||||
|
@ -51,6 +61,6 @@ _start:
|
|||
// CHECK-NEXT: SHF_ALLOC
|
||||
// CHECK-NEXT: SHF_WRITE
|
||||
// CHECK-NEXT: ]
|
||||
// CHECK-NEXT: Address: 0x202004
|
||||
// CHECK-NEXT: Offset: 0x2004
|
||||
// CHECK-NEXT: Address: 0x202010
|
||||
// CHECK-NEXT: Offset: 0x2010
|
||||
// CHECK-NEXT: Size: 4
|
||||
|
|
Loading…
Reference in New Issue