forked from OSchip/llvm-project
Recommit r294464 "[ELF] - Added partial support for --emit-relocs (no --gc-section case, no /DISCARD/ support) #3"
with temporarily file name fix in testcase. Original commit message: -q, --emit-relocs - Generate relocations in output Simplest implementation: * no GC case, * no "/DISCARD/" linkerscript command support. This patch is extracted from D28612 / D29636, Relative to PR31579. Differential revision: https://reviews.llvm.org/D29663 llvm-svn: 294469
This commit is contained in:
parent
7e101936b6
commit
82bd8be6d8
|
@ -102,6 +102,7 @@ struct Configuration {
|
|||
bool Demangle = true;
|
||||
bool DisableVerify;
|
||||
bool EhFrameHdr;
|
||||
bool EmitRelocs;
|
||||
bool EnableNewDtags;
|
||||
bool ExportDynamic;
|
||||
bool FatalWarnings;
|
||||
|
@ -157,6 +158,7 @@ struct Configuration {
|
|||
unsigned LTOO;
|
||||
unsigned Optimize;
|
||||
unsigned ThinLTOJobs;
|
||||
bool copyRelocs() { return Relocatable || EmitRelocs; };
|
||||
};
|
||||
|
||||
// The only instance of Configuration struct.
|
||||
|
|
|
@ -519,6 +519,7 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
|
|||
Config->BsymbolicFunctions = Args.hasArg(OPT_Bsymbolic_functions);
|
||||
Config->Demangle = getArg(Args, OPT_demangle, OPT_no_demangle, true);
|
||||
Config->DisableVerify = Args.hasArg(OPT_disable_verify);
|
||||
Config->EmitRelocs = Args.hasArg(OPT_emit_relocs);
|
||||
Config->EhFrameHdr = Args.hasArg(OPT_eh_frame_hdr);
|
||||
Config->EnableNewDtags = !Args.hasArg(OPT_disable_new_dtags);
|
||||
Config->ExportDynamic =
|
||||
|
|
|
@ -399,6 +399,13 @@ elf::ObjectFile<ELFT>::createInputSection(const Elf_Shdr &Sec,
|
|||
}
|
||||
assert(isUInt<31>(NumRelocations));
|
||||
Target->NumRelocations = NumRelocations;
|
||||
|
||||
// Relocation sections processed by the linker are usually removed
|
||||
// from the output, so returning `nullptr` for the normal case.
|
||||
// However, if -emit-relocs is given, we need to leave them in the output.
|
||||
// (Some post link analysis tools need this information.)
|
||||
if (Config->EmitRelocs)
|
||||
return make<InputSection<ELFT>>(this, &Sec, Name);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -214,9 +214,9 @@ InputSectionBase<ELFT> *InputSection<ELFT>::getRelocatedSection() {
|
|||
return Sections[this->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.
|
||||
// This is used for -r and --emit-relocs. 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 <class RelTy>
|
||||
void InputSection<ELFT>::copyRelocations(uint8_t *Buf, ArrayRef<RelTy> Rels) {
|
||||
|
@ -235,7 +235,11 @@ void InputSection<ELFT>::copyRelocations(uint8_t *Buf, ArrayRef<RelTy> Rels) {
|
|||
|
||||
if (Config->Rela)
|
||||
P->r_addend = getAddend<ELFT>(Rel);
|
||||
P->r_offset = RelocatedSection->getOffset(Rel.r_offset);
|
||||
|
||||
// Output section VA is zero for -r, so r_offset is an offset within the
|
||||
// section, but for --emit-relocs it is an virtual address.
|
||||
P->r_offset = RelocatedSection->OutSec->Addr +
|
||||
RelocatedSection->getOffset(Rel.r_offset);
|
||||
P->setSymbolAndType(In<ELFT>::SymTab->getSymbolIndex(&Body), Type,
|
||||
Config->Mips64EL);
|
||||
}
|
||||
|
@ -514,7 +518,8 @@ template <class ELFT> void InputSection<ELFT>::writeTo(uint8_t *Buf) {
|
|||
return;
|
||||
}
|
||||
|
||||
// If -r is given, then an InputSection may be a relocation section.
|
||||
// If -r or --emit-relocs is given, then an InputSection
|
||||
// may be a relocation section.
|
||||
if (this->Type == SHT_RELA) {
|
||||
copyRelocations(Buf + OutSecOff, this->template getDataAs<Elf_Rela>());
|
||||
return;
|
||||
|
|
|
@ -70,6 +70,8 @@ def dynamic_list: S<"dynamic-list">,
|
|||
def eh_frame_hdr: F<"eh-frame-hdr">,
|
||||
HelpText<"Request creation of .eh_frame_hdr section and PT_GNU_EH_FRAME segment header">;
|
||||
|
||||
def emit_relocs: F<"emit-relocs">, HelpText<"Generate relocations in output">;
|
||||
|
||||
def enable_new_dtags: F<"enable-new-dtags">,
|
||||
HelpText<"Enable new dynamic tags">;
|
||||
|
||||
|
@ -283,6 +285,7 @@ def alias_define_common_dp: F<"dp">, Alias<define_common>;
|
|||
def alias_discard_all_x: Flag<["-"], "x">, Alias<discard_all>;
|
||||
def alias_discard_locals_X: Flag<["-"], "X">, Alias<discard_locals>;
|
||||
def alias_dynamic_list: J<"dynamic-list=">, Alias<dynamic_list>;
|
||||
def alias_emit_relocs: Flag<["-"], "q">, Alias<emit_relocs>;
|
||||
def alias_entry_e: JoinedOrSeparate<["-"], "e">, Alias<entry>;
|
||||
def alias_entry_entry: J<"entry=">, Alias<entry>;
|
||||
def alias_error_limit: J<"error-limit=">, Alias<error_limit>;
|
||||
|
|
|
@ -116,7 +116,7 @@ template <class ELFT> void OutputSection<ELFT>::finalize() {
|
|||
}
|
||||
|
||||
uint32_t Type = this->Type;
|
||||
if (!Config->Relocatable || (Type != SHT_RELA && Type != SHT_REL))
|
||||
if (!Config->copyRelocs() || (Type != SHT_RELA && Type != SHT_REL))
|
||||
return;
|
||||
|
||||
this->Link = In<ELFT>::SymTab->OutSec->SectionIndex;
|
||||
|
|
|
@ -449,9 +449,9 @@ static bool shouldKeepInSymtab(InputSectionBase<ELFT> *Sec, StringRef SymName,
|
|||
if (B.isFile())
|
||||
return false;
|
||||
|
||||
// We keep sections in symtab for relocatable output.
|
||||
// We keep sections in symtab for relocatable output and --emit-reloc.
|
||||
if (B.isSection())
|
||||
return Config->Relocatable;
|
||||
return Config->copyRelocs();
|
||||
|
||||
// If sym references a section in a discarded group, don't keep it.
|
||||
if (Sec == &InputSection<ELFT>::Discarded)
|
||||
|
|
|
@ -0,0 +1,108 @@
|
|||
# REQUIRES: x86
|
||||
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
|
||||
# RUN: ld.lld --emit-relocs %t1.o -o %t
|
||||
# RUN: llvm-readobj -t -r %t | FileCheck %s
|
||||
|
||||
## Check single dash form.
|
||||
# RUN: ld.lld -emit-relocs %t1.o -o %t1
|
||||
# RUN: llvm-readobj -t -r %t1 | FileCheck %s
|
||||
|
||||
## Check alias.
|
||||
# RUN: ld.lld -q %t1.o -o %t2
|
||||
# RUN: llvm-readobj -t -r %t2 | FileCheck %s
|
||||
|
||||
# CHECK: Relocations [
|
||||
# CHECK-NEXT: Section ({{.*}}) .rela.text {
|
||||
# CHECK-NEXT: 0x201002 R_X86_64_32 .text 0x1
|
||||
# CHECK-NEXT: 0x201007 R_X86_64_PLT32 fn 0xFFFFFFFFFFFFFFFC
|
||||
# CHECK-NEXT: 0x20100E R_X86_64_32 .text 0x1
|
||||
# CHECK-NEXT: 0x201013 R_X86_64_PLT32 fn2 0xFFFFFFFFFFFFFFFC
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: Symbols [
|
||||
# CHECK-NEXT: Symbol {
|
||||
# CHECK-NEXT: Name:
|
||||
# CHECK-NEXT: Value: 0x0
|
||||
# CHECK-NEXT: Size: 0
|
||||
# CHECK-NEXT: Binding: Local
|
||||
# CHECK-NEXT: Type: None
|
||||
# CHECK-NEXT: Other: 0
|
||||
# CHECK-NEXT: Section: Undefined
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: Symbol {
|
||||
# CHECK-NEXT: Name: bar
|
||||
# CHECK-NEXT: Value: 0x201001
|
||||
# CHECK-NEXT: Size: 0
|
||||
# CHECK-NEXT: Binding: Local
|
||||
# CHECK-NEXT: Type: None
|
||||
# CHECK-NEXT: Other: 0
|
||||
# CHECK-NEXT: Section: .text
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: Symbol {
|
||||
# CHECK-NEXT: Name: foo
|
||||
# CHECK-NEXT: Value: 0x20100D
|
||||
# CHECK-NEXT: Size: 0
|
||||
# CHECK-NEXT: Binding: Local
|
||||
# CHECK-NEXT: Type: None
|
||||
# CHECK-NEXT: Other: 0
|
||||
# CHECK-NEXT: Section: .text
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: Symbol {
|
||||
# CHECK-NEXT: Name:
|
||||
# CHECK-NEXT: Value: 0x201000
|
||||
# CHECK-NEXT: Size: 0
|
||||
# CHECK-NEXT: Binding: Local
|
||||
# CHECK-NEXT: Type: Section
|
||||
# CHECK-NEXT: Other: 0
|
||||
# CHECK-NEXT: Section: .text
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: Symbol {
|
||||
# CHECK-NEXT: Name:
|
||||
# CHECK-NEXT: Value: 0x20100C
|
||||
# CHECK-NEXT: Size: 0
|
||||
# CHECK-NEXT: Binding: Local
|
||||
# CHECK-NEXT: Type: Section
|
||||
# CHECK-NEXT: Other: 0
|
||||
# CHECK-NEXT: Section: .text
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: Symbol {
|
||||
# CHECK-NEXT: Name: fn
|
||||
# CHECK-NEXT: Value: 0x201000
|
||||
# CHECK-NEXT: Size: 0
|
||||
# CHECK-NEXT: Binding: Global
|
||||
# CHECK-NEXT: Type: Function
|
||||
# CHECK-NEXT: Other: 0
|
||||
# CHECK-NEXT: Section: .text
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: Symbol {
|
||||
# CHECK-NEXT: Name: fn2
|
||||
# CHECK-NEXT: Value: 0x20100C
|
||||
# CHECK-NEXT: Size: 0
|
||||
# CHECK-NEXT: Binding: Global
|
||||
# CHECK-NEXT: Type: Function
|
||||
# CHECK-NEXT: Other: 0
|
||||
# CHECK-NEXT: Section: .text
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: ]
|
||||
|
||||
.section .text,"ax",@progbits,unique,0
|
||||
.globl fn
|
||||
.type fn,@function
|
||||
fn:
|
||||
nop
|
||||
|
||||
bar:
|
||||
movl $bar, %edx
|
||||
callq fn@PLT
|
||||
nop
|
||||
|
||||
.section .text,"ax",@progbits,unique,1
|
||||
.globl fn2
|
||||
.type fn2,@function
|
||||
fn2:
|
||||
nop
|
||||
|
||||
foo:
|
||||
movl $foo, %edx
|
||||
callq fn2@PLT
|
||||
nop
|
Loading…
Reference in New Issue