[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:
Peter Smith 2017-04-19 12:46:32 +00:00
parent cb89513bc7
commit cbfe9e946f
4 changed files with 67 additions and 40 deletions

View File

@ -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)

View File

@ -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();

View File

@ -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

View File

@ -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