forked from OSchip/llvm-project
Start adding target abstractions.
This is just enough to get PLT working on 32 bit x86. The idea behind using a virtual interface is that it should be easy to convert any of the functions to template parameters if any turns out to be performance critical. llvm-svn: 248308
This commit is contained in:
parent
e8fe34d4d1
commit
01205f79a4
|
@ -11,6 +11,7 @@ add_llvm_library(lldELF2
|
|||
OutputSections.cpp
|
||||
SymbolTable.cpp
|
||||
Symbols.cpp
|
||||
Target.cpp
|
||||
Writer.cpp
|
||||
|
||||
LINK_COMPONENTS
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "Error.h"
|
||||
#include "InputFiles.h"
|
||||
#include "OutputSections.h"
|
||||
#include "Target.h"
|
||||
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
|
@ -114,12 +115,12 @@ void InputSection<ELFT>::relocate(
|
|||
break;
|
||||
}
|
||||
case SymbolBody::SharedKind:
|
||||
if (relocNeedsPLT(Type)) {
|
||||
if (Target->relocNeedsPlt(Type)) {
|
||||
SymVA = PltSec.getEntryAddr(*Body);
|
||||
Type = R_X86_64_PC32;
|
||||
} else if (relocNeedsGOT(Type)) {
|
||||
Type = Target->getPCRelReloc();
|
||||
} else if (Target->relocNeedsGot(Type)) {
|
||||
SymVA = GotSec.getEntryAddr(*Body);
|
||||
Type = R_X86_64_PC32;
|
||||
Type = Target->getPCRelReloc();
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "OutputSections.h"
|
||||
#include "Config.h"
|
||||
#include "SymbolTable.h"
|
||||
#include "Target.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::object;
|
||||
|
@ -42,21 +43,11 @@ template <class ELFT> void PltSection<ELFT>::writeTo(uint8_t *Buf) {
|
|||
uintptr_t Start = reinterpret_cast<uintptr_t>(Buf);
|
||||
ArrayRef<uint8_t> Jmp = {0xff, 0x25}; // jmpq *val(%rip)
|
||||
for (const SymbolBody *E : Entries) {
|
||||
uint64_t GotEntryAddr = GotSec.getEntryAddr(*E);
|
||||
uintptr_t InstPos = reinterpret_cast<uintptr_t>(Buf);
|
||||
|
||||
memcpy(Buf, Jmp.data(), Jmp.size());
|
||||
Buf += Jmp.size();
|
||||
|
||||
uintptr_t OffsetInPLT = (InstPos + 6) - Start;
|
||||
intptr_t Delta = GotSec.getEntryAddr(*E) - (this->getVA() + OffsetInPLT);
|
||||
assert(isInt<32>(Delta));
|
||||
support::endian::write32le(Buf, Delta);
|
||||
Buf += 4;
|
||||
|
||||
*Buf = 0x90; // nop
|
||||
++Buf;
|
||||
*Buf = 0x90; // nop
|
||||
++Buf;
|
||||
uint64_t PltEntryAddr = (InstPos - Start) + this->getVA();
|
||||
Target->writePltEntry(Buf, GotEntryAddr, PltEntryAddr);
|
||||
Buf += 8;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -71,26 +62,6 @@ PltSection<ELFT>::getEntryAddr(const SymbolBody &B) const {
|
|||
return this->getVA() + B.getPltIndex() * EntrySize;
|
||||
}
|
||||
|
||||
bool lld::elf2::relocNeedsPLT(uint32_t Type) {
|
||||
switch (Type) {
|
||||
default:
|
||||
return false;
|
||||
case R_X86_64_PLT32:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool lld::elf2::relocNeedsGOT(uint32_t Type) {
|
||||
if (relocNeedsPLT(Type))
|
||||
return true;
|
||||
switch (Type) {
|
||||
default:
|
||||
return false;
|
||||
case R_X86_64_GOTPCREL:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) {
|
||||
const unsigned EntrySize = IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel);
|
||||
bool IsMips64EL = Relocs[0].C.getFile()->getObj()->isMips64EL();
|
||||
|
@ -104,7 +75,7 @@ template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) {
|
|||
uint32_t SymIndex = RI.getSymbol(IsMips64EL);
|
||||
const SymbolBody *Body = C.getFile()->getSymbolBody(SymIndex);
|
||||
uint32_t Type = RI.getType(IsMips64EL);
|
||||
if (relocNeedsGOT(Type)) {
|
||||
if (Target->relocNeedsGot(Type)) {
|
||||
P->r_offset = GotSec.getEntryAddr(*Body);
|
||||
P->setSymbolAndType(Body->getDynamicSymbolTableIndex(), R_X86_64_GLOB_DAT,
|
||||
IsMips64EL);
|
||||
|
|
|
@ -29,9 +29,6 @@ template <class ELFT> class OutputSection;
|
|||
template <class ELFT> class ObjectFile;
|
||||
template <class ELFT> class DefinedRegular;
|
||||
|
||||
bool relocNeedsPLT(uint32_t Type);
|
||||
bool relocNeedsGOT(uint32_t Type);
|
||||
|
||||
template <class ELFT>
|
||||
typename llvm::object::ELFFile<ELFT>::uintX_t
|
||||
getSymVA(const DefinedRegular<ELFT> *DR);
|
||||
|
|
|
@ -11,9 +11,11 @@
|
|||
#include "Config.h"
|
||||
#include "Error.h"
|
||||
#include "Symbols.h"
|
||||
#include "Target.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::object;
|
||||
using namespace llvm::ELF;
|
||||
|
||||
using namespace lld;
|
||||
using namespace lld::elf2;
|
||||
|
@ -37,7 +39,11 @@ void SymbolTable::addFile(std::unique_ptr<InputFile> File) {
|
|||
addELFFile(cast<ELFFileBase>(FileP));
|
||||
}
|
||||
|
||||
template <class ELFT> void SymbolTable::init() {
|
||||
template <class ELFT> void SymbolTable::init(uint16_t EMachine) {
|
||||
if (EMachine == EM_X86_64)
|
||||
Target.reset(new X86_64TargetInfo());
|
||||
else
|
||||
Target.reset(new X86TargetInfo());
|
||||
if (Config->Shared)
|
||||
return;
|
||||
EntrySym = new (Alloc) Undefined<ELFT>("_start", Undefined<ELFT>::Synthetic);
|
||||
|
@ -49,7 +55,7 @@ template <class ELFT> void SymbolTable::addELFFile(ELFFileBase *File) {
|
|||
if (!Old->isCompatibleWith(*File))
|
||||
error(Twine(Old->getName() + " is incompatible with " + File->getName()));
|
||||
} else {
|
||||
init<ELFT>();
|
||||
init<ELFT>(File->getEMachine());
|
||||
}
|
||||
|
||||
if (auto *O = dyn_cast<ObjectFileBase>(File)) {
|
||||
|
|
|
@ -68,7 +68,7 @@ private:
|
|||
void addLazy(Lazy *New);
|
||||
void addMemberFile(Lazy *Body);
|
||||
|
||||
template <class ELFT> void init();
|
||||
template <class ELFT> void init(uint16_t EMachine);
|
||||
template <class ELFT> void resolve(SymbolBody *Body);
|
||||
|
||||
std::vector<std::unique_ptr<ArchiveFile>> ArchiveFiles;
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
//===- Target.cpp ---------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "Target.h"
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
#include "llvm/Support/ELF.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::ELF;
|
||||
|
||||
namespace lld {
|
||||
namespace elf2 {
|
||||
|
||||
std::unique_ptr<TargetInfo> Target;
|
||||
|
||||
TargetInfo::~TargetInfo() {}
|
||||
|
||||
X86TargetInfo::X86TargetInfo() { PCRelReloc = R_386_PC32; }
|
||||
|
||||
void X86TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
|
||||
uint64_t PltEntryAddr) const {
|
||||
ArrayRef<uint8_t> Jmp = {0xff, 0x25}; // jmpl *val
|
||||
memcpy(Buf, Jmp.data(), Jmp.size());
|
||||
Buf += Jmp.size();
|
||||
|
||||
assert(isUInt<32>(GotEntryAddr));
|
||||
support::endian::write32le(Buf, GotEntryAddr);
|
||||
Buf += 4;
|
||||
|
||||
ArrayRef<uint8_t> Nops = {0x90, 0x90};
|
||||
memcpy(Buf, Nops.data(), Nops.size());
|
||||
}
|
||||
|
||||
bool X86TargetInfo::relocNeedsGot(uint32_t Type) const {
|
||||
if (relocNeedsPlt(Type))
|
||||
return true;
|
||||
switch (Type) {
|
||||
default:
|
||||
return false;
|
||||
case R_386_GOT32:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool X86TargetInfo::relocNeedsPlt(uint32_t Type) const {
|
||||
switch (Type) {
|
||||
default:
|
||||
return false;
|
||||
case R_386_PLT32:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
X86_64TargetInfo::X86_64TargetInfo() { PCRelReloc = R_X86_64_PC32; }
|
||||
|
||||
void X86_64TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
|
||||
uint64_t PltEntryAddr) const {
|
||||
ArrayRef<uint8_t> Jmp = {0xff, 0x25}; // jmpq *val(%rip)
|
||||
memcpy(Buf, Jmp.data(), Jmp.size());
|
||||
Buf += Jmp.size();
|
||||
|
||||
uintptr_t NextPC = PltEntryAddr + 6;
|
||||
uintptr_t Delta = GotEntryAddr - NextPC;
|
||||
assert(isInt<32>(Delta));
|
||||
support::endian::write32le(Buf, Delta);
|
||||
Buf += 4;
|
||||
|
||||
ArrayRef<uint8_t> Nops = {0x90, 0x90};
|
||||
memcpy(Buf, Nops.data(), Nops.size());
|
||||
}
|
||||
|
||||
bool X86_64TargetInfo::relocNeedsGot(uint32_t Type) const {
|
||||
if (relocNeedsPlt(Type))
|
||||
return true;
|
||||
switch (Type) {
|
||||
default:
|
||||
return false;
|
||||
case R_X86_64_GOTPCREL:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool X86_64TargetInfo::relocNeedsPlt(uint32_t Type) const {
|
||||
switch (Type) {
|
||||
default:
|
||||
return false;
|
||||
case R_X86_64_PLT32:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
//===- Target.h -------------------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_ELF_TARGET_H
|
||||
#define LLD_ELF_TARGET_H
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace lld {
|
||||
namespace elf2 {
|
||||
class SymbolBody;
|
||||
|
||||
class TargetInfo {
|
||||
public:
|
||||
unsigned getPCRelReloc() const { return PCRelReloc; }
|
||||
virtual void writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
|
||||
uint64_t PltEntryAddr) const = 0;
|
||||
virtual bool relocNeedsGot(uint32_t Type) const = 0;
|
||||
virtual bool relocNeedsPlt(uint32_t Type) const = 0;
|
||||
virtual ~TargetInfo();
|
||||
|
||||
protected:
|
||||
unsigned PCRelReloc;
|
||||
};
|
||||
|
||||
class X86TargetInfo final : public TargetInfo {
|
||||
public:
|
||||
X86TargetInfo();
|
||||
void writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
|
||||
uint64_t PltEntryAddr) const override;
|
||||
bool relocNeedsGot(uint32_t Type) const override;
|
||||
bool relocNeedsPlt(uint32_t Type) const override;
|
||||
};
|
||||
|
||||
class X86_64TargetInfo final : public TargetInfo {
|
||||
public:
|
||||
X86_64TargetInfo();
|
||||
void writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
|
||||
uint64_t PltEntryAddr) const override;
|
||||
bool relocNeedsGot(uint32_t Type) const override;
|
||||
bool relocNeedsPlt(uint32_t Type) const override;
|
||||
};
|
||||
|
||||
extern std::unique_ptr<TargetInfo> Target;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -11,6 +11,7 @@
|
|||
#include "Config.h"
|
||||
#include "OutputSections.h"
|
||||
#include "SymbolTable.h"
|
||||
#include "Target.h"
|
||||
|
||||
#include "llvm/Support/FileOutputBuffer.h"
|
||||
|
||||
|
@ -256,12 +257,12 @@ void Writer<ELFT>::scanRelocs(
|
|||
if (!S)
|
||||
continue;
|
||||
uint32_t Type = RI.getType(IsMips64EL);
|
||||
if (relocNeedsPLT(Type)) {
|
||||
if (Target->relocNeedsPlt(Type)) {
|
||||
if (Body->isInPlt())
|
||||
continue;
|
||||
PltSec.addEntry(Body);
|
||||
}
|
||||
if (relocNeedsGOT(Type)) {
|
||||
if (Target->relocNeedsGot(Type)) {
|
||||
if (Body->isInGot())
|
||||
continue;
|
||||
GotSec.addEntry(Body);
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t.o
|
||||
// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %p/Inputs/shared.s -o %t2.o
|
||||
// RUN: lld -flavor gnu2 -shared %t2.o -o %t2.so
|
||||
// RUN: lld -flavor gnu2 %t.o %t2.so -o %t
|
||||
// RUN: llvm-readobj -s -r %t | FileCheck %s
|
||||
// RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASM %s
|
||||
// REQUIRES: x86
|
||||
|
||||
// CHECK: Name: .plt
|
||||
// CHECK-NEXT: Type: SHT_PROGBITS
|
||||
// CHECK-NEXT: Flags [
|
||||
// CHECK-NEXT: SHF_ALLOC
|
||||
// CHECK-NEXT: SHF_EXECINSTR
|
||||
// CHECK-NEXT: ]
|
||||
// CHECK-NEXT: Address: 0x16000
|
||||
// CHECK-NEXT: Offset:
|
||||
// CHECK-NEXT: Size: 16
|
||||
// CHECK-NEXT: Link: 0
|
||||
// CHECK-NEXT: Info: 0
|
||||
// CHECK-NEXT: AddressAlignment: 16
|
||||
|
||||
// CHECK: Relocations [
|
||||
// CHECK-NEXT: Section ({{.*}}) .rel.dyn {
|
||||
// CHECK-NEXT: 0x15000 R_386_GLOB_DAT bar 0x0
|
||||
// CHECK-NEXT: 0x15004 R_386_GLOB_DAT zed 0x0
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: ]
|
||||
|
||||
// Unfortunately FileCheck can't do math, so we have to check for explicit
|
||||
// values:
|
||||
|
||||
// 0x16000 - (0x11000 + 1) - 4 = 20475
|
||||
// 0x16000 - (0x11005 + 1) - 4 = 20470
|
||||
// 0x16008 - (0x1100a + 1) - 4 = 20473
|
||||
|
||||
// DISASM: _start:
|
||||
// DISASM-NEXT: 11000: e9 fb 4f 00 00 jmp 20475
|
||||
// DISASM-NEXT: 11005: e9 f6 4f 00 00 jmp 20470
|
||||
// DISASM-NEXT: 1100a: e9 f9 4f 00 00 jmp 20473
|
||||
|
||||
// 0x15000 = 86016
|
||||
// 0x15004 = 86020
|
||||
|
||||
// DISASM: Disassembly of section .plt:
|
||||
// DISASM-NEXT: .plt:
|
||||
// DISASM-NEXT: 16000: ff 25 00 50 01 00 jmpl *86016
|
||||
// DISASM-NEXT: 16006: 90 nop
|
||||
// DISASM-NEXT: 16007: 90 nop
|
||||
// DISASM-NEXT: 16008: ff 25 04 50 01 00 jmpl *86020
|
||||
// DISASM-NEXT: 1600e: 90 nop
|
||||
// DISASM-NEXT: 1600f: 90 nop
|
||||
|
||||
.global _start
|
||||
_start:
|
||||
jmp bar@PLT
|
||||
jmp bar@PLT
|
||||
jmp zed@PLT
|
Loading…
Reference in New Issue