forked from OSchip/llvm-project
[ELF2] - Basic implementation of -r/--relocatable
-r, -relocatable - Generate relocatable output Currently does not have support for files containing relocation sections with entries that refer to local symbols (like rel[a].eh_frame which refer to sections and not to symbols) Differential revision: http://reviews.llvm.org/D14382 llvm-svn: 261838
This commit is contained in:
parent
72c3cce484
commit
58941ee12a
|
@ -67,6 +67,7 @@ struct Configuration {
|
|||
bool NoInhibitExec;
|
||||
bool NoUndefined;
|
||||
bool PrintGcSections;
|
||||
bool Relocatable;
|
||||
bool Shared;
|
||||
bool Static = false;
|
||||
bool StripAll;
|
||||
|
|
|
@ -111,6 +111,10 @@ void LinkerDriver::addFile(StringRef Path) {
|
|||
Files.push_back(make_unique<ArchiveFile>(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;
|
||||
default:
|
||||
|
@ -130,12 +134,6 @@ void LinkerDriver::addLibrary(StringRef Name) {
|
|||
// 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)
|
||||
|
@ -143,6 +141,9 @@ static void checkOptions(opt::InputArgList &Args) {
|
|||
|
||||
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
|
||||
|
@ -219,6 +220,7 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
|
|||
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);
|
||||
|
@ -237,6 +239,9 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
|
|||
Config->ZOrigin = hasZOption(Args, "origin");
|
||||
Config->ZRelro = !hasZOption(Args, "norelro");
|
||||
|
||||
if (Config->Relocatable)
|
||||
Config->StripAll = false;
|
||||
|
||||
if (auto *Arg = Args.getLastArg(OPT_O)) {
|
||||
StringRef Val = Arg->getValue();
|
||||
if (Val.getAsInteger(10, Config->Optimize))
|
||||
|
@ -303,7 +308,7 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
|
|||
std::unique_ptr<TargetInfo> 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
|
||||
|
|
|
@ -226,7 +226,10 @@ void elf2::ObjectFile<ELFT>::initializeSections(
|
|||
continue;
|
||||
if (!RelocatedSection)
|
||||
fatal("Unsupported relocation reference");
|
||||
if (auto *S = dyn_cast<InputSection<ELFT>>(RelocatedSection)) {
|
||||
if (Config->Relocatable) {
|
||||
// For -r, relocation sections are handled as regular input sections.
|
||||
Sections[I] = new (Alloc) InputSection<ELFT>(this, &Sec);
|
||||
} else if (auto *S = dyn_cast<InputSection<ELFT>>(RelocatedSection)) {
|
||||
S->RelocSections.push_back(&Sec);
|
||||
} else if (auto *S = dyn_cast<EHInputSection<ELFT>>(RelocatedSection)) {
|
||||
if (S->RelocSection)
|
||||
|
|
|
@ -104,6 +104,43 @@ bool InputSection<ELFT>::classof(const InputSectionBase<ELFT> *S) {
|
|||
return S->SectionKind == Base::Regular;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
InputSectionBase<ELFT> *InputSection<ELFT>::getRelocatedSection() {
|
||||
assert(this->Header->sh_type == SHT_RELA || this->Header->sh_type == SHT_REL);
|
||||
ArrayRef<InputSectionBase<ELFT> *> Sections = this->File->getSections();
|
||||
return Sections[this->Header->sh_info];
|
||||
}
|
||||
|
||||
// This is used for -r. 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 <class ELFT>
|
||||
template <bool isRela>
|
||||
void InputSection<ELFT>::copyRelocations(uint8_t *Buf,
|
||||
RelIteratorRange<isRela> Rels) {
|
||||
typedef Elf_Rel_Impl<ELFT, isRela> RelType;
|
||||
InputSectionBase<ELFT> *RelocatedSection = getRelocatedSection();
|
||||
|
||||
for (const RelType &Rel : Rels) {
|
||||
uint32_t SymIndex = Rel.getSymbol(Config->Mips64EL);
|
||||
uint32_t Type = Rel.getType(Config->Mips64EL);
|
||||
const Elf_Shdr *SymTab = this->File->getSymbolTable();
|
||||
|
||||
RelType *P = reinterpret_cast<RelType *>(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 = this->File->getSymbolBody(SymIndex)->repl();
|
||||
P->r_offset = RelocatedSection->getOffset(Rel.r_offset);
|
||||
P->setSymbolAndType(Body->DynsymIndex, Type, Config->Mips64EL);
|
||||
}
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
template <bool isRela>
|
||||
uint8_t *
|
||||
|
@ -256,9 +293,21 @@ template <class ELFT> void InputSection<ELFT>::writeTo(uint8_t *Buf) {
|
|||
return;
|
||||
// Copy section contents from source object file to output file.
|
||||
ArrayRef<uint8_t> Data = this->getSectionData();
|
||||
ELFFile<ELFT> &EObj = this->File->getObj();
|
||||
|
||||
// That happens with -r. In that case we need fix the relocation position and
|
||||
// target. No relocations are applied.
|
||||
if (this->Header->sh_type == SHT_RELA) {
|
||||
this->copyRelocations(Buf + OutSecOff, EObj.relas(this->Header));
|
||||
return;
|
||||
}
|
||||
if (this->Header->sh_type == SHT_REL) {
|
||||
this->copyRelocations(Buf + OutSecOff, EObj.rels(this->Header));
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(Buf + OutSecOff, Data.data(), Data.size());
|
||||
|
||||
ELFFile<ELFT> &EObj = this->File->getObj();
|
||||
uint8_t *BufEnd = Buf + OutSecOff + Data.size();
|
||||
// Iterate over all relocation sections that apply to this section.
|
||||
for (const Elf_Shdr *RelSec : this->RelocSections) {
|
||||
|
|
|
@ -158,6 +158,16 @@ public:
|
|||
uint64_t OutSecOff = 0;
|
||||
|
||||
static bool classof(const InputSectionBase<ELFT> *S);
|
||||
|
||||
InputSectionBase<ELFT> *getRelocatedSection();
|
||||
|
||||
private:
|
||||
template <bool isRela>
|
||||
using RelIteratorRange =
|
||||
llvm::iterator_range<const llvm::object::Elf_Rel_Impl<ELFT, isRela> *>;
|
||||
|
||||
template <bool isRela>
|
||||
void copyRelocations(uint8_t *Buf, RelIteratorRange<isRela> Rels);
|
||||
};
|
||||
|
||||
// MIPS .reginfo section provides information on the registers used by the code
|
||||
|
|
|
@ -94,7 +94,8 @@ def print_gc_sections: Flag<["--"], "print-gc-sections">,
|
|||
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">;
|
||||
|
||||
|
|
|
@ -728,9 +728,24 @@ template <class ELFT> void EhFrameHeader<ELFT>::reserveFde() {
|
|||
}
|
||||
|
||||
template <class ELFT>
|
||||
OutputSection<ELFT>::OutputSection(StringRef Name, uint32_t Type,
|
||||
uintX_t Flags)
|
||||
: OutputSectionBase<ELFT>(Name, Type, Flags) {}
|
||||
OutputSection<ELFT>::OutputSection(StringRef Name, uint32_t Type, uintX_t Flags)
|
||||
: OutputSectionBase<ELFT>(Name, Type, Flags) {
|
||||
if (Type == SHT_RELA)
|
||||
this->Header.sh_entsize = sizeof(Elf_Rela);
|
||||
else if (Type == SHT_REL)
|
||||
this->Header.sh_entsize = sizeof(Elf_Rel);
|
||||
}
|
||||
|
||||
template <class ELFT> void OutputSection<ELFT>::finalize() {
|
||||
uint32_t Type = this->Header.sh_type;
|
||||
if (Type != SHT_RELA && Type != SHT_REL)
|
||||
return;
|
||||
this->Header.sh_link = Out<ELFT>::SymTab->SectionIndex;
|
||||
// sh_info for SHT_REL[A] sections should contain the section header index of
|
||||
// the section to which the relocation applies.
|
||||
InputSectionBase<ELFT> *S = Sections[0]->getRelocatedSection();
|
||||
this->Header.sh_info = S->OutSec->SectionIndex;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
void OutputSection<ELFT>::addSection(InputSectionBase<ELFT> *C) {
|
||||
|
@ -1368,6 +1383,13 @@ template <class ELFT> void SymbolTableSection<ELFT>::finalize() {
|
|||
this->Header.sh_link = StrTabSec.SectionIndex;
|
||||
this->Header.sh_info = NumLocals + 1;
|
||||
|
||||
if (Config->Relocatable) {
|
||||
size_t I = NumLocals;
|
||||
for (const std::pair<SymbolBody *, size_t> &P : Symbols)
|
||||
P.first->DynsymIndex = ++I;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!StrTabSec.isDynamic()) {
|
||||
std::stable_sort(Symbols.begin(), Symbols.end(),
|
||||
[](const std::pair<SymbolBody *, unsigned> &L,
|
||||
|
|
|
@ -287,6 +287,7 @@ public:
|
|||
void sortInitFini();
|
||||
void sortCtorsDtors();
|
||||
void writeTo(uint8_t *Buf) override;
|
||||
void finalize() override;
|
||||
|
||||
private:
|
||||
void reassignOffsets();
|
||||
|
|
|
@ -69,6 +69,7 @@ private:
|
|||
void scanRelocs(InputSectionBase<ELFT> &S, const Elf_Shdr &RelSec);
|
||||
void createPhdrs();
|
||||
void assignAddresses();
|
||||
void assignAddressesRelocatable();
|
||||
void fixAbsoluteSymbols();
|
||||
bool openFile();
|
||||
void writeHeader();
|
||||
|
@ -93,13 +94,15 @@ private:
|
|||
std::vector<std::unique_ptr<OutputSectionBase<ELFT>>> OwningSections;
|
||||
|
||||
// We create a section for the ELF header and one for the program headers.
|
||||
const unsigned NumDummySections = 2;
|
||||
ArrayRef<OutputSectionBase<ELFT> *> 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 @@ template <class ELFT> void Writer<ELFT>::run() {
|
|||
addReservedSymbols();
|
||||
if (!createSections())
|
||||
return;
|
||||
createPhdrs();
|
||||
assignAddresses();
|
||||
if (!Config->Relocatable) {
|
||||
createPhdrs();
|
||||
assignAddresses();
|
||||
} else {
|
||||
assignAddressesRelocatable();
|
||||
}
|
||||
fixAbsoluteSymbols();
|
||||
if (!openFile())
|
||||
return;
|
||||
|
@ -495,7 +502,7 @@ void Writer<ELFT>::scanRelocs(InputSectionBase<ELFT> &S,
|
|||
|
||||
template <class ELFT>
|
||||
static void reportUndefined(SymbolTable<ELFT> &Symtab, SymbolBody *Sym) {
|
||||
if (Config->Shared && !Config->NoUndefined)
|
||||
if ((Config->Relocatable || Config->Shared) && !Config->NoUndefined)
|
||||
return;
|
||||
|
||||
std::string Msg = "undefined symbol: " + Sym->getName().str();
|
||||
|
@ -928,7 +935,8 @@ template <class ELFT> static void sortCtorsDtors(OutputSectionBase<ELFT> *S) {
|
|||
// Create output section objects and add them to OutputSections.
|
||||
template <class ELFT> bool Writer<ELFT>::createSections() {
|
||||
OutputSections.push_back(Out<ELFT>::ElfHeader);
|
||||
OutputSections.push_back(Out<ELFT>::ProgramHeaders);
|
||||
if (!Config->Relocatable)
|
||||
OutputSections.push_back(Out<ELFT>::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 +1048,8 @@ template <class ELFT> bool Writer<ELFT>::createSections() {
|
|||
std::stable_sort(OutputSections.begin(), OutputSections.end(),
|
||||
compareSections<ELFT>);
|
||||
|
||||
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<ELFT> *Sec : getSections())
|
||||
Sec->setSHName(Out<ELFT>::ShStrTab->addString(Sec->getName()));
|
||||
|
@ -1304,6 +1312,21 @@ template <class ELFT> void Writer<ELFT>::createPhdrs() {
|
|||
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 <class ELFT> void Writer<ELFT>::assignAddressesRelocatable() {
|
||||
Out<ELFT>::ElfHeader->setSize(sizeof(Elf_Ehdr));
|
||||
uintX_t FileOff = 0;
|
||||
for (OutputSectionBase<ELFT> *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 <class ELFT> void Writer<ELFT>::assignAddresses() {
|
||||
|
@ -1445,20 +1468,29 @@ template <class ELFT> void Writer<ELFT>::writeHeader() {
|
|||
auto &FirstObj = cast<ELFFileBase<ELFT>>(*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<ELFT>();
|
||||
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<ELFT>::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<Elf_Phdr *>(Buf + EHdr->e_phoff);
|
||||
for (Phdr &P : Phdrs)
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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: 0x11E8
|
||||
# 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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue