Index: ELF/Config.h =================================================================== --- ELF/Config.h +++ ELF/Config.h @@ -67,6 +67,7 @@ bool NoInhibitExec; bool NoUndefined; bool PrintGcSections; + bool Relocatable; bool Shared; bool Static = false; bool StripAll; Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -111,6 +111,10 @@ Files.push_back(make_unique(MBRef)); return; case file_magic::elf_shared_object: + if (Config->Relocatable) { + error("Attempted static link of dynamic object " + Path); + return; + } Files.push_back(createSharedFile(MBRef)); return; case sys::fs::file_magic::bitcode: @@ -133,12 +137,6 @@ // Some command line options or some combinations of them are not allowed. // This function checks for such errors. static void checkOptions(opt::InputArgList &Args) { - // Traditional linkers can generate re-linkable object files instead - // of executables or DSOs. We don't support that since the feature - // does not seem to provide more value than the static archiver. - if (Args.hasArg(OPT_relocatable)) - error("-r option is not supported. Use 'ar' command instead."); - // The MIPS ABI as of 2016 does not support the GNU-style symbol lookup // table which is a relatively new feature. if (Config->EMachine == EM_MIPS && Config->GnuHash) @@ -146,6 +144,9 @@ if (Config->EMachine == EM_AMDGPU && !Config->Entry.empty()) error("-e option is not valid for AMDGPU."); + + if (Config->Relocatable && Config->Shared) + error("-r and -shared may not be used together"); } static StringRef @@ -222,6 +223,7 @@ Config->NoInhibitExec = Args.hasArg(OPT_noinhibit_exec); Config->NoUndefined = Args.hasArg(OPT_no_undefined); Config->PrintGcSections = Args.hasArg(OPT_print_gc_sections); + Config->Relocatable = Args.hasArg(OPT_relocatable); Config->Shared = Args.hasArg(OPT_shared); Config->StripAll = Args.hasArg(OPT_strip_all); Config->Verbose = Args.hasArg(OPT_verbose); @@ -240,6 +242,11 @@ Config->ZOrigin = hasZOption(Args, "origin"); Config->ZRelro = !hasZOption(Args, "norelro"); + if (Config->Relocatable) { + Config->StripAll = false; + Config->Static = true; + } + if (auto *Arg = Args.getLastArg(OPT_O)) { StringRef Val = Arg->getValue(); if (Val.getAsInteger(10, Config->Optimize)) @@ -306,7 +313,7 @@ std::unique_ptr TI(createTarget()); Target = TI.get(); - if (!Config->Shared) { + if (!Config->Shared && !Config->Relocatable) { // Add entry symbol. // // There is no entry symbol for AMDGPU binaries, so skip adding one to avoid Index: ELF/InputFiles.cpp =================================================================== --- ELF/InputFiles.cpp +++ ELF/InputFiles.cpp @@ -226,7 +226,14 @@ continue; if (!RelocatedSection) fatal("Unsupported relocation reference"); - if (auto *S = dyn_cast>(RelocatedSection)) { + if (Config->Relocatable) { + // If relocatable output is chosen, relocation sections are handled as + // regular input sections, as no relocations are applied during link. + InputSection *S = new (Alloc) InputSection( + this, &Sec, InputSectionBase::RelInputSection); + S->RelocatingSection = RelocatedSection; + Sections[I] = S; + } else if (auto *S = dyn_cast>(RelocatedSection)) { S->RelocSections.push_back(&Sec); } else if (auto *S = dyn_cast>(RelocatedSection)) { if (S->RelocSection) @@ -268,7 +275,8 @@ return new (EHAlloc.Allocate()) EHInputSection(this, &Sec); if (shouldMerge(Sec)) return new (MAlloc.Allocate()) MergeInputSection(this, &Sec); - return new (Alloc) InputSection(this, &Sec); + return new (Alloc) + InputSection(this, &Sec, InputSectionBase::Regular); } template void elf2::ObjectFile::initializeSymbols() { Index: ELF/InputSection.h =================================================================== --- ELF/InputSection.h +++ ELF/InputSection.h @@ -36,7 +36,7 @@ ObjectFile *File; public: - enum Kind { Regular, EHFrame, Merge, MipsReginfo }; + enum Kind { Regular, RelInputSection, EHFrame, Merge, MipsReginfo }; Kind SectionKind; InputSectionBase(ObjectFile *File, const Elf_Shdr *Header, @@ -83,6 +83,17 @@ template void relocate(uint8_t *Buf, uint8_t *BufEnd, RelIteratorRange Rels); + template + void copyRelocations(uint8_t *Buf, RelIteratorRange Rels); + + // If -r (or --relocatable) option is given, this member may have a non-null + // value. During partial linking, we do not apply any relocations but just + // leave them as is, expecting the final static linking applies them all at + // once. In that case, relocation sections are handled as regular input + // sections, and their RelocatingSection pointers point to their target + // sections. + InputSectionBase *RelocatingSection = nullptr; + private: template uint8_t *findMipsPairedReloc(uint8_t *Buf, uint32_t SymIndex, uint32_t Type, @@ -152,9 +163,10 @@ typedef typename llvm::object::ELFFile::Elf_Rel Elf_Rel; typedef typename llvm::object::ELFFile::Elf_Sym Elf_Sym; typedef typename llvm::object::ELFFile::uintX_t uintX_t; + typedef typename Base::Kind Kind; public: - InputSection(ObjectFile *F, const Elf_Shdr *Header); + InputSection(ObjectFile *F, const Elf_Shdr *Header, Kind K); // Write this section to a mmap'ed file, assuming Buf is pointing to // beginning of the output section. Index: ELF/InputSection.cpp =================================================================== --- ELF/InputSection.cpp +++ ELF/InputSection.cpp @@ -46,6 +46,7 @@ InputSectionBase::getOffset(uintX_t Offset) { switch (SectionKind) { case Regular: + case RelInputSection: return cast>(this)->OutSecOff + Offset; case EHFrame: return cast>(this)->getOffset(Offset); @@ -88,12 +89,46 @@ } template -InputSection::InputSection(ObjectFile *F, const Elf_Shdr *Header) - : InputSectionBase(F, Header, Base::Regular) {} +InputSection::InputSection(ObjectFile *F, const Elf_Shdr *H, Kind K) + : InputSectionBase(F, H, K) {} template bool InputSection::classof(const InputSectionBase *S) { - return S->SectionKind == Base::Regular; + return S->SectionKind == Base::Regular || + S->SectionKind == Base::RelInputSection; +} + +// This function copies section contents to Buf, assuming that the current +// section contains relocations. Usually this function is not called because we +// apply and consume relocation ourselves as a static linker. However, if -r is +// specified, we are a producer of an object file, so instead of applying, we +// copy all relocations to a resulting object file and let the final static +// linker resolve all relocations. We can't use memcpy to copy relocations +// because we need to update symbol table offset and section index for each +// relocation. So we copy relocations one by one. +template +template +void InputSectionBase::copyRelocations(uint8_t *Buf, + RelIteratorRange Rels) { + typedef Elf_Rel_Impl RelType; + for (const RelType &Rel : Rels) { + uint32_t SymIndex = Rel.getSymbol(Config->Mips64EL); + uint32_t Type = Rel.getType(Config->Mips64EL); + const Elf_Shdr *SymTab = File->getSymbolTable(); + + RelType *P = reinterpret_cast(Buf); + Buf += sizeof(RelType); + + // Relocation for local symbol here means that it is probably + // rel[a].eh_frame section which has references to + // sections in r_info field. Also needs fix for addend. + if (SymIndex < SymTab->sh_info) + fatal("Relocation against local symbols is not supported yet"); + + SymbolBody *Body = File->getSymbolBody(SymIndex)->repl(); + P->r_offset = RelocatingSection->getOffset(Rel.r_offset); + P->setSymbolAndType(Body->DynsymIndex, Type, Config->Mips64EL); + } } template @@ -248,10 +283,23 @@ return; // Copy section contents from source object file to output file. ArrayRef Data = this->getSectionData(); - memcpy(Buf + OutSecOff, Data.data(), Data.size()); - ELFFile &EObj = this->File->getObj(); uint8_t *BufEnd = Buf + OutSecOff + Data.size(); + + // If it is SHT_REL[A] section then RelocatingSection may be available. + // That happens if relocatable output was choosen. In that case we should fix + // the symbol indices within symtab table, fix addends in some cases and also + // other possible data. No relocations are applied. + if (this->RelocatingSection) { + if (this->Header->sh_type == SHT_RELA) + this->copyRelocations(Buf + OutSecOff, EObj.relas(this->Header)); + else + this->copyRelocations(Buf + OutSecOff, EObj.rels(this->Header)); + return; + } + + memcpy(Buf + OutSecOff, Data.data(), Data.size()); + // Iterate over all relocation sections that apply to this section. for (const Elf_Shdr *RelSec : this->RelocSections) { if (RelSec->sh_type == SHT_RELA) Index: ELF/Options.td =================================================================== --- ELF/Options.td +++ ELF/Options.td @@ -94,7 +94,8 @@ def rpath : Separate<["-"], "rpath">, HelpText<"Add a DT_RUNPATH to the output">; -def relocatable : Flag<["--"], "relocatable">; +def relocatable : Flag<["--"], "relocatable">, + HelpText<"Create relocatable object file">; def script : Separate<["--"], "script">, HelpText<"Read linker script">; Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -293,6 +293,28 @@ std::vector *> Sections; }; +// This section contains input relocation sections so that they are copied +// to the output. Used only when -r is specified (-r lets the linker do partial +// linking, which combines multiple .o files into single .o file). +// Normally, we don't need this class because we interpret and consume +// relocations ourselves instead of copying. +template +class StaticRelocSection final : public OutputSectionBase { +public: + typedef typename llvm::object::ELFFile::Elf_Rel Elf_Rel; + typedef typename llvm::object::ELFFile::Elf_Rela Elf_Rela; + typedef typename llvm::object::ELFFile::uintX_t uintX_t; + StaticRelocSection(StringRef Name, uint32_t Type, uintX_t Flags, bool IsRela); + void addSection(InputSectionBase *S) override; + void finalize() override; + void writeTo(uint8_t *Buf) override; + +private: + // The output section to which relocation would be applied. + OutputSectionBase *RelocOutSec = nullptr; + std::vector *> Sections; +}; + template class MergeOutputSection final : public OutputSectionBase { typedef typename OutputSectionBase::uintX_t uintX_t; Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -747,6 +747,47 @@ this->Header.sh_size = Off; } +template +StaticRelocSection::StaticRelocSection(StringRef Name, uint32_t Type, + uintX_t Flags, bool IsRela) + : OutputSectionBase(Name, Type, Flags) { + this->Header.sh_addralign = sizeof(uintX_t); + this->Header.sh_entsize = IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel); +} + +template +void StaticRelocSection::addSection(InputSectionBase *Sec) { + if (!RelocOutSec) + RelocOutSec = Sec->RelocatingSection->OutSec; + else if (RelocOutSec != Sec->RelocatingSection->OutSec) + error("Sections to which the relocations applies doesn`t match"); + + auto *S = cast>(Sec); + Sections.push_back(S); + S->OutSec = this; + uint32_t Align = S->getAlign(); + if (Align > this->Header.sh_addralign) + this->Header.sh_addralign = Align; + + uintX_t Off = this->Header.sh_size; + Off = alignTo(Off, Align); + S->OutSecOff = Off; + Off += S->getSize(); + this->Header.sh_size = Off; +} + +template void StaticRelocSection::writeTo(uint8_t *Buf) { + for (InputSection *S : Sections) + S->writeTo(Buf); +} + +template void StaticRelocSection::finalize() { + this->Header.sh_link = Out::SymTab->SectionIndex; + // sh_info for SHT_REL[A] sections should contain the section header index of + // the section to which the relocation applies. + this->Header.sh_info = RelocOutSec->SectionIndex; +} + // If an input string is in the form of "foo.N" where N is a number, // return N. Otherwise, returns 65536, which is one greater than the // lowest priority. @@ -1369,6 +1410,13 @@ this->Header.sh_link = StrTabSec.SectionIndex; this->Header.sh_info = NumLocals + 1; + if (Config->Relocatable) { + size_t I = NumLocals; + for (const std::pair &P : Symbols) + P.first->DynsymIndex = ++I; + return; + } + if (!StrTabSec.isDynamic()) { std::stable_sort(Symbols.begin(), Symbols.end(), [](const std::pair &L, @@ -1598,6 +1646,11 @@ template class OutputSection; template class OutputSection; +template class StaticRelocSection; +template class StaticRelocSection; +template class StaticRelocSection; +template class StaticRelocSection; + template class EHOutputSection; template class EHOutputSection; template class EHOutputSection; Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -69,6 +69,7 @@ void scanRelocs(InputSectionBase &S, const Elf_Shdr &RelSec); void createPhdrs(); void assignAddresses(); + void assignAddressesRelocatable(); void fixAbsoluteSymbols(); bool openFile(); void writeHeader(); @@ -93,13 +94,15 @@ std::vector>> OwningSections; // We create a section for the ELF header and one for the program headers. - const unsigned NumDummySections = 2; ArrayRef *> getSections() const { - return makeArrayRef(OutputSections).slice(NumDummySections); + return makeArrayRef(OutputSections).slice(dummySectionsNum()); } unsigned getNumSections() const { - return OutputSections.size() + 1 - NumDummySections; + return OutputSections.size() + 1 - dummySectionsNum(); } + // Usually there are 2 dummies sections: ELF header and program header. + // Relocatable output does not require program headers to be created. + unsigned dummySectionsNum() const { return Config->Relocatable ? 1 : 2; } void addRelIpltSymbols(); void addStartEndSymbols(); @@ -193,8 +196,12 @@ addReservedSymbols(); if (!createSections()) return; - createPhdrs(); - assignAddresses(); + if (!Config->Relocatable) { + createPhdrs(); + assignAddresses(); + } else { + assignAddressesRelocatable(); + } fixAbsoluteSymbols(); if (!openFile()) return; @@ -495,7 +502,7 @@ template static void reportUndefined(SymbolTable &Symtab, SymbolBody *Sym) { - if (Config->Shared && !Config->NoUndefined) + if ((Config->Relocatable || Config->Shared) && !Config->NoUndefined) return; std::string Msg = "undefined symbol: " + Sym->getName().str(); @@ -837,6 +844,10 @@ case InputSectionBase::Regular: Sec = new OutputSection(Key.Name, Key.Type, Key.Flags); break; + case InputSectionBase::RelInputSection: + Sec = new StaticRelocSection(Key.Name, Key.Type, Key.Flags, + shouldUseRela()); + break; case InputSectionBase::EHFrame: Sec = new EHOutputSection(Key.Name, Key.Type, Key.Flags); break; @@ -928,7 +939,8 @@ // Create output section objects and add them to OutputSections. template bool Writer::createSections() { OutputSections.push_back(Out::ElfHeader); - OutputSections.push_back(Out::ProgramHeaders); + if (!Config->Relocatable) + OutputSections.push_back(Out::ProgramHeaders); // Add .interp first because some loaders want to see that section // on the first page of the executable file when loaded into memory. @@ -1040,8 +1052,8 @@ std::stable_sort(OutputSections.begin(), OutputSections.end(), compareSections); - for (unsigned I = NumDummySections, N = OutputSections.size(); I < N; ++I) - OutputSections[I]->SectionIndex = I + 1 - NumDummySections; + for (unsigned I = dummySectionsNum(), N = OutputSections.size(); I < N; ++I) + OutputSections[I]->SectionIndex = I + 1 - dummySectionsNum(); for (OutputSectionBase *Sec : getSections()) Sec->setSHName(Out::ShStrTab->addString(Sec->getName())); @@ -1304,6 +1316,21 @@ AddHdr(PT_GNU_STACK, PF_R | PF_W); } +// Used for relocatable output (-r). In this case we create only ELF file +// header, do not create program headers. Also assign of section addresses +// is very straightforward: we just put all sections sequentually to the file. +template void Writer::assignAddressesRelocatable() { + Out::ElfHeader->setSize(sizeof(Elf_Ehdr)); + uintX_t FileOff = 0; + for (OutputSectionBase *Sec : OutputSections) { + FileOff = alignTo(FileOff, Sec->getAlign()); + Sec->setFileOffset(FileOff); + FileOff += Sec->getSize(); + } + SectionHeaderOff = alignTo(FileOff, sizeof(uintX_t)); + FileSize = SectionHeaderOff + getNumSections() * sizeof(Elf_Shdr); +} + // Visits all headers in PhdrTable and assigns the adresses to // the output sections. Also creates common and special headers. template void Writer::assignAddresses() { @@ -1444,20 +1471,29 @@ auto &FirstObj = cast>(*Config->FirstElf); EHdr->e_ident[EI_OSABI] = FirstObj.getOSABI(); - EHdr->e_type = Config->Shared ? ET_DYN : ET_EXEC; + if (Config->Shared) + EHdr->e_type = ET_DYN; + else if (Config->Relocatable) + EHdr->e_type = ET_REL; + else + EHdr->e_type = ET_EXEC; + EHdr->e_machine = FirstObj.getEMachine(); EHdr->e_version = EV_CURRENT; EHdr->e_entry = getEntryAddr(); - EHdr->e_phoff = sizeof(Elf_Ehdr); EHdr->e_shoff = SectionHeaderOff; EHdr->e_flags = getELFFlags(); EHdr->e_ehsize = sizeof(Elf_Ehdr); - EHdr->e_phentsize = sizeof(Elf_Phdr); EHdr->e_phnum = Phdrs.size(); EHdr->e_shentsize = sizeof(Elf_Shdr); EHdr->e_shnum = getNumSections(); EHdr->e_shstrndx = Out::ShStrTab->SectionIndex; + if (!Config->Relocatable) { + EHdr->e_phoff = sizeof(Elf_Ehdr); + EHdr->e_phentsize = sizeof(Elf_Phdr); + } + // Write the program header table. auto *HBuf = reinterpret_cast(Buf + EHdr->e_phoff); for (Phdr &P : Phdrs) Index: test/ELF/Inputs/relocatable.s =================================================================== --- test/ELF/Inputs/relocatable.s +++ test/ELF/Inputs/relocatable.s @@ -0,0 +1,22 @@ +.text +.type xx,@object +.bss +.globl xx +.align 4 +xx: +.long 0 +.size xx, 4 +.type yy,@object +.globl yy +.align 4 +yy: +.long 0 +.size yy, 4 + +.text +.globl foo +.align 16, 0x90 +.type foo,@function +foo: +movl $1, xx +movl $2, yy Index: test/ELF/Inputs/relocatable2.s =================================================================== --- test/ELF/Inputs/relocatable2.s +++ test/ELF/Inputs/relocatable2.s @@ -0,0 +1,22 @@ +.text +.type xxx,@object +.bss +.globl xxx +.align 4 +xxx: +.long 0 +.size xxx, 4 +.type yyy,@object +.globl yyy +.align 4 +yyy: +.long 0 +.size yyy, 4 + +.text +.globl bar +.align 16, 0x90 +.type bar,@function +bar: +movl $8, xxx +movl $9, yyy Index: test/ELF/relocatable.s =================================================================== --- test/ELF/relocatable.s +++ test/ELF/relocatable.s @@ -1,9 +1,129 @@ # REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/relocatable.s -o %t2.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/relocatable2.s -o %t3.o +# RUN: ld.lld -r %t1.o %t2.o %t3.o -o %t +# RUN: llvm-readobj -file-headers -sections -program-headers -symbols -r %t | FileCheck %s +# RUN: llvm-objdump -s -d %t | FileCheck -check-prefix=CHECKTEXT %s -# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t -# RUN: not ld.lld -r %t -o %t2 2>&1 | FileCheck %s +## Test --relocatable alias +# RUN: ld.lld --relocatable %t1.o %t2.o %t3.o -o %t +# RUN: llvm-readobj -file-headers -sections -program-headers -symbols -r %t | FileCheck %s +# RUN: llvm-objdump -s -d %t | FileCheck -check-prefix=CHECKTEXT %s -# CHECK: -r option is not supported. Use 'ar' command instead. +## Verify that we can use our relocation output as input to produce executable +# RUN: ld.lld -e main %t -o %texec +# RUN: llvm-readobj -file-headers %texec | FileCheck -check-prefix=CHECKEXE %s -.globl _start; -_start: +## Attempt to link DSO with -r +# RUN: ld.lld -shared %t1.o -o %t.so +# RUN: not ld.lld -r %t.so %t2.o -o %tfail 2>&1 | FileCheck -check-prefix=ERR %s +# ERR: Attempted static link of dynamic object + +## Attempt to use -r and shared together +# RUN: not ld.lld -r -shared %t2.o -o %tfail 2>&1 | FileCheck -check-prefix=ERR2 %s +# ERR2: -r and -shared may not be used together + +# CHECK: ElfHeader { +# CHECK-NEXT: Ident { +# CHECK-NEXT: Magic: (7F 45 4C 46) +# CHECK-NEXT: Class: 64-bit +# CHECK-NEXT: DataEncoding: LittleEndian +# CHECK-NEXT: FileVersion: 1 +# CHECK-NEXT: OS/ABI: SystemV +# CHECK-NEXT: ABIVersion: 0 +# CHECK-NEXT: Unused: (00 00 00 00 00 00 00) +# CHECK-NEXT: } +# CHECK-NEXT: Type: Relocatable +# CHECK-NEXT: Machine: EM_X86_64 +# CHECK-NEXT: Version: 1 +# CHECK-NEXT: Entry: 0x0 +# CHECK-NEXT: ProgramHeaderOffset: 0x0 +# CHECK-NEXT: SectionHeaderOffset: 0x2D8 +# CHECK-NEXT: Flags [ +# CHECK-NEXT: ] +# CHECK-NEXT: HeaderSize: 64 +# CHECK-NEXT: ProgramHeaderEntrySize: 0 +# CHECK-NEXT: ProgramHeaderCount: 0 +# CHECK-NEXT: SectionHeaderEntrySize: 64 +# CHECK-NEXT: SectionHeaderCount: 7 +# CHECK-NEXT: StringTableSectionIndex: 5 +# CHECK-NEXT: } + +# CHECK: Relocations [ +# CHECK-NEXT: Section (3) .rela.text { +# CHECK-NEXT: 0x3 R_X86_64_32S x 0x0 +# CHECK-NEXT: 0xE R_X86_64_32S y 0x0 +# CHECK-NEXT: 0x23 R_X86_64_32S xx 0x0 +# CHECK-NEXT: 0x2E R_X86_64_32S yy 0x0 +# CHECK-NEXT: 0x43 R_X86_64_32S xxx 0x0 +# CHECK-NEXT: 0x4E R_X86_64_32S yyy 0x0 +# CHECK-NEXT: } + +# CHECKTEXT: Disassembly of section .text: +# CHECKTEXT-NEXT: main: +# CHECKTEXT-NEXT: 0: c7 04 25 00 00 00 00 05 00 00 00 movl $5, 0 +# CHECKTEXT-NEXT: b: c7 04 25 00 00 00 00 07 00 00 00 movl $7, 0 +# CHECKTEXT: foo: +# CHECKTEXT-NEXT: 20: c7 04 25 00 00 00 00 01 00 00 00 movl $1, 0 +# CHECKTEXT-NEXT: 2b: c7 04 25 00 00 00 00 02 00 00 00 movl $2, 0 +# CHECKTEXT: bar: +# CHECKTEXT-NEXT: 40: c7 04 25 00 00 00 00 08 00 00 00 movl $8, 0 +# CHECKTEXT-NEXT: 4b: c7 04 25 00 00 00 00 09 00 00 00 movl $9, 0 + +# CHECKEXE: Format: ELF64-x86-64 +# CHECKEXE-NEXT: Arch: x86_64 +# CHECKEXE-NEXT: AddressSize: 64bit +# CHECKEXE-NEXT: LoadName: +# CHECKEXE-NEXT: ElfHeader { +# CHECKEXE-NEXT: Ident { +# CHECKEXE-NEXT: Magic: (7F 45 4C 46) +# CHECKEXE-NEXT: Class: 64-bit +# CHECKEXE-NEXT: DataEncoding: LittleEndian +# CHECKEXE-NEXT: FileVersion: 1 +# CHECKEXE-NEXT: OS/ABI: SystemV (0x0) +# CHECKEXE-NEXT: ABIVersion: 0 +# CHECKEXE-NEXT: Unused: (00 00 00 00 00 00 00) +# CHECKEXE-NEXT: } +# CHECKEXE-NEXT: Type: Executable +# CHECKEXE-NEXT: Machine: EM_X86_64 +# CHECKEXE-NEXT: Version: 1 +# CHECKEXE-NEXT: Entry: 0x11000 +# CHECKEXE-NEXT: ProgramHeaderOffset: 0x40 +# CHECKEXE-NEXT: SectionHeaderOffset: 0x2190 +# CHECKEXE-NEXT: Flags [ +# CHECKEXE-NEXT: ] +# CHECKEXE-NEXT: HeaderSize: 64 +# CHECKEXE-NEXT: ProgramHeaderEntrySize: 56 +# CHECKEXE-NEXT: ProgramHeaderCount: 5 +# CHECKEXE-NEXT: SectionHeaderEntrySize: 64 +# CHECKEXE-NEXT: SectionHeaderCount: 6 +# CHECKEXE-NEXT: StringTableSectionIndex: 4 +# CHECKEXE-NEXT: } + +.text +.type x,@object +.bss +.globl x +.align 4 +x: +.long 0 +.size x, 4 +.type y,@object +.globl y +.align 4 +y: +.long 0 +.size y, 4 + +.text +.globl main +.align 16, 0x90 +.type main,@function +main: +movl $5, x +movl $7, y + +blah: +goo: +abs = 42 Index: test/ELF/strip-all.s =================================================================== --- test/ELF/strip-all.s +++ test/ELF/strip-all.s @@ -13,6 +13,10 @@ #AFTER: .shstrtab #AFTER-NOT: .strtab +# Ignore --strip-all if -r is specified +#RUN: ld.lld %t.o --strip-all -r -o %t1 +#RUN: llvm-objdump -section-headers %t1 | FileCheck %s -check-prefix BEFORE + # Test alias -s #RUN: ld.lld %t.o -s -o %t1 #RUN: llvm-objdump -section-headers %t1 | FileCheck %s -check-prefix AFTER