From eade07ba59210f8fde8679d56ce37d58f1112691 Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Wed, 16 Sep 2015 21:57:07 +0000 Subject: [PATCH] Start adding support for Elf_Rel. I don't intend to add full i686 support right now, just make sure we have all the infrastructure in place for it. llvm-svn: 247858 --- lld/ELF/Writer.cpp | 137 +++++++++++++++++++++----------- lld/test/elf2/relocation-i686.s | 16 ++++ 2 files changed, 106 insertions(+), 47 deletions(-) create mode 100644 lld/test/elf2/relocation-i686.s diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index 6161eb81e309..a3a81912f02a 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -147,6 +147,7 @@ class lld::elf2::OutputSection final public: typedef typename OutputSectionBase::uintX_t uintX_t; typedef typename ELFFile::Elf_Shdr Elf_Shdr; + typedef typename ELFFile::Elf_Rel Elf_Rel; typedef typename ELFFile::Elf_Rela Elf_Rela; OutputSection(StringRef Name, uint32_t sh_type, uintX_t sh_flags, RelocationSection &RelaDynSec) @@ -156,6 +157,16 @@ public: void addChunk(SectionChunk *C); void writeTo(uint8_t *Buf) override; + template + void relocate(uint8_t *Buf, + iterator_range *> Rels, + const ObjectFile &File, uintX_t BaseAddr); + + void relocateOne(uint8_t *Buf, const Elf_Rela &Rel, uint32_t Type, + uintX_t BaseAddr, uintX_t SymVA); + void relocateOne(uint8_t *Buf, const Elf_Rel &Rel, uint32_t Type, + uintX_t BaseAddr, uintX_t SymVA); + private: std::vector *> Chunks; RelocationSection &RelaDynSec; @@ -540,61 +551,93 @@ getSymVA(const DefinedRegular *DR) { return OS->getVA() + SC->getOutputSectionOff() + DR->Sym.st_value; } +template +void OutputSection::relocateOne(uint8_t *Buf, const Elf_Rel &Rel, + uint32_t Type, uintX_t BaseAddr, + uintX_t SymVA) { + uintX_t Offset = Rel.r_offset; + uint8_t *Location = Buf + Offset; + switch (Type) { + case R_386_32: + support::endian::write32le(Location, SymVA); + break; + default: + llvm::errs() << Twine("unrecognized reloc ") + Twine(Type) << '\n'; + break; + } +} + +template +void OutputSection::relocateOne(uint8_t *Buf, const Elf_Rela &Rel, + uint32_t Type, uintX_t BaseAddr, + uintX_t SymVA) { + uintX_t Offset = Rel.r_offset; + uint8_t *Location = Buf + Offset; + switch (Type) { + case R_X86_64_PC32: + support::endian::write32le(Location, + SymVA + (Rel.r_addend - (BaseAddr + Offset))); + break; + case R_X86_64_64: + support::endian::write64le(Location, SymVA + Rel.r_addend); + break; + case R_X86_64_32: { + case R_X86_64_32S: + uint64_t VA = SymVA + Rel.r_addend; + if (Type == R_X86_64_32 && !isUInt<32>(VA)) + error("R_X86_64_32 out of range"); + else if (!isInt<32>(VA)) + error("R_X86_64_32S out of range"); + + support::endian::write32le(Location, VA); + break; + } + default: + llvm::errs() << Twine("unrecognized reloc ") + Twine(Type) << '\n'; + break; + } +} + +template +template +void OutputSection::relocate( + uint8_t *Buf, iterator_range *> Rels, + const ObjectFile &File, uintX_t BaseAddr) { + typedef Elf_Rel_Impl RelType; + 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; + + uintX_t SymVA; + if (auto *DR = dyn_cast>(Body)) + SymVA = getSymVA(DR); + else if (auto *DA = dyn_cast>(Body)) + SymVA = DA->Sym.st_value; + else + // Skip unsupported for now. + continue; + + uint32_t Type = RI.getType(IsMips64EL); + relocateOne(Buf, RI, Type, BaseAddr, SymVA); + } +} + template void OutputSection::writeTo(uint8_t *Buf) { for (SectionChunk *C : Chunks) { C->writeTo(Buf); const ObjectFile *File = C->getFile(); ELFFile *EObj = File->getObj(); uint8_t *Base = Buf + C->getOutputSectionOff(); - + uintX_t BaseAddr = this->getVA() + C->getOutputSectionOff(); // Iterate over all relocation sections that apply to this section. for (const Elf_Shdr *RelSec : C->RelocSections) { - // Only support RELA for now. - if (RelSec->sh_type != SHT_RELA) - continue; - for (const Elf_Rela &RI : EObj->relas(RelSec)) { - uint32_t SymIndex = RI.getSymbol(EObj->isMips64EL()); - const SymbolBody *Body = File->getSymbolBody(SymIndex); - if (!Body) - continue; - - uintX_t SymVA; - if (auto *DR = dyn_cast>(Body)) - SymVA = getSymVA(DR); - else if (auto *DA = dyn_cast>(Body)) - SymVA = DA->Sym.st_value; - else - // Skip unsupported for now. - continue; - - uintX_t Offset = RI.r_offset; - uint32_t Type = RI.getType(EObj->isMips64EL()); - uintX_t P = this->getVA() + C->getOutputSectionOff(); - uint8_t *Location = Base + Offset; - switch (Type) { - case llvm::ELF::R_X86_64_PC32: - support::endian::write32le(Location, - SymVA + (RI.r_addend - (P + Offset))); - break; - case llvm::ELF::R_X86_64_64: - support::endian::write64le(Location, SymVA + RI.r_addend); - break; - case llvm::ELF::R_X86_64_32: { - case llvm::ELF::R_X86_64_32S: - uint64_t VA = SymVA + RI.r_addend; - if (Type == llvm::ELF::R_X86_64_32 && !isUInt<32>(VA)) - error("R_X86_64_32 out of range"); - else if (!isInt<32>(VA)) - error("R_X86_64_32S out of range"); - - support::endian::write32le(Location, VA); - break; - } - default: - llvm::errs() << Twine("unrecognized reloc ") + Twine(Type) << '\n'; - break; - } - } + if (RelSec->sh_type == SHT_RELA) + relocate(Base, EObj->relas(RelSec), *File, BaseAddr); + else + relocate(Base, EObj->rels(RelSec), *File, BaseAddr); } } } diff --git a/lld/test/elf2/relocation-i686.s b/lld/test/elf2/relocation-i686.s new file mode 100644 index 000000000000..98cfb4f79383 --- /dev/null +++ b/lld/test/elf2/relocation-i686.s @@ -0,0 +1,16 @@ +// RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t +// RUN: lld -flavor gnu2 %t -o %t2 +// RUN: llvm-objdump -d %t2 | FileCheck %s +// REQUIRES: x86 + +.global _start +_start: + +.section .R_386_32,"ax",@progbits +.global R_386_32 +R_386_32: + movl $R_386_32, %edx + +// CHECK: Disassembly of section .R_386_32: +// CHECK-NEXT: R_386_32: +// CHECK-NEXT: 11000: {{.*}} movl $69632, %edx