[ELF2] Support relocs for local symbols

Differential Revision:	 http://reviews.llvm.org/D12978

llvm-svn: 248196
This commit is contained in:
Davide Italiano 2015-09-21 19:30:11 +00:00
parent b12db0e42c
commit 8ca741d51d
2 changed files with 94 additions and 31 deletions

View File

@ -263,6 +263,7 @@ class lld::elf2::OutputSection final
public:
typedef typename OutputSectionBase<ELFT::Is64Bits>::uintX_t uintX_t;
typedef typename ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
typedef typename ELFFile<ELFT>::Elf_Sym Elf_Sym;
typedef typename ELFFile<ELFT>::Elf_Rel Elf_Rel;
typedef typename ELFFile<ELFT>::Elf_Rela Elf_Rela;
OutputSection(const PltSection<ELFT> &PltSec, const GotSection<ELFT> &GotSec,
@ -733,6 +734,21 @@ getSymVA(const DefinedRegular<ELFT> *DR) {
return OS->getVA() + SC->getOutputSectionOff() + DR->Sym.st_value;
}
template <class ELFT>
static typename ELFFile<ELFT>::uintX_t
getLocalSymVA(const typename ELFFile<ELFT>::Elf_Sym *Sym,
const ObjectFile<ELFT> &File) {
uint32_t SecIndex = Sym->st_shndx;
if (SecIndex == SHN_XINDEX)
SecIndex = File.getObj()->getExtendedSymbolTableIndex(
Sym, File.getSymbolTable(), File.getSymbolTableShndx());
ArrayRef<InputSection<ELFT> *> Chunks = File.getChunks();
InputSection<ELFT> *Section = Chunks[SecIndex];
OutputSection<ELFT> *Out = Section->getOutputSection();
return Out->getVA() + Section->getOutputSectionOff() + Sym->st_value;
}
template <class ELFT>
void OutputSection<ELFT>::relocateOne(uint8_t *Buf, const Elf_Rel &Rel,
uint32_t Type, uintX_t BaseAddr,
@ -789,42 +805,51 @@ void OutputSection<ELFT>::relocate(
bool IsMips64EL = File.getObj()->isMips64EL();
for (const RelType &RI : Rels) {
uint32_t SymIndex = RI.getSymbol(IsMips64EL);
const SymbolBody *Body = File.getSymbolBody(SymIndex);
if (!Body)
continue;
uint32_t Type = RI.getType(IsMips64EL);
uintX_t SymVA;
switch (Body->kind()) {
case SymbolBody::DefinedRegularKind:
SymVA = getSymVA<ELFT>(cast<DefinedRegular<ELFT>>(Body));
break;
case SymbolBody::DefinedAbsoluteKind:
SymVA = cast<DefinedAbsolute<ELFT>>(Body)->Sym.st_value;
break;
case SymbolBody::DefinedCommonKind: {
auto *DC = cast<DefinedCommon<ELFT>>(Body);
SymVA = DC->OutputSec->getVA() + DC->OffsetInBSS;
break;
}
case SymbolBody::SharedKind:
if (relocNeedsPLT(Type)) {
SymVA = PltSec.getEntryAddr(*Body);
Type = R_X86_64_PC32;
} else if (relocNeedsGOT(Type)) {
SymVA = GotSec.getEntryAddr(*Body);
Type = R_X86_64_PC32;
} else {
// Handle relocations for local symbols -- they never get
// resolved so we don't allocate a SymbolBody.
const Elf_Shdr *SymTab = File.getSymbolTable();
if (SymIndex < SymTab->sh_info) {
const Elf_Sym *Sym = File.getObj()->getRelocationSymbol(&RI, SymTab);
if (!Sym)
continue;
SymVA = getLocalSymVA(Sym, File);
} else {
const SymbolBody *Body = File.getSymbolBody(SymIndex);
if (!Body)
continue;
switch (Body->kind()) {
case SymbolBody::DefinedRegularKind:
SymVA = getSymVA<ELFT>(cast<DefinedRegular<ELFT>>(Body));
break;
case SymbolBody::DefinedAbsoluteKind:
SymVA = cast<DefinedAbsolute<ELFT>>(Body)->Sym.st_value;
break;
case SymbolBody::DefinedCommonKind: {
auto *DC = cast<DefinedCommon<ELFT>>(Body);
SymVA = DC->OutputSec->getVA() + DC->OffsetInBSS;
break;
}
case SymbolBody::SharedKind:
if (relocNeedsPLT(Type)) {
SymVA = PltSec.getEntryAddr(*Body);
Type = R_X86_64_PC32;
} else if (relocNeedsGOT(Type)) {
SymVA = GotSec.getEntryAddr(*Body);
Type = R_X86_64_PC32;
} else {
continue;
}
break;
case SymbolBody::UndefinedKind:
assert(Body->isWeak() && "Undefined symbol reached writer");
SymVA = 0;
break;
case SymbolBody::LazyKind:
llvm_unreachable("Lazy symbol reached writer");
}
break;
case SymbolBody::UndefinedKind:
assert(Body->isWeak() && "Undefined symbol reached writer");
SymVA = 0;
break;
case SymbolBody::LazyKind:
llvm_unreachable("Lazy symbol reached writer");
}
relocateOne(Buf, RI, Type, BaseAddr, SymVA);

View File

@ -0,0 +1,38 @@
// Test that relocation of local symbols is working.
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
// RUN: lld -flavor gnu2 %t -o %t2
// RUN: llvm-objdump -s -d %t2 | FileCheck %s
// REQUIRES: x86
.global _start
_start:
call lulz
.zero 4
lulz:
.section .text2,"ax",@progbits
R_X86_64_32:
movl $R_X86_64_32, %edx
// FIXME: this would be far more self evident if llvm-objdump printed
// constants in hex.
// CHECK: Disassembly of section .text2:
// CHECK-NEXT: R_X86_64_32:
// CHECK-NEXT: 1100c: {{.*}} movl $69644, %edx
.section .R_X86_64_32S,"ax",@progbits
R_X86_64_32S:
movq lulz - 0x100000, %rdx
// CHECK: Disassembly of section .R_X86_64_32S:
// CHECK-NEXT: R_X86_64_32S:
// CHECK-NEXT: {{.*}}: {{.*}} movq -978935, %rdx
.section .R_X86_64_64,"a",@progbits
R_X86_64_64:
.quad R_X86_64_64
// CHECK: Contents of section .R_X86_64_64:
// CHECK-NEXT: 12000 00200100 00000000