forked from OSchip/llvm-project
				
			[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