forked from OSchip/llvm-project
[ELF] Support --no-align-segments.
lld generates an ELF by adhering to the ELF spec by aligning vma/fileoffset to a page boundary, but this becomes an issue when dealing with large pages. This adds support so that lld generated executables adheres to the ELF spec with the rule vma % p_align = offset % p_align. This is supported by the flag --no-align-segments. This could be the default in few targets like X86_64 to save space on disk. llvm-svn: 221571
This commit is contained in:
parent
8da0bf3b7c
commit
22c76a5d79
|
@ -278,6 +278,10 @@ public:
|
|||
bool demangleSymbols() const { return _demangle; }
|
||||
void setDemangleSymbols(bool d) { _demangle = d; }
|
||||
|
||||
/// \brief Align segments.
|
||||
bool alignSegments() const { return _alignSegments; }
|
||||
void setAlignSegments(bool align) { _alignSegments = align; }
|
||||
|
||||
private:
|
||||
ELFLinkingContext() LLVM_DELETED_FUNCTION;
|
||||
|
||||
|
@ -303,6 +307,7 @@ protected:
|
|||
bool _noAllowDynamicLibraries;
|
||||
bool _mergeRODataToTextSegment;
|
||||
bool _demangle;
|
||||
bool _alignSegments;
|
||||
OutputMagic _outputMagic;
|
||||
StringRefVector _inputSearchPaths;
|
||||
std::unique_ptr<Writer> _writer;
|
||||
|
|
|
@ -555,6 +555,10 @@ bool GnuLdDriver::parse(int argc, const char *argv[],
|
|||
ctx->setCreateSeparateROSegment();
|
||||
break;
|
||||
|
||||
case OPT_no_align_segments:
|
||||
ctx->setAlignSegments(false);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
} // end switch on option ID
|
||||
|
|
|
@ -221,6 +221,9 @@ def rosegment: Flag<["--"], "rosegment">,
|
|||
def z : Separate<["-"], "z">,
|
||||
HelpText<"Linker Option extensions">,
|
||||
Group<grp_customopts>;
|
||||
def no_align_segments: Flag<["--"], "no-align-segments">,
|
||||
HelpText<"Don't align ELF segments(virtualaddress/fileoffset) to page boundaries">,
|
||||
Group<grp_customopts>;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// Symbol options
|
||||
|
|
|
@ -62,7 +62,8 @@ ELFLinkingContext::ELFLinkingContext(
|
|||
_mergeCommonStrings(false), _runLayoutPass(true),
|
||||
_useShlibUndefines(true), _dynamicLinkerArg(false),
|
||||
_noAllowDynamicLibraries(false), _mergeRODataToTextSegment(true),
|
||||
_demangle(true), _outputMagic(OutputMagic::DEFAULT), _sysrootPath("") {}
|
||||
_demangle(true), _alignSegments(true), _outputMagic(OutputMagic::DEFAULT),
|
||||
_sysrootPath("") {}
|
||||
|
||||
void ELFLinkingContext::addPasses(PassManager &pm) {
|
||||
if (_runLayoutPass)
|
||||
|
|
|
@ -399,14 +399,12 @@ void Segment<ELFT>::assignFileOffsets(uint64_t startOffset) {
|
|||
uint64_t fileOffset = startOffset;
|
||||
uint64_t curSliceFileOffset = fileOffset;
|
||||
bool isDataPageAlignedForNMagic = false;
|
||||
bool alignSegments = this->_context.alignSegments();
|
||||
uint64_t p_align = this->_context.getPageSize();
|
||||
|
||||
this->setFileOffset(startOffset);
|
||||
for (auto &slice : slices()) {
|
||||
// Align to the slice alignment
|
||||
fileOffset = llvm::RoundUpToAlignment(fileOffset, slice->align2());
|
||||
|
||||
bool isFirstSection = true;
|
||||
|
||||
for (auto section : slice->sections()) {
|
||||
// If the linker outputmagic is set to OutputMagic::NMAGIC, align the Data
|
||||
// to a page boundary
|
||||
|
@ -415,16 +413,25 @@ void Segment<ELFT>::assignFileOffsets(uint64_t startOffset) {
|
|||
_outputMagic != ELFLinkingContext::OutputMagic::OMAGIC) {
|
||||
// Align to a page only if the output is not
|
||||
// OutputMagic::NMAGIC/OutputMagic::OMAGIC
|
||||
fileOffset =
|
||||
llvm::RoundUpToAlignment(fileOffset, this->_context.getPageSize());
|
||||
}
|
||||
if (!isDataPageAlignedForNMagic && needAlign(section)) {
|
||||
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 padding = 0;
|
||||
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);
|
||||
}
|
||||
} else if (!isDataPageAlignedForNMagic && needAlign(section)) {
|
||||
fileOffset =
|
||||
llvm::RoundUpToAlignment(fileOffset, this->_context.getPageSize());
|
||||
isDataPageAlignedForNMagic = true;
|
||||
}
|
||||
// Align the section address
|
||||
fileOffset = llvm::RoundUpToAlignment(fileOffset, section->align2());
|
||||
} else
|
||||
fileOffset = llvm::RoundUpToAlignment(fileOffset, section->align2());
|
||||
|
||||
if (isFirstSection) {
|
||||
slice->setFileOffset(fileOffset);
|
||||
|
@ -460,6 +467,7 @@ template <class ELFT> void Segment<ELFT>::assignVirtualAddress(uint64_t addr) {
|
|||
uint64_t startAddr = addr;
|
||||
SegmentSlice<ELFT> *slice = nullptr;
|
||||
uint64_t tlsStartAddr = 0;
|
||||
bool alignSegments = this->_context.alignSegments();
|
||||
|
||||
for (auto si = _sections.begin(); si != _sections.end(); ++si) {
|
||||
// If this is first section in the segment, page align the section start
|
||||
|
@ -467,7 +475,8 @@ template <class ELFT> void Segment<ELFT>::assignVirtualAddress(uint64_t addr) {
|
|||
// only if NMAGIC is set.
|
||||
if (isFirstSection) {
|
||||
isFirstSection = false;
|
||||
if (_outputMagic != ELFLinkingContext::OutputMagic::NMAGIC &&
|
||||
if (alignSegments &&
|
||||
_outputMagic != ELFLinkingContext::OutputMagic::NMAGIC &&
|
||||
_outputMagic != ELFLinkingContext::OutputMagic::OMAGIC)
|
||||
// Align to a page only if the output is not
|
||||
// OutputMagic::NMAGIC/OutputMagic::OMAGIC
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
# Checks that segments are aligned as per ELF spec than aligning each
|
||||
# segment fileoffset / virtual address to a page.
|
||||
|
||||
# Build executable
|
||||
# RUN: yaml2obj -format=elf -docnum 1 %s -o %t.o
|
||||
# RUN: lld -flavor gnu -target x86_64 %t.o -o %t.exe -static \
|
||||
# RUN: --no-align-segments --noinhibit-exec
|
||||
# RUN: llvm-readobj -program-headers %t.exe | FileCheck %s
|
||||
#
|
||||
#CHECK: VirtualAddress: 0x400000
|
||||
#CHECK: PhysicalAddress: 0x400000
|
||||
#CHECK: VirtualAddress: 0x400178
|
||||
#CHECK: PhysicalAddress: 0x400178
|
||||
|
||||
# object
|
||||
---
|
||||
FileHeader:
|
||||
Class: ELFCLASS64
|
||||
Data: ELFDATA2LSB
|
||||
OSABI: ELFOSABI_GNU
|
||||
Type: ET_REL
|
||||
Machine: EM_X86_64
|
||||
Sections:
|
||||
- Name: .text
|
||||
Type: SHT_PROGBITS
|
||||
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
|
||||
AddressAlign: 0x0000000000000010
|
||||
Content: 554889E5B864000000C745FC000000005DC366666666662E0F1F840000000000554889E531C05DC3
|
||||
- Name: .data
|
||||
Type: SHT_PROGBITS
|
||||
Flags: [ SHF_WRITE, SHF_ALLOC ]
|
||||
AddressAlign: 0x0000000000000004
|
||||
Content: ''
|
||||
- Name: .bss
|
||||
Type: SHT_NOBITS
|
||||
Flags: [ SHF_WRITE, SHF_ALLOC ]
|
||||
AddressAlign: 0x0000000000000004
|
||||
Content: '64000000'
|
||||
- Name: .rodata
|
||||
Type: SHT_PROGBITS
|
||||
Flags: [ SHF_ALLOC ]
|
||||
AddressAlign: 0x0000000000000004
|
||||
Content: '64000000'
|
||||
- Name: .eh_frame
|
||||
Type: SHT_PROGBITS
|
||||
Flags: [ SHF_ALLOC ]
|
||||
AddressAlign: 0x0000000000000008
|
||||
Content: 1400000000000000037A5200017810011B0C070890010000180000001C000000000000001200000000410E108602430D060000001800000038000000000000000800000000410E108602430D06000000
|
||||
- Name: .rela.eh_frame
|
||||
Type: SHT_RELA
|
||||
Link: .symtab
|
||||
AddressAlign: 0x0000000000000008
|
||||
Info: .eh_frame
|
||||
Relocations:
|
||||
- Offset: 0x0000000000000020
|
||||
Symbol: .text
|
||||
Type: R_X86_64_PC32
|
||||
Addend: 0
|
||||
- Offset: 0x000000000000003C
|
||||
Symbol: .text
|
||||
Type: R_X86_64_PC32
|
||||
Addend: 32
|
||||
Symbols:
|
||||
Local:
|
||||
- Name: .text
|
||||
Type: STT_SECTION
|
||||
Section: .text
|
||||
- Name: .data
|
||||
Type: STT_SECTION
|
||||
Section: .data
|
||||
- Name: .bss
|
||||
Type: STT_SECTION
|
||||
Section: .bss
|
||||
- Name: .eh_frame
|
||||
Type: STT_SECTION
|
||||
Section: .eh_frame
|
||||
Global:
|
||||
- Name: foo
|
||||
Type: STT_FUNC
|
||||
Section: .text
|
||||
Value: 0x0000000000000020
|
||||
Size: 0x0000000000000008
|
||||
- Name: main
|
||||
Type: STT_FUNC
|
||||
Section: .text
|
||||
Size: 0x0000000000000012
|
||||
- Name: myval
|
||||
Type: STT_OBJECT
|
||||
Section: .bss
|
||||
Size: 0x0000000000000004
|
||||
- Name: val
|
||||
Type: STT_OBJECT
|
||||
Section: .rodata
|
||||
Size: 0x0000000000000004
|
||||
...
|
|
@ -59,7 +59,7 @@ I386-NEXT: Alignment: 4096
|
|||
I386-NEXT: }
|
||||
I386-NEXT: ProgramHeader {
|
||||
I386-NEXT: Type: PT_LOAD (0x1)
|
||||
I386-NEXT: Offset: 0x4000
|
||||
I386-NEXT: Offset: 0x2000
|
||||
I386-NEXT: VirtualAddress: 0x4000
|
||||
I386-NEXT: PhysicalAddress: 0x4000
|
||||
I386-NEXT: FileSize: 4
|
||||
|
|
Loading…
Reference in New Issue