Index: lld/trunk/ELF/Chunks.h =================================================================== --- lld/trunk/ELF/Chunks.h +++ lld/trunk/ELF/Chunks.h @@ -27,7 +27,7 @@ typedef typename llvm::object::ELFFile::uintX_t uintX_t; public: - SectionChunk(llvm::object::ELFFile *Obj, const Elf_Shdr *Header); + SectionChunk(ObjectFile *F, const Elf_Shdr *Header); // Returns the size of this chunk (even if this is a common or BSS.) size_t getSize() const { return Header->sh_size; } @@ -38,6 +38,7 @@ StringRef getSectionName() const; const Elf_Shdr *getSectionHdr() const { return Header; } + ObjectFile *getFile() { return File; } // The writer sets and uses the addresses. uintX_t getOutputSectionOff() const { return OutputSectionOff; } @@ -47,13 +48,16 @@ void setOutputSection(OutputSection *O) { Out = O; } OutputSection *getOutputSection() const { return Out; } + // Relocation sections that refer to this one. + SmallVector RelocSections; + private: // The offset from beginning of the output sections this chunk was assigned // to. The writer sets a value. uint64_t OutputSectionOff = 0; - // A file this chunk was created from. - llvm::object::ELFFile *Obj; + // The file this chunk was created from. + ObjectFile *File; OutputSection *Out = nullptr; Index: lld/trunk/ELF/Chunks.cpp =================================================================== --- lld/trunk/ELF/Chunks.cpp +++ lld/trunk/ELF/Chunks.cpp @@ -9,6 +9,7 @@ #include "Chunks.h" #include "Error.h" +#include "InputFiles.h" using namespace llvm; using namespace llvm::ELF; @@ -17,22 +18,19 @@ using namespace lld::elf2; template -SectionChunk::SectionChunk(object::ELFFile *Obj, - const Elf_Shdr *Header) - : Obj(Obj), Header(Header) {} +SectionChunk::SectionChunk(ObjectFile *F, const Elf_Shdr *Header) + : File(F), Header(Header) {} template void SectionChunk::writeTo(uint8_t *Buf) { if (Header->sh_type == SHT_NOBITS) return; // Copy section contents from source object file to output file. - ArrayRef Data = *Obj->getSectionContents(Header); + ArrayRef Data = *File->getObj()->getSectionContents(Header); memcpy(Buf + OutputSectionOff, Data.data(), Data.size()); - - // FIXME: Relocations } template StringRef SectionChunk::getSectionName() const { - ErrorOr Name = Obj->getSectionName(Header); + ErrorOr Name = File->getObj()->getSectionName(Header); error(Name); return *Name; } Index: lld/trunk/ELF/InputFiles.h =================================================================== --- lld/trunk/ELF/InputFiles.h +++ lld/trunk/ELF/InputFiles.h @@ -91,6 +91,13 @@ ArrayRef *> getChunks() { return Chunks; } + SymbolBody *getSymbolBody(uint32_t SymbolIndex) { + uint32_t FirstNonLocal = Symtab->sh_info; + if (SymbolIndex < FirstNonLocal) + return nullptr; + return SymbolBodies[SymbolIndex - FirstNonLocal]->getReplacement(); + } + private: void initializeChunks(); void initializeSymbols(); Index: lld/trunk/ELF/InputFiles.cpp =================================================================== --- lld/trunk/ELF/InputFiles.cpp +++ lld/trunk/ELF/InputFiles.cpp @@ -54,11 +54,20 @@ } case SHT_STRTAB: case SHT_NULL: + break; case SHT_RELA: - case SHT_REL: + case SHT_REL: { + uint32_t RelocatedSectionIndex = Sec.sh_info; + if (RelocatedSectionIndex >= Size) + error("Invalid relocated section index"); + SectionChunk *RelocatedSection = Chunks[RelocatedSectionIndex]; + if (!RelocatedSection) + error("Unsupported relocation reference"); + RelocatedSection->RelocSections.push_back(&Sec); break; + } default: - Chunks[I] = new (Alloc) SectionChunk(this->getObj(), &Sec); + Chunks[I] = new (Alloc) SectionChunk(this, &Sec); break; } ++I; Index: lld/trunk/ELF/Symbols.h =================================================================== --- lld/trunk/ELF/Symbols.h +++ lld/trunk/ELF/Symbols.h @@ -63,6 +63,7 @@ // has chosen the object among other objects having the same name, // you can access P->Backref->Body to get the resolver's result. void setBackref(Symbol *P) { Backref = P; } + SymbolBody *getReplacement() { return Backref ? Backref->Body : this; } // Decides which symbol should "win" in the symbol table, this or // the Other. Returns 1 if this wins, -1 if the Other wins, or 0 if Index: lld/trunk/ELF/Writer.cpp =================================================================== --- lld/trunk/ELF/Writer.cpp +++ lld/trunk/ELF/Writer.cpp @@ -10,12 +10,14 @@ #include "Chunks.h" #include "Config.h" #include "Error.h" +#include "Symbols.h" #include "SymbolTable.h" #include "Writer.h" #include "Symbols.h" #include "llvm/ADT/DenseMap.h" #include "llvm/Support/FileOutputBuffer.h" +#include "llvm/Support/raw_ostream.h" using namespace llvm; using namespace llvm::ELF; @@ -77,6 +79,8 @@ : public OutputSectionBase { public: typedef typename OutputSectionBase::uintX_t uintX_t; + typedef typename ELFFile::Elf_Shdr Elf_Shdr; + typedef typename ELFFile::Elf_Rela Elf_Rela; OutputSection(StringRef Name, uint32_t sh_type, uintX_t sh_flags) : OutputSectionBase(Name, sh_type, sh_flags) {} @@ -215,9 +219,52 @@ this->Header.sh_size = Off; } +template +static typename llvm::object::ELFFile::uintX_t +getSymVA(DefinedRegular *DR) { + const SectionChunk *SC = &DR->Section; + OutputSection *OS = SC->getOutputSection(); + return OS->getVA() + SC->getOutputSectionOff() + DR->Sym.st_value; +} + template void OutputSection::writeTo(uint8_t *Buf) { - for (SectionChunk *C : Chunks) + for (SectionChunk *C : Chunks) { C->writeTo(Buf); + ObjectFile *File = C->getFile(); + ELFFile *EObj = File->getObj(); + uint8_t *Base = Buf + 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()); + SymbolBody *Body = File->getSymbolBody(SymIndex); + if (!Body) + continue; + // Skip undefined weak for now. + if (isa>(Body)) + continue; + if (!isa>(Body)) + error(Twine("Can't relocate symbol ") + Body->getName()); + uintX_t Offset = RI.r_offset; + uint32_t Type = RI.getType(EObj->isMips64EL()); + uintX_t P = this->getVA() + C->getOutputSectionOff(); + uintX_t SymVA = getSymVA(cast>(Body)); + switch (Type) { + case llvm::ELF::R_X86_64_PC32: + support::endian::write32le(Base + Offset, + SymVA + (RI.r_addend - (P + Offset))); + break; + default: + llvm::errs() << Twine("unrecognized reloc ") + Twine(Type) << '\n'; + break; + } + } + } + } } template Index: lld/trunk/test/elf2/invalid-relocations.test =================================================================== --- lld/trunk/test/elf2/invalid-relocations.test +++ lld/trunk/test/elf2/invalid-relocations.test @@ -0,0 +1,30 @@ +# RUN: yaml2obj -format elf %s -o %t +# RUN: not lld -flavor gnu2 %t -o %tout 2>&1 | FileCheck %s + +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + OSABI: ELFOSABI_GNU + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + AddressAlign: 0x0000000000000004 + Content: E800000000 + - Name: .rela.text + Type: SHT_RELA + Info: 12 # Invalid index + Relocations: + - Offset: 0x0000000000000001 + Symbol: lulz + Type: R_X86_64_PC32 + Addend: -4 +Symbols: + Global: + - Name: lulz + Type: STT_FUNC + Section: .text + +# CHECK: Invalid relocated section index Index: lld/trunk/test/elf2/relocation.s =================================================================== --- lld/trunk/test/elf2/relocation.s +++ lld/trunk/test/elf2/relocation.s @@ -0,0 +1,17 @@ +// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t +// RUN: lld -flavor gnu2 %t -o %t2 +// RUN: llvm-objdump -d %t2 | FileCheck %s +// REQUIRES: x86 + + +.section .text,"ax",@progbits,unique,1 +.global _start +_start: + call lulz + +.section .text,"ax",@progbits,unique,2 +.zero 4 +.global lulz +lulz: + +// CHECK: e8 04 00 00 00 callq 4