diff options
author | Shankar Easwaran <shankare@codeaurora.org> | 2014-11-08 03:44:49 +0000 |
---|---|---|
committer | Shankar Easwaran <shankare@codeaurora.org> | 2014-11-08 03:44:49 +0000 |
commit | 22c76a5d79ad6ceb4bbf46b6b280dfd10483bade (patch) | |
tree | 7d7ab83b247d028e5fd78b01d435d5651824a6c6 | |
parent | 8da0bf3b7cf3670095d7ce9eac885dfc5976720e (diff) | |
download | bcm5719-llvm-22c76a5d79ad6ceb4bbf46b6b280dfd10483bade.tar.gz bcm5719-llvm-22c76a5d79ad6ceb4bbf46b6b280dfd10483bade.zip |
[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
-rw-r--r-- | lld/include/lld/ReaderWriter/ELFLinkingContext.h | 5 | ||||
-rw-r--r-- | lld/lib/Driver/GnuLdDriver.cpp | 4 | ||||
-rw-r--r-- | lld/lib/Driver/GnuLdOptions.td | 3 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/ELF/ELFLinkingContext.cpp | 3 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/ELF/SegmentChunks.h | 33 | ||||
-rw-r--r-- | lld/test/elf/X86_64/noalignsegments.test | 95 | ||||
-rw-r--r-- | lld/test/elf/phdr.test | 2 |
7 files changed, 131 insertions, 14 deletions
diff --git a/lld/include/lld/ReaderWriter/ELFLinkingContext.h b/lld/include/lld/ReaderWriter/ELFLinkingContext.h index 05324aca97d..b7a7ac147c7 100644 --- a/lld/include/lld/ReaderWriter/ELFLinkingContext.h +++ b/lld/include/lld/ReaderWriter/ELFLinkingContext.h @@ -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; diff --git a/lld/lib/Driver/GnuLdDriver.cpp b/lld/lib/Driver/GnuLdDriver.cpp index 542b1bda3f8..fc191584a77 100644 --- a/lld/lib/Driver/GnuLdDriver.cpp +++ b/lld/lib/Driver/GnuLdDriver.cpp @@ -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 diff --git a/lld/lib/Driver/GnuLdOptions.td b/lld/lib/Driver/GnuLdOptions.td index c060fe77677..ca551523fd4 100644 --- a/lld/lib/Driver/GnuLdOptions.td +++ b/lld/lib/Driver/GnuLdOptions.td @@ -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 diff --git a/lld/lib/ReaderWriter/ELF/ELFLinkingContext.cpp b/lld/lib/ReaderWriter/ELF/ELFLinkingContext.cpp index 221a78bfd5c..0eccf64e1a5 100644 --- a/lld/lib/ReaderWriter/ELF/ELFLinkingContext.cpp +++ b/lld/lib/ReaderWriter/ELF/ELFLinkingContext.cpp @@ -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) diff --git a/lld/lib/ReaderWriter/ELF/SegmentChunks.h b/lld/lib/ReaderWriter/ELF/SegmentChunks.h index 017358df921..9524f1bc319 100644 --- a/lld/lib/ReaderWriter/ELF/SegmentChunks.h +++ b/lld/lib/ReaderWriter/ELF/SegmentChunks.h @@ -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 diff --git a/lld/test/elf/X86_64/noalignsegments.test b/lld/test/elf/X86_64/noalignsegments.test new file mode 100644 index 00000000000..8432bda51f0 --- /dev/null +++ b/lld/test/elf/X86_64/noalignsegments.test @@ -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 +... diff --git a/lld/test/elf/phdr.test b/lld/test/elf/phdr.test index 3f626aa1179..ba0165c113d 100644 --- a/lld/test/elf/phdr.test +++ b/lld/test/elf/phdr.test @@ -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 |