[lld] r242096 - [LinkerScript] Don't create unnecessarily large segments
Rafael Auler
rafaelauler at gmail.com
Mon Jul 13 17:34:43 PDT 2015
Author: rafauler
Date: Mon Jul 13 19:34:43 2015
New Revision: 242096
URL: http://llvm.org/viewvc/llvm-project?rev=242096&view=rev
Log:
[LinkerScript] Don't create unnecessarily large segments
When using a linker script expression to change the address of a section, even
if the new address is more than a page of distance from the old address, lld
may put everything in the same segment, forcing it to be unnecessarily large.
This patch changes the logic in Segment::assignVirtualAddress() and
Segment::assignFileOffsets() to allow the segment to be sliced into two or more
if it detects a linker script expression that changes a section address.
Differential Revision: http://reviews.llvm.org/D10952
Modified:
lld/trunk/lib/ReaderWriter/ELF/SegmentChunks.cpp
lld/trunk/test/elf/linkerscript/sections-order.test
Modified: lld/trunk/lib/ReaderWriter/ELF/SegmentChunks.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/SegmentChunks.cpp?rev=242096&r1=242095&r2=242096&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/SegmentChunks.cpp (original)
+++ lld/trunk/lib/ReaderWriter/ELF/SegmentChunks.cpp Mon Jul 13 19:34:43 2015
@@ -118,13 +118,23 @@ void Segment<ELFT>::assignFileOffsets(ui
uint64_t lastVirtualAddress = 0;
this->setFileOffset(startOffset);
+ bool changeOffset = false;
+ uint64_t newOffset = 0;
for (auto &slice : slices()) {
bool isFirstSection = true;
for (auto section : slice->sections()) {
// Handle linker script expressions, which may change the offset
- if (!isFirstSection)
- if (auto expr = dyn_cast<ExpressionChunk<ELFT>>(section))
- fileOffset += expr->virtualAddr() - lastVirtualAddress;
+ if (auto expr = dyn_cast<ExpressionChunk<ELFT>>(section)) {
+ if (!isFirstSection) {
+ changeOffset = true;
+ newOffset = fileOffset + expr->virtualAddr() - lastVirtualAddress;
+ }
+ continue;
+ }
+ if (changeOffset) {
+ changeOffset = false;
+ fileOffset = newOffset;
+ }
// Align fileoffset to the alignment of the section.
fileOffset = llvm::RoundUpToAlignment(fileOffset, section->alignment());
// If the linker outputmagic is set to OutputMagic::NMAGIC, align the Data
@@ -136,17 +146,14 @@ void Segment<ELFT>::assignFileOffsets(ui
// OutputMagic::NMAGIC/OutputMagic::OMAGIC
if (alignSegments)
fileOffset = llvm::RoundUpToAlignment(fileOffset, p_align);
- else {
- // Align according to ELF spec.
- // in p75, http://www.sco.com/developers/devspecs/gabi41.pdf
- uint64_t virtualAddress = slice->virtualAddr();
- Section<ELFT> *sect = dyn_cast<Section<ELFT>>(section);
- if (sect && sect->isLoadableSection() &&
- ((virtualAddress & (p_align - 1)) !=
- (fileOffset & (p_align - 1))))
- fileOffset = llvm::RoundUpToAlignment(fileOffset, p_align) +
- (virtualAddress % p_align);
- }
+ // Align according to ELF spec.
+ // in p75, http://www.sco.com/developers/devspecs/gabi41.pdf
+ uint64_t virtualAddress = slice->virtualAddr();
+ Section<ELFT> *sect = dyn_cast<Section<ELFT>>(section);
+ if (sect && sect->isLoadableSection() &&
+ ((virtualAddress & (p_align - 1)) != (fileOffset & (p_align - 1))))
+ fileOffset = llvm::RoundUpToAlignment(fileOffset, p_align) +
+ (virtualAddress % p_align);
} else if (!isDataPageAlignedForNMagic && needAlign(section)) {
fileOffset =
llvm::RoundUpToAlignment(fileOffset, this->_ctx.getPageSize());
@@ -161,6 +168,7 @@ void Segment<ELFT>::assignFileOffsets(ui
fileOffset += section->fileSize();
lastVirtualAddress = section->virtualAddr() + section->memSize();
}
+ changeOffset = false;
slice->setFileSize(fileOffset - curSliceFileOffset);
}
this->setFileSize(fileOffset - startOffset);
@@ -242,6 +250,8 @@ template <class ELFT> void Segment<ELFT>
++si;
}
+ uint64_t scriptAddr = 0;
+ bool forceScriptAddr = false;
for (auto e = _sections.end(); si != e; ++si) {
uint64_t curAddr = curSliceAddress + curSliceSize;
if (!isDataPageAlignedForNMagic && needAlign(*si)) {
@@ -251,23 +261,25 @@ template <class ELFT> void Segment<ELFT>
curAddr = llvm::RoundUpToAlignment(curAddr, this->_ctx.getPageSize());
isDataPageAlignedForNMagic = true;
}
- uint64_t newAddr = llvm::RoundUpToAlignment(curAddr, (*si)->alignment());
- // Handle linker script expressions, which *may update newAddr* if the
- // expression assigns to "."
- if (auto expr = dyn_cast<ExpressionChunk<ELFT>>(*si))
+ uint64_t newAddr = llvm::RoundUpToAlignment(
+ forceScriptAddr ? scriptAddr : curAddr, (*si)->alignment());
+ forceScriptAddr = false;
+
+ // Handle linker script expressions, which may force an address change if
+ // the expression assigns to "."
+ if (auto expr = dyn_cast<ExpressionChunk<ELFT>>(*si)) {
+ uint64_t oldAddr = newAddr;
expr->evalExpr(newAddr);
- Section<ELFT> *sec = dyn_cast<Section<ELFT>>(*si);
- StringRef curOutputSectionName;
- if (sec) {
- curOutputSectionName = sec->outputSectionName();
- } else {
- // If this is a linker script expression, propagate the name of the
- // previous section instead
- if (isa<ExpressionChunk<ELFT>>(*si))
- curOutputSectionName = prevOutputSectionName;
- else
- curOutputSectionName = (*si)->name();
+ if (oldAddr != newAddr) {
+ forceScriptAddr = true;
+ scriptAddr = newAddr;
+ }
+ (*si)->setVirtualAddr(newAddr);
+ continue;
}
+ Section<ELFT> *sec = dyn_cast<Section<ELFT>>(*si);
+ StringRef curOutputSectionName =
+ sec ? sec->outputSectionName() : (*si)->name();
bool autoCreateSlice = true;
if (curOutputSectionName == prevOutputSectionName)
autoCreateSlice = false;
Modified: lld/trunk/test/elf/linkerscript/sections-order.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/linkerscript/sections-order.test?rev=242096&r1=242095&r2=242096&view=diff
==============================================================================
--- lld/trunk/test/elf/linkerscript/sections-order.test (original)
+++ lld/trunk/test/elf/linkerscript/sections-order.test Mon Jul 13 19:34:43 2015
@@ -94,4 +94,20 @@ CHECKSYMS-NEXT: Value: 0x506038
CHECKSYMS: Name: prog2
CHECKSYMS-NEXT: Value: 0x506050
+
+RUN: llvm-readobj -program-headers %t1 | FileCheck -check-prefix CHECKPHDRS %s
+
+CHECKPHDRS: Type: PT_LOAD (0x1)
+CHECKPHDRS: Offset: 0x1000
+CHECKPHDRS-NEXT: VirtualAddress: 0x500000
+CHECKPHDRS-NEXT: PhysicalAddress: 0x500000
+CHECKPHDRS-NEXT: FileSize: 48
+CHECKPHDRS-NEXT: MemSize: 48
+
+CHECKPHDRS: Type: PT_LOAD (0x1)
+CHECKPHDRS: Offset: 0x2030
+CHECKPHDRS-NEXT: VirtualAddress: 0x506030
+CHECKPHDRS-NEXT: PhysicalAddress: 0x506030
+CHECKPHDRS-NEXT: FileSize: 168
+CHECKPHDRS-NEXT: MemSize: 168
*/
More information about the llvm-commits
mailing list