Imported Upstream version 6.10.0.49

Former-commit-id: 1d6753294b2993e1fbf92de9366bb9544db4189b
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2020-01-16 16:38:04 +00:00
parent d94e79959b
commit 468663ddbb
48518 changed files with 2789335 additions and 61176 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,52 @@
//===- AArch64ErrataFix.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_AARCH64ERRATAFIX_H
#define LLD_ELF_AARCH64ERRATAFIX_H
#include "lld/Common/LLVM.h"
#include <map>
#include <vector>
namespace lld {
namespace elf {
class Defined;
class InputSection;
struct InputSectionDescription;
class OutputSection;
class Patch843419Section;
class AArch64Err843419Patcher {
public:
// return true if Patches have been added to the OutputSections.
bool createFixes();
private:
std::vector<Patch843419Section *>
patchInputSectionDescription(InputSectionDescription &ISD);
void insertPatches(InputSectionDescription &ISD,
std::vector<Patch843419Section *> &Patches);
void init();
// A cache of the mapping symbols defined by the InputSecion sorted in order
// of ascending value with redundant symbols removed. These describe
// the ranges of code and data in an executable InputSection.
std::map<InputSection *, std::vector<const Defined *>> SectionMap;
bool Initialized = false;
};
} // namespace elf
} // namespace lld
#endif

View File

@@ -0,0 +1,426 @@
//===- AArch64.cpp --------------------------------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
#include "Thunks.h"
#include "lld/Common/ErrorHandler.h"
#include "llvm/Object/ELF.h"
#include "llvm/Support/Endian.h"
using namespace llvm;
using namespace llvm::support::endian;
using namespace llvm::ELF;
using namespace lld;
using namespace lld::elf;
// Page(Expr) is the page address of the expression Expr, defined
// as (Expr & ~0xFFF). (This applies even if the machine page size
// supported by the platform has a different value.)
uint64_t elf::getAArch64Page(uint64_t Expr) {
return Expr & ~static_cast<uint64_t>(0xFFF);
}
namespace {
class AArch64 final : public TargetInfo {
public:
AArch64();
RelExpr getRelExpr(RelType Type, const Symbol &S,
const uint8_t *Loc) const override;
bool isPicRel(RelType Type) const override;
void writeGotPlt(uint8_t *Buf, const Symbol &S) const override;
void writePltHeader(uint8_t *Buf) const override;
void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
int32_t Index, unsigned RelOff) const override;
bool needsThunk(RelExpr Expr, RelType Type, const InputFile *File,
uint64_t BranchAddr, const Symbol &S) const override;
bool inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const override;
bool usesOnlyLowPageBits(RelType Type) const override;
void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override;
RelExpr adjustRelaxExpr(RelType Type, const uint8_t *Data,
RelExpr Expr) const override;
void relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
void relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
void relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
};
} // namespace
AArch64::AArch64() {
CopyRel = R_AARCH64_COPY;
RelativeRel = R_AARCH64_RELATIVE;
IRelativeRel = R_AARCH64_IRELATIVE;
GotRel = R_AARCH64_GLOB_DAT;
PltRel = R_AARCH64_JUMP_SLOT;
TlsDescRel = R_AARCH64_TLSDESC;
TlsGotRel = R_AARCH64_TLS_TPREL64;
GotEntrySize = 8;
GotPltEntrySize = 8;
PltEntrySize = 16;
PltHeaderSize = 32;
DefaultMaxPageSize = 65536;
// It doesn't seem to be documented anywhere, but tls on aarch64 uses variant
// 1 of the tls structures and the tcb size is 16.
TcbSize = 16;
NeedsThunks = true;
// See comment in Arch/ARM.cpp for a more detailed explanation of
// ThunkSectionSpacing. For AArch64 the only branches we are permitted to
// Thunk have a range of +/- 128 MiB
ThunkSectionSpacing = (128 * 1024 * 1024) - 0x30000;
}
RelExpr AArch64::getRelExpr(RelType Type, const Symbol &S,
const uint8_t *Loc) const {
switch (Type) {
case R_AARCH64_TLSDESC_ADR_PAGE21:
return R_TLSDESC_PAGE;
case R_AARCH64_TLSDESC_LD64_LO12:
case R_AARCH64_TLSDESC_ADD_LO12:
return R_TLSDESC;
case R_AARCH64_TLSDESC_CALL:
return R_TLSDESC_CALL;
case R_AARCH64_TLSLE_ADD_TPREL_HI12:
case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
return R_TLS;
case R_AARCH64_CALL26:
case R_AARCH64_CONDBR19:
case R_AARCH64_JUMP26:
case R_AARCH64_TSTBR14:
return R_PLT_PC;
case R_AARCH64_PREL16:
case R_AARCH64_PREL32:
case R_AARCH64_PREL64:
case R_AARCH64_ADR_PREL_LO21:
case R_AARCH64_LD_PREL_LO19:
return R_PC;
case R_AARCH64_ADR_PREL_PG_HI21:
return R_PAGE_PC;
case R_AARCH64_LD64_GOT_LO12_NC:
case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
return R_GOT;
case R_AARCH64_ADR_GOT_PAGE:
case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
return R_GOT_PAGE_PC;
case R_AARCH64_NONE:
return R_NONE;
default:
return R_ABS;
}
}
RelExpr AArch64::adjustRelaxExpr(RelType Type, const uint8_t *Data,
RelExpr Expr) const {
if (Expr == R_RELAX_TLS_GD_TO_IE) {
if (Type == R_AARCH64_TLSDESC_ADR_PAGE21)
return R_RELAX_TLS_GD_TO_IE_PAGE_PC;
return R_RELAX_TLS_GD_TO_IE_ABS;
}
return Expr;
}
bool AArch64::usesOnlyLowPageBits(RelType Type) const {
switch (Type) {
default:
return false;
case R_AARCH64_ADD_ABS_LO12_NC:
case R_AARCH64_LD64_GOT_LO12_NC:
case R_AARCH64_LDST128_ABS_LO12_NC:
case R_AARCH64_LDST16_ABS_LO12_NC:
case R_AARCH64_LDST32_ABS_LO12_NC:
case R_AARCH64_LDST64_ABS_LO12_NC:
case R_AARCH64_LDST8_ABS_LO12_NC:
case R_AARCH64_TLSDESC_ADD_LO12:
case R_AARCH64_TLSDESC_LD64_LO12:
case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
return true;
}
}
bool AArch64::isPicRel(RelType Type) const {
return Type == R_AARCH64_ABS32 || Type == R_AARCH64_ABS64;
}
void AArch64::writeGotPlt(uint8_t *Buf, const Symbol &) const {
write64le(Buf, InX::Plt->getVA());
}
void AArch64::writePltHeader(uint8_t *Buf) const {
const uint8_t PltData[] = {
0xf0, 0x7b, 0xbf, 0xa9, // stp x16, x30, [sp,#-16]!
0x10, 0x00, 0x00, 0x90, // adrp x16, Page(&(.plt.got[2]))
0x11, 0x02, 0x40, 0xf9, // ldr x17, [x16, Offset(&(.plt.got[2]))]
0x10, 0x02, 0x00, 0x91, // add x16, x16, Offset(&(.plt.got[2]))
0x20, 0x02, 0x1f, 0xd6, // br x17
0x1f, 0x20, 0x03, 0xd5, // nop
0x1f, 0x20, 0x03, 0xd5, // nop
0x1f, 0x20, 0x03, 0xd5 // nop
};
memcpy(Buf, PltData, sizeof(PltData));
uint64_t Got = InX::GotPlt->getVA();
uint64_t Plt = InX::Plt->getVA();
relocateOne(Buf + 4, R_AARCH64_ADR_PREL_PG_HI21,
getAArch64Page(Got + 16) - getAArch64Page(Plt + 4));
relocateOne(Buf + 8, R_AARCH64_LDST64_ABS_LO12_NC, Got + 16);
relocateOne(Buf + 12, R_AARCH64_ADD_ABS_LO12_NC, Got + 16);
}
void AArch64::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
uint64_t PltEntryAddr, int32_t Index,
unsigned RelOff) const {
const uint8_t Inst[] = {
0x10, 0x00, 0x00, 0x90, // adrp x16, Page(&(.plt.got[n]))
0x11, 0x02, 0x40, 0xf9, // ldr x17, [x16, Offset(&(.plt.got[n]))]
0x10, 0x02, 0x00, 0x91, // add x16, x16, Offset(&(.plt.got[n]))
0x20, 0x02, 0x1f, 0xd6 // br x17
};
memcpy(Buf, Inst, sizeof(Inst));
relocateOne(Buf, R_AARCH64_ADR_PREL_PG_HI21,
getAArch64Page(GotPltEntryAddr) - getAArch64Page(PltEntryAddr));
relocateOne(Buf + 4, R_AARCH64_LDST64_ABS_LO12_NC, GotPltEntryAddr);
relocateOne(Buf + 8, R_AARCH64_ADD_ABS_LO12_NC, GotPltEntryAddr);
}
bool AArch64::needsThunk(RelExpr Expr, RelType Type, const InputFile *File,
uint64_t BranchAddr, const Symbol &S) const {
// ELF for the ARM 64-bit architecture, section Call and Jump relocations
// only permits range extension thunks for R_AARCH64_CALL26 and
// R_AARCH64_JUMP26 relocation types.
if (Type != R_AARCH64_CALL26 && Type != R_AARCH64_JUMP26)
return false;
uint64_t Dst = (Expr == R_PLT_PC) ? S.getPltVA() : S.getVA();
return !inBranchRange(Type, BranchAddr, Dst);
}
bool AArch64::inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const {
if (Type != R_AARCH64_CALL26 && Type != R_AARCH64_JUMP26)
return true;
// The AArch64 call and unconditional branch instructions have a range of
// +/- 128 MiB.
uint64_t Range = 128 * 1024 * 1024;
if (Dst > Src) {
// Immediate of branch is signed.
Range -= 4;
return Dst - Src <= Range;
}
return Src - Dst <= Range;
}
static void write32AArch64Addr(uint8_t *L, uint64_t Imm) {
uint32_t ImmLo = (Imm & 0x3) << 29;
uint32_t ImmHi = (Imm & 0x1FFFFC) << 3;
uint64_t Mask = (0x3 << 29) | (0x1FFFFC << 3);
write32le(L, (read32le(L) & ~Mask) | ImmLo | ImmHi);
}
// Return the bits [Start, End] from Val shifted Start bits.
// For instance, getBits(0xF0, 4, 8) returns 0xF.
static uint64_t getBits(uint64_t Val, int Start, int End) {
uint64_t Mask = ((uint64_t)1 << (End + 1 - Start)) - 1;
return (Val >> Start) & Mask;
}
static void or32le(uint8_t *P, int32_t V) { write32le(P, read32le(P) | V); }
// Update the immediate field in a AARCH64 ldr, str, and add instruction.
static void or32AArch64Imm(uint8_t *L, uint64_t Imm) {
or32le(L, (Imm & 0xFFF) << 10);
}
void AArch64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
switch (Type) {
case R_AARCH64_ABS16:
case R_AARCH64_PREL16:
checkIntUInt<16>(Loc, Val, Type);
write16le(Loc, Val);
break;
case R_AARCH64_ABS32:
case R_AARCH64_PREL32:
checkIntUInt<32>(Loc, Val, Type);
write32le(Loc, Val);
break;
case R_AARCH64_ABS64:
case R_AARCH64_GLOB_DAT:
case R_AARCH64_PREL64:
write64le(Loc, Val);
break;
case R_AARCH64_ADD_ABS_LO12_NC:
or32AArch64Imm(Loc, Val);
break;
case R_AARCH64_ADR_GOT_PAGE:
case R_AARCH64_ADR_PREL_PG_HI21:
case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
case R_AARCH64_TLSDESC_ADR_PAGE21:
checkInt<33>(Loc, Val, Type);
write32AArch64Addr(Loc, Val >> 12);
break;
case R_AARCH64_ADR_PREL_LO21:
checkInt<21>(Loc, Val, Type);
write32AArch64Addr(Loc, Val);
break;
case R_AARCH64_JUMP26:
// Normally we would just write the bits of the immediate field, however
// when patching instructions for the cpu errata fix -fix-cortex-a53-843419
// we want to replace a non-branch instruction with a branch immediate
// instruction. By writing all the bits of the instruction including the
// opcode and the immediate (0 001 | 01 imm26) we can do this
// transformation by placing a R_AARCH64_JUMP26 relocation at the offset of
// the instruction we want to patch.
write32le(Loc, 0x14000000);
LLVM_FALLTHROUGH;
case R_AARCH64_CALL26:
checkInt<28>(Loc, Val, Type);
or32le(Loc, (Val & 0x0FFFFFFC) >> 2);
break;
case R_AARCH64_CONDBR19:
case R_AARCH64_LD_PREL_LO19:
checkAlignment<4>(Loc, Val, Type);
checkInt<21>(Loc, Val, Type);
or32le(Loc, (Val & 0x1FFFFC) << 3);
break;
case R_AARCH64_LD64_GOT_LO12_NC:
case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
case R_AARCH64_TLSDESC_LD64_LO12:
checkAlignment<8>(Loc, Val, Type);
or32le(Loc, (Val & 0xFF8) << 7);
break;
case R_AARCH64_LDST8_ABS_LO12_NC:
or32AArch64Imm(Loc, getBits(Val, 0, 11));
break;
case R_AARCH64_LDST16_ABS_LO12_NC:
checkAlignment<2>(Loc, Val, Type);
or32AArch64Imm(Loc, getBits(Val, 1, 11));
break;
case R_AARCH64_LDST32_ABS_LO12_NC:
checkAlignment<4>(Loc, Val, Type);
or32AArch64Imm(Loc, getBits(Val, 2, 11));
break;
case R_AARCH64_LDST64_ABS_LO12_NC:
checkAlignment<8>(Loc, Val, Type);
or32AArch64Imm(Loc, getBits(Val, 3, 11));
break;
case R_AARCH64_LDST128_ABS_LO12_NC:
checkAlignment<16>(Loc, Val, Type);
or32AArch64Imm(Loc, getBits(Val, 4, 11));
break;
case R_AARCH64_MOVW_UABS_G0_NC:
or32le(Loc, (Val & 0xFFFF) << 5);
break;
case R_AARCH64_MOVW_UABS_G1_NC:
or32le(Loc, (Val & 0xFFFF0000) >> 11);
break;
case R_AARCH64_MOVW_UABS_G2_NC:
or32le(Loc, (Val & 0xFFFF00000000) >> 27);
break;
case R_AARCH64_MOVW_UABS_G3:
or32le(Loc, (Val & 0xFFFF000000000000) >> 43);
break;
case R_AARCH64_TSTBR14:
checkInt<16>(Loc, Val, Type);
or32le(Loc, (Val & 0xFFFC) << 3);
break;
case R_AARCH64_TLSLE_ADD_TPREL_HI12:
checkInt<24>(Loc, Val, Type);
or32AArch64Imm(Loc, Val >> 12);
break;
case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
case R_AARCH64_TLSDESC_ADD_LO12:
or32AArch64Imm(Loc, Val);
break;
default:
error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
}
}
void AArch64::relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
// TLSDESC Global-Dynamic relocation are in the form:
// adrp x0, :tlsdesc:v [R_AARCH64_TLSDESC_ADR_PAGE21]
// ldr x1, [x0, #:tlsdesc_lo12:v [R_AARCH64_TLSDESC_LD64_LO12]
// add x0, x0, :tlsdesc_los:v [R_AARCH64_TLSDESC_ADD_LO12]
// .tlsdesccall [R_AARCH64_TLSDESC_CALL]
// blr x1
// And it can optimized to:
// movz x0, #0x0, lsl #16
// movk x0, #0x10
// nop
// nop
checkUInt<32>(Loc, Val, Type);
switch (Type) {
case R_AARCH64_TLSDESC_ADD_LO12:
case R_AARCH64_TLSDESC_CALL:
write32le(Loc, 0xd503201f); // nop
return;
case R_AARCH64_TLSDESC_ADR_PAGE21:
write32le(Loc, 0xd2a00000 | (((Val >> 16) & 0xffff) << 5)); // movz
return;
case R_AARCH64_TLSDESC_LD64_LO12:
write32le(Loc, 0xf2800000 | ((Val & 0xffff) << 5)); // movk
return;
default:
llvm_unreachable("unsupported relocation for TLS GD to LE relaxation");
}
}
void AArch64::relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const {
// TLSDESC Global-Dynamic relocation are in the form:
// adrp x0, :tlsdesc:v [R_AARCH64_TLSDESC_ADR_PAGE21]
// ldr x1, [x0, #:tlsdesc_lo12:v [R_AARCH64_TLSDESC_LD64_LO12]
// add x0, x0, :tlsdesc_los:v [R_AARCH64_TLSDESC_ADD_LO12]
// .tlsdesccall [R_AARCH64_TLSDESC_CALL]
// blr x1
// And it can optimized to:
// adrp x0, :gottprel:v
// ldr x0, [x0, :gottprel_lo12:v]
// nop
// nop
switch (Type) {
case R_AARCH64_TLSDESC_ADD_LO12:
case R_AARCH64_TLSDESC_CALL:
write32le(Loc, 0xd503201f); // nop
break;
case R_AARCH64_TLSDESC_ADR_PAGE21:
write32le(Loc, 0x90000000); // adrp
relocateOne(Loc, R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21, Val);
break;
case R_AARCH64_TLSDESC_LD64_LO12:
write32le(Loc, 0xf9400000); // ldr
relocateOne(Loc, R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC, Val);
break;
default:
llvm_unreachable("unsupported relocation for TLS GD to LE relaxation");
}
}
void AArch64::relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
checkUInt<32>(Loc, Val, Type);
if (Type == R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21) {
// Generate MOVZ.
uint32_t RegNo = read32le(Loc) & 0x1f;
write32le(Loc, (0xd2a00000 | RegNo) | (((Val >> 16) & 0xffff) << 5));
return;
}
if (Type == R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC) {
// Generate MOVK.
uint32_t RegNo = read32le(Loc) & 0x1f;
write32le(Loc, (0xf2800000 | RegNo) | ((Val & 0xffff) << 5));
return;
}
llvm_unreachable("invalid relocation for TLS IE to LE relaxation");
}
TargetInfo *elf::getAArch64TargetInfo() {
static AArch64 Target;
return &Target;
}

View File

@@ -0,0 +1,102 @@
//===- AMDGPU.cpp ---------------------------------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "InputFiles.h"
#include "Symbols.h"
#include "Target.h"
#include "lld/Common/ErrorHandler.h"
#include "llvm/Object/ELF.h"
#include "llvm/Support/Endian.h"
using namespace llvm;
using namespace llvm::object;
using namespace llvm::support::endian;
using namespace llvm::ELF;
using namespace lld;
using namespace lld::elf;
namespace {
class AMDGPU final : public TargetInfo {
public:
AMDGPU();
uint32_t calcEFlags() const override;
void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override;
RelExpr getRelExpr(RelType Type, const Symbol &S,
const uint8_t *Loc) const override;
};
} // namespace
AMDGPU::AMDGPU() {
RelativeRel = R_AMDGPU_RELATIVE64;
GotRel = R_AMDGPU_ABS64;
GotEntrySize = 8;
}
static uint32_t getEFlags(InputFile *File) {
return cast<ObjFile<ELF64LE>>(File)->getObj().getHeader()->e_flags;
}
uint32_t AMDGPU::calcEFlags() const {
assert(!ObjectFiles.empty());
uint32_t Ret = getEFlags(ObjectFiles[0]);
// Verify that all input files have the same e_flags.
for (InputFile *F : makeArrayRef(ObjectFiles).slice(1)) {
if (Ret == getEFlags(F))
continue;
error("incompatible e_flags: " + toString(F));
return 0;
}
return Ret;
}
void AMDGPU::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
switch (Type) {
case R_AMDGPU_ABS32:
case R_AMDGPU_GOTPCREL:
case R_AMDGPU_GOTPCREL32_LO:
case R_AMDGPU_REL32:
case R_AMDGPU_REL32_LO:
write32le(Loc, Val);
break;
case R_AMDGPU_ABS64:
write64le(Loc, Val);
break;
case R_AMDGPU_GOTPCREL32_HI:
case R_AMDGPU_REL32_HI:
write32le(Loc, Val >> 32);
break;
default:
error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
}
}
RelExpr AMDGPU::getRelExpr(RelType Type, const Symbol &S,
const uint8_t *Loc) const {
switch (Type) {
case R_AMDGPU_ABS32:
case R_AMDGPU_ABS64:
return R_ABS;
case R_AMDGPU_REL32:
case R_AMDGPU_REL32_LO:
case R_AMDGPU_REL32_HI:
return R_PC;
case R_AMDGPU_GOTPCREL:
case R_AMDGPU_GOTPCREL32_LO:
case R_AMDGPU_GOTPCREL32_HI:
return R_GOT_PC;
default:
return R_INVALID;
}
}
TargetInfo *elf::getAMDGPUTargetInfo() {
static AMDGPU Target;
return &Target;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,74 @@
//===- AVR.cpp ------------------------------------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// AVR is a Harvard-architecture 8-bit micrcontroller designed for small
// baremetal programs. All AVR-family processors have 32 8-bit registers.
// The tiniest AVR has 32 byte RAM and 1 KiB program memory, and the largest
// one supports up to 2^24 data address space and 2^22 code address space.
//
// Since it is a baremetal programming, there's usually no loader to load
// ELF files on AVRs. You are expected to link your program against address
// 0 and pull out a .text section from the result using objcopy, so that you
// can write the linked code to on-chip flush memory. You can do that with
// the following commands:
//
// ld.lld -Ttext=0 -o foo foo.o
// objcopy -O binary --only-section=.text foo output.bin
//
// Note that the current AVR support is very preliminary so you can't
// link any useful program yet, though.
//
//===----------------------------------------------------------------------===//
#include "InputFiles.h"
#include "Symbols.h"
#include "Target.h"
#include "lld/Common/ErrorHandler.h"
#include "llvm/Object/ELF.h"
#include "llvm/Support/Endian.h"
using namespace llvm;
using namespace llvm::object;
using namespace llvm::support::endian;
using namespace llvm::ELF;
using namespace lld;
using namespace lld::elf;
namespace {
class AVR final : public TargetInfo {
public:
RelExpr getRelExpr(RelType Type, const Symbol &S,
const uint8_t *Loc) const override;
void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override;
};
} // namespace
RelExpr AVR::getRelExpr(RelType Type, const Symbol &S,
const uint8_t *Loc) const {
return R_ABS;
}
void AVR::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
switch (Type) {
case R_AVR_CALL: {
uint16_t Hi = Val >> 17;
uint16_t Lo = Val >> 1;
write16le(Loc, read16le(Loc) | ((Hi >> 1) << 4) | (Hi & 1));
write16le(Loc + 2, Lo);
break;
}
default:
error(getErrorLocation(Loc) + "unrecognized reloc " + toString(Type));
}
}
TargetInfo *elf::getAVRTargetInfo() {
static AVR Target;
return &Target;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,383 @@
//===- MipsArchTree.cpp --------------------------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===---------------------------------------------------------------------===//
//
// This file contains a helper function for the Writer.
//
//===---------------------------------------------------------------------===//
#include "InputFiles.h"
#include "SymbolTable.h"
#include "Writer.h"
#include "lld/Common/ErrorHandler.h"
#include "llvm/BinaryFormat/ELF.h"
#include "llvm/Object/ELF.h"
#include "llvm/Support/MipsABIFlags.h"
using namespace llvm;
using namespace llvm::object;
using namespace llvm::ELF;
using namespace lld;
using namespace lld::elf;
namespace {
struct ArchTreeEdge {
uint32_t Child;
uint32_t Parent;
};
struct FileFlags {
InputFile *File;
uint32_t Flags;
};
} // namespace
static StringRef getAbiName(uint32_t Flags) {
switch (Flags) {
case 0:
return "n64";
case EF_MIPS_ABI2:
return "n32";
case EF_MIPS_ABI_O32:
return "o32";
case EF_MIPS_ABI_O64:
return "o64";
case EF_MIPS_ABI_EABI32:
return "eabi32";
case EF_MIPS_ABI_EABI64:
return "eabi64";
default:
return "unknown";
}
}
static StringRef getNanName(bool IsNan2008) {
return IsNan2008 ? "2008" : "legacy";
}
static StringRef getFpName(bool IsFp64) { return IsFp64 ? "64" : "32"; }
static void checkFlags(ArrayRef<FileFlags> Files) {
uint32_t ABI = Files[0].Flags & (EF_MIPS_ABI | EF_MIPS_ABI2);
bool Nan = Files[0].Flags & EF_MIPS_NAN2008;
bool Fp = Files[0].Flags & EF_MIPS_FP64;
for (const FileFlags &F : Files.slice(1)) {
uint32_t ABI2 = F.Flags & (EF_MIPS_ABI | EF_MIPS_ABI2);
if (ABI != ABI2)
error("target ABI '" + getAbiName(ABI) + "' is incompatible with '" +
getAbiName(ABI2) + "': " + toString(F.File));
bool Nan2 = F.Flags & EF_MIPS_NAN2008;
if (Nan != Nan2)
error("target -mnan=" + getNanName(Nan) + " is incompatible with -mnan=" +
getNanName(Nan2) + ": " + toString(F.File));
bool Fp2 = F.Flags & EF_MIPS_FP64;
if (Fp != Fp2)
error("target -mfp" + getFpName(Fp) + " is incompatible with -mfp" +
getFpName(Fp2) + ": " + toString(F.File));
}
}
static uint32_t getMiscFlags(ArrayRef<FileFlags> Files) {
uint32_t Ret = 0;
for (const FileFlags &F : Files)
Ret |= F.Flags &
(EF_MIPS_ABI | EF_MIPS_ABI2 | EF_MIPS_ARCH_ASE | EF_MIPS_NOREORDER |
EF_MIPS_MICROMIPS | EF_MIPS_NAN2008 | EF_MIPS_32BITMODE);
return Ret;
}
static uint32_t getPicFlags(ArrayRef<FileFlags> Files) {
// Check PIC/non-PIC compatibility.
bool IsPic = Files[0].Flags & (EF_MIPS_PIC | EF_MIPS_CPIC);
for (const FileFlags &F : Files.slice(1)) {
bool IsPic2 = F.Flags & (EF_MIPS_PIC | EF_MIPS_CPIC);
if (IsPic && !IsPic2)
warn("linking abicalls code " + toString(Files[0].File) +
" with non-abicalls file: " + toString(F.File));
if (!IsPic && IsPic2)
warn("linking non-abicalls code " + toString(Files[0].File) +
" with abicalls file: " + toString(F.File));
}
// Compute the result PIC/non-PIC flag.
uint32_t Ret = Files[0].Flags & (EF_MIPS_PIC | EF_MIPS_CPIC);
for (const FileFlags &F : Files.slice(1))
Ret &= F.Flags & (EF_MIPS_PIC | EF_MIPS_CPIC);
// PIC code is inherently CPIC and may not set CPIC flag explicitly.
if (Ret & EF_MIPS_PIC)
Ret |= EF_MIPS_CPIC;
return Ret;
}
static ArchTreeEdge ArchTree[] = {
// MIPS32R6 and MIPS64R6 are not compatible with other extensions
// MIPS64R2 extensions.
{EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON3, EF_MIPS_ARCH_64R2},
{EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON2, EF_MIPS_ARCH_64R2},
{EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON, EF_MIPS_ARCH_64R2},
{EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_LS3A, EF_MIPS_ARCH_64R2},
// MIPS64 extensions.
{EF_MIPS_ARCH_64 | EF_MIPS_MACH_SB1, EF_MIPS_ARCH_64},
{EF_MIPS_ARCH_64 | EF_MIPS_MACH_XLR, EF_MIPS_ARCH_64},
{EF_MIPS_ARCH_64R2, EF_MIPS_ARCH_64},
// MIPS V extensions.
{EF_MIPS_ARCH_64, EF_MIPS_ARCH_5},
// R5000 extensions.
{EF_MIPS_ARCH_4 | EF_MIPS_MACH_5500, EF_MIPS_ARCH_4 | EF_MIPS_MACH_5400},
// MIPS IV extensions.
{EF_MIPS_ARCH_4 | EF_MIPS_MACH_5400, EF_MIPS_ARCH_4},
{EF_MIPS_ARCH_4 | EF_MIPS_MACH_9000, EF_MIPS_ARCH_4},
{EF_MIPS_ARCH_5, EF_MIPS_ARCH_4},
// VR4100 extensions.
{EF_MIPS_ARCH_3 | EF_MIPS_MACH_4111, EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100},
{EF_MIPS_ARCH_3 | EF_MIPS_MACH_4120, EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100},
// MIPS III extensions.
{EF_MIPS_ARCH_3 | EF_MIPS_MACH_4010, EF_MIPS_ARCH_3},
{EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100, EF_MIPS_ARCH_3},
{EF_MIPS_ARCH_3 | EF_MIPS_MACH_4650, EF_MIPS_ARCH_3},
{EF_MIPS_ARCH_3 | EF_MIPS_MACH_5900, EF_MIPS_ARCH_3},
{EF_MIPS_ARCH_3 | EF_MIPS_MACH_LS2E, EF_MIPS_ARCH_3},
{EF_MIPS_ARCH_3 | EF_MIPS_MACH_LS2F, EF_MIPS_ARCH_3},
{EF_MIPS_ARCH_4, EF_MIPS_ARCH_3},
// MIPS32 extensions.
{EF_MIPS_ARCH_32R2, EF_MIPS_ARCH_32},
// MIPS II extensions.
{EF_MIPS_ARCH_3, EF_MIPS_ARCH_2},
{EF_MIPS_ARCH_32, EF_MIPS_ARCH_2},
// MIPS I extensions.
{EF_MIPS_ARCH_1 | EF_MIPS_MACH_3900, EF_MIPS_ARCH_1},
{EF_MIPS_ARCH_2, EF_MIPS_ARCH_1},
};
static bool isArchMatched(uint32_t New, uint32_t Res) {
if (New == Res)
return true;
if (New == EF_MIPS_ARCH_32 && isArchMatched(EF_MIPS_ARCH_64, Res))
return true;
if (New == EF_MIPS_ARCH_32R2 && isArchMatched(EF_MIPS_ARCH_64R2, Res))
return true;
for (const auto &Edge : ArchTree) {
if (Res == Edge.Child) {
Res = Edge.Parent;
if (Res == New)
return true;
}
}
return false;
}
static StringRef getMachName(uint32_t Flags) {
switch (Flags & EF_MIPS_MACH) {
case EF_MIPS_MACH_NONE:
return "";
case EF_MIPS_MACH_3900:
return "r3900";
case EF_MIPS_MACH_4010:
return "r4010";
case EF_MIPS_MACH_4100:
return "r4100";
case EF_MIPS_MACH_4650:
return "r4650";
case EF_MIPS_MACH_4120:
return "r4120";
case EF_MIPS_MACH_4111:
return "r4111";
case EF_MIPS_MACH_5400:
return "vr5400";
case EF_MIPS_MACH_5900:
return "vr5900";
case EF_MIPS_MACH_5500:
return "vr5500";
case EF_MIPS_MACH_9000:
return "rm9000";
case EF_MIPS_MACH_LS2E:
return "loongson2e";
case EF_MIPS_MACH_LS2F:
return "loongson2f";
case EF_MIPS_MACH_LS3A:
return "loongson3a";
case EF_MIPS_MACH_OCTEON:
return "octeon";
case EF_MIPS_MACH_OCTEON2:
return "octeon2";
case EF_MIPS_MACH_OCTEON3:
return "octeon3";
case EF_MIPS_MACH_SB1:
return "sb1";
case EF_MIPS_MACH_XLR:
return "xlr";
default:
return "unknown machine";
}
}
static StringRef getArchName(uint32_t Flags) {
switch (Flags & EF_MIPS_ARCH) {
case EF_MIPS_ARCH_1:
return "mips1";
case EF_MIPS_ARCH_2:
return "mips2";
case EF_MIPS_ARCH_3:
return "mips3";
case EF_MIPS_ARCH_4:
return "mips4";
case EF_MIPS_ARCH_5:
return "mips5";
case EF_MIPS_ARCH_32:
return "mips32";
case EF_MIPS_ARCH_64:
return "mips64";
case EF_MIPS_ARCH_32R2:
return "mips32r2";
case EF_MIPS_ARCH_64R2:
return "mips64r2";
case EF_MIPS_ARCH_32R6:
return "mips32r6";
case EF_MIPS_ARCH_64R6:
return "mips64r6";
default:
return "unknown arch";
}
}
static std::string getFullArchName(uint32_t Flags) {
StringRef Arch = getArchName(Flags);
StringRef Mach = getMachName(Flags);
if (Mach.empty())
return Arch.str();
return (Arch + " (" + Mach + ")").str();
}
// There are (arguably too) many MIPS ISAs out there. Their relationships
// can be represented as a forest. If all input files have ISAs which
// reachable by repeated proceeding from the single child to the parent,
// these input files are compatible. In that case we need to return "highest"
// ISA. If there are incompatible input files, we show an error.
// For example, mips1 is a "parent" of mips2 and such files are compatible.
// Output file gets EF_MIPS_ARCH_2 flag. From the other side mips3 and mips32
// are incompatible because nor mips3 is a parent for misp32, nor mips32
// is a parent for mips3.
static uint32_t getArchFlags(ArrayRef<FileFlags> Files) {
uint32_t Ret = Files[0].Flags & (EF_MIPS_ARCH | EF_MIPS_MACH);
for (const FileFlags &F : Files.slice(1)) {
uint32_t New = F.Flags & (EF_MIPS_ARCH | EF_MIPS_MACH);
// Check ISA compatibility.
if (isArchMatched(New, Ret))
continue;
if (!isArchMatched(Ret, New)) {
error("incompatible target ISA:\n>>> " + toString(Files[0].File) + ": " +
getFullArchName(Ret) + "\n>>> " + toString(F.File) + ": " +
getFullArchName(New));
return 0;
}
Ret = New;
}
return Ret;
}
template <class ELFT> uint32_t elf::calcMipsEFlags() {
std::vector<FileFlags> V;
for (InputFile *F : ObjectFiles)
V.push_back({F, cast<ObjFile<ELFT>>(F)->getObj().getHeader()->e_flags});
if (V.empty())
return 0;
checkFlags(V);
return getMiscFlags(V) | getPicFlags(V) | getArchFlags(V);
}
static int compareMipsFpAbi(uint8_t FpA, uint8_t FpB) {
if (FpA == FpB)
return 0;
if (FpB == Mips::Val_GNU_MIPS_ABI_FP_ANY)
return 1;
if (FpB == Mips::Val_GNU_MIPS_ABI_FP_64A &&
FpA == Mips::Val_GNU_MIPS_ABI_FP_64)
return 1;
if (FpB != Mips::Val_GNU_MIPS_ABI_FP_XX)
return -1;
if (FpA == Mips::Val_GNU_MIPS_ABI_FP_DOUBLE ||
FpA == Mips::Val_GNU_MIPS_ABI_FP_64 ||
FpA == Mips::Val_GNU_MIPS_ABI_FP_64A)
return 1;
return -1;
}
static StringRef getMipsFpAbiName(uint8_t FpAbi) {
switch (FpAbi) {
case Mips::Val_GNU_MIPS_ABI_FP_ANY:
return "any";
case Mips::Val_GNU_MIPS_ABI_FP_DOUBLE:
return "-mdouble-float";
case Mips::Val_GNU_MIPS_ABI_FP_SINGLE:
return "-msingle-float";
case Mips::Val_GNU_MIPS_ABI_FP_SOFT:
return "-msoft-float";
case Mips::Val_GNU_MIPS_ABI_FP_OLD_64:
return "-mips32r2 -mfp64 (old)";
case Mips::Val_GNU_MIPS_ABI_FP_XX:
return "-mfpxx";
case Mips::Val_GNU_MIPS_ABI_FP_64:
return "-mgp32 -mfp64";
case Mips::Val_GNU_MIPS_ABI_FP_64A:
return "-mgp32 -mfp64 -mno-odd-spreg";
default:
return "unknown";
}
}
uint8_t elf::getMipsFpAbiFlag(uint8_t OldFlag, uint8_t NewFlag,
StringRef FileName) {
if (compareMipsFpAbi(NewFlag, OldFlag) >= 0)
return NewFlag;
if (compareMipsFpAbi(OldFlag, NewFlag) < 0)
error("target floating point ABI '" + getMipsFpAbiName(OldFlag) +
"' is incompatible with '" + getMipsFpAbiName(NewFlag) +
"': " + FileName);
return OldFlag;
}
template <class ELFT> static bool isN32Abi(const InputFile *F) {
if (auto *EF = dyn_cast<ELFFileBase<ELFT>>(F))
return EF->getObj().getHeader()->e_flags & EF_MIPS_ABI2;
return false;
}
bool elf::isMipsN32Abi(const InputFile *F) {
switch (Config->EKind) {
case ELF32LEKind:
return isN32Abi<ELF32LE>(F);
case ELF32BEKind:
return isN32Abi<ELF32BE>(F);
case ELF64LEKind:
return isN32Abi<ELF64LE>(F);
case ELF64BEKind:
return isN32Abi<ELF64BE>(F);
default:
llvm_unreachable("unknown Config->EKind");
}
}
bool elf::isMicroMips() { return Config->EFlags & EF_MIPS_MICROMIPS; }
bool elf::isMipsR6() {
uint32_t Arch = Config->EFlags & EF_MIPS_ARCH;
return Arch == EF_MIPS_ARCH_32R6 || Arch == EF_MIPS_ARCH_64R6;
}
template uint32_t elf::calcMipsEFlags<ELF32LE>();
template uint32_t elf::calcMipsEFlags<ELF32BE>();
template uint32_t elf::calcMipsEFlags<ELF64LE>();
template uint32_t elf::calcMipsEFlags<ELF64BE>();

View File

@@ -0,0 +1,71 @@
//===- PPC.cpp ------------------------------------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "Symbols.h"
#include "Target.h"
#include "lld/Common/ErrorHandler.h"
#include "llvm/Support/Endian.h"
using namespace llvm;
using namespace llvm::support::endian;
using namespace llvm::ELF;
using namespace lld;
using namespace lld::elf;
namespace {
class PPC final : public TargetInfo {
public:
PPC() { GotBaseSymOff = 0x8000; }
void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override;
RelExpr getRelExpr(RelType Type, const Symbol &S,
const uint8_t *Loc) const override;
};
} // namespace
RelExpr PPC::getRelExpr(RelType Type, const Symbol &S,
const uint8_t *Loc) const {
switch (Type) {
case R_PPC_REL24:
case R_PPC_REL32:
return R_PC;
case R_PPC_PLTREL24:
return R_PLT_PC;
default:
return R_ABS;
}
}
void PPC::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
switch (Type) {
case R_PPC_ADDR16_HA:
write16be(Loc, (Val + 0x8000) >> 16);
break;
case R_PPC_ADDR16_HI:
write16be(Loc, Val >> 16);
break;
case R_PPC_ADDR16_LO:
write16be(Loc, Val);
break;
case R_PPC_ADDR32:
case R_PPC_REL32:
write32be(Loc, Val);
break;
case R_PPC_PLTREL24:
case R_PPC_REL24:
write32be(Loc, read32be(Loc) | (Val & 0x3FFFFFC));
break;
default:
error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
}
}
TargetInfo *elf::getPPCTargetInfo() {
static PPC Target;
return &Target;
}

View File

@@ -0,0 +1,217 @@
//===- PPC64.cpp ----------------------------------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
#include "lld/Common/ErrorHandler.h"
#include "llvm/Support/Endian.h"
using namespace llvm;
using namespace llvm::support::endian;
using namespace llvm::ELF;
using namespace lld;
using namespace lld::elf;
static uint64_t PPC64TocOffset = 0x8000;
uint64_t elf::getPPC64TocBase() {
// The TOC consists of sections .got, .toc, .tocbss, .plt in that order. The
// TOC starts where the first of these sections starts. We always create a
// .got when we see a relocation that uses it, so for us the start is always
// the .got.
uint64_t TocVA = InX::Got->getVA();
// Per the ppc64-elf-linux ABI, The TOC base is TOC value plus 0x8000
// thus permitting a full 64 Kbytes segment. Note that the glibc startup
// code (crt1.o) assumes that you can get from the TOC base to the
// start of the .toc section with only a single (signed) 16-bit relocation.
return TocVA + PPC64TocOffset;
}
namespace {
class PPC64 final : public TargetInfo {
public:
PPC64();
RelExpr getRelExpr(RelType Type, const Symbol &S,
const uint8_t *Loc) const override;
void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
int32_t Index, unsigned RelOff) const override;
void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override;
};
} // namespace
// Relocation masks following the #lo(value), #hi(value), #ha(value),
// #higher(value), #highera(value), #highest(value), and #highesta(value)
// macros defined in section 4.5.1. Relocation Types of the PPC-elf64abi
// document.
static uint16_t applyPPCLo(uint64_t V) { return V; }
static uint16_t applyPPCHi(uint64_t V) { return V >> 16; }
static uint16_t applyPPCHa(uint64_t V) { return (V + 0x8000) >> 16; }
static uint16_t applyPPCHigher(uint64_t V) { return V >> 32; }
static uint16_t applyPPCHighera(uint64_t V) { return (V + 0x8000) >> 32; }
static uint16_t applyPPCHighest(uint64_t V) { return V >> 48; }
static uint16_t applyPPCHighesta(uint64_t V) { return (V + 0x8000) >> 48; }
PPC64::PPC64() {
PltRel = GotRel = R_PPC64_GLOB_DAT;
RelativeRel = R_PPC64_RELATIVE;
GotEntrySize = 8;
GotPltEntrySize = 8;
PltEntrySize = 32;
PltHeaderSize = 0;
// We need 64K pages (at least under glibc/Linux, the loader won't
// set different permissions on a finer granularity than that).
DefaultMaxPageSize = 65536;
// The PPC64 ELF ABI v1 spec, says:
//
// It is normally desirable to put segments with different characteristics
// in separate 256 Mbyte portions of the address space, to give the
// operating system full paging flexibility in the 64-bit address space.
//
// And because the lowest non-zero 256M boundary is 0x10000000, PPC64 linkers
// use 0x10000000 as the starting address.
DefaultImageBase = 0x10000000;
}
RelExpr PPC64::getRelExpr(RelType Type, const Symbol &S,
const uint8_t *Loc) const {
switch (Type) {
case R_PPC64_TOC16:
case R_PPC64_TOC16_DS:
case R_PPC64_TOC16_HA:
case R_PPC64_TOC16_HI:
case R_PPC64_TOC16_LO:
case R_PPC64_TOC16_LO_DS:
return R_GOTREL;
case R_PPC64_TOC:
return R_PPC_TOC;
case R_PPC64_REL24:
return R_PPC_PLT_OPD;
default:
return R_ABS;
}
}
void PPC64::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
uint64_t PltEntryAddr, int32_t Index,
unsigned RelOff) const {
uint64_t Off = GotPltEntryAddr - getPPC64TocBase();
// FIXME: What we should do, in theory, is get the offset of the function
// descriptor in the .opd section, and use that as the offset from %r2 (the
// TOC-base pointer). Instead, we have the GOT-entry offset, and that will
// be a pointer to the function descriptor in the .opd section. Using
// this scheme is simpler, but requires an extra indirection per PLT dispatch.
write32be(Buf, 0xf8410028); // std %r2, 40(%r1)
write32be(Buf + 4, 0x3d620000 | applyPPCHa(Off)); // addis %r11, %r2, X@ha
write32be(Buf + 8, 0xe98b0000 | applyPPCLo(Off)); // ld %r12, X@l(%r11)
write32be(Buf + 12, 0xe96c0000); // ld %r11,0(%r12)
write32be(Buf + 16, 0x7d6903a6); // mtctr %r11
write32be(Buf + 20, 0xe84c0008); // ld %r2,8(%r12)
write32be(Buf + 24, 0xe96c0010); // ld %r11,16(%r12)
write32be(Buf + 28, 0x4e800420); // bctr
}
static std::pair<RelType, uint64_t> toAddr16Rel(RelType Type, uint64_t Val) {
uint64_t V = Val - PPC64TocOffset;
switch (Type) {
case R_PPC64_TOC16:
return {R_PPC64_ADDR16, V};
case R_PPC64_TOC16_DS:
return {R_PPC64_ADDR16_DS, V};
case R_PPC64_TOC16_HA:
return {R_PPC64_ADDR16_HA, V};
case R_PPC64_TOC16_HI:
return {R_PPC64_ADDR16_HI, V};
case R_PPC64_TOC16_LO:
return {R_PPC64_ADDR16_LO, V};
case R_PPC64_TOC16_LO_DS:
return {R_PPC64_ADDR16_LO_DS, V};
default:
return {Type, Val};
}
}
void PPC64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
// For a TOC-relative relocation, proceed in terms of the corresponding
// ADDR16 relocation type.
std::tie(Type, Val) = toAddr16Rel(Type, Val);
switch (Type) {
case R_PPC64_ADDR14: {
checkAlignment<4>(Loc, Val, Type);
// Preserve the AA/LK bits in the branch instruction
uint8_t AALK = Loc[3];
write16be(Loc + 2, (AALK & 3) | (Val & 0xfffc));
break;
}
case R_PPC64_ADDR16:
checkInt<16>(Loc, Val, Type);
write16be(Loc, Val);
break;
case R_PPC64_ADDR16_DS:
checkInt<16>(Loc, Val, Type);
write16be(Loc, (read16be(Loc) & 3) | (Val & ~3));
break;
case R_PPC64_ADDR16_HA:
case R_PPC64_REL16_HA:
write16be(Loc, applyPPCHa(Val));
break;
case R_PPC64_ADDR16_HI:
case R_PPC64_REL16_HI:
write16be(Loc, applyPPCHi(Val));
break;
case R_PPC64_ADDR16_HIGHER:
write16be(Loc, applyPPCHigher(Val));
break;
case R_PPC64_ADDR16_HIGHERA:
write16be(Loc, applyPPCHighera(Val));
break;
case R_PPC64_ADDR16_HIGHEST:
write16be(Loc, applyPPCHighest(Val));
break;
case R_PPC64_ADDR16_HIGHESTA:
write16be(Loc, applyPPCHighesta(Val));
break;
case R_PPC64_ADDR16_LO:
write16be(Loc, applyPPCLo(Val));
break;
case R_PPC64_ADDR16_LO_DS:
case R_PPC64_REL16_LO:
write16be(Loc, (read16be(Loc) & 3) | (applyPPCLo(Val) & ~3));
break;
case R_PPC64_ADDR32:
case R_PPC64_REL32:
checkInt<32>(Loc, Val, Type);
write32be(Loc, Val);
break;
case R_PPC64_ADDR64:
case R_PPC64_REL64:
case R_PPC64_TOC:
write64be(Loc, Val);
break;
case R_PPC64_REL24: {
uint32_t Mask = 0x03FFFFFC;
checkInt<24>(Loc, Val, Type);
write32be(Loc, (read32be(Loc) & ~Mask) | (Val & Mask));
break;
}
default:
error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
}
}
TargetInfo *elf::getPPC64TargetInfo() {
static PPC64 Target;
return &Target;
}

View File

@@ -0,0 +1,148 @@
//===- SPARCV9.cpp --------------------------------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "InputFiles.h"
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
#include "lld/Common/ErrorHandler.h"
#include "llvm/Support/Endian.h"
using namespace llvm;
using namespace llvm::support::endian;
using namespace llvm::ELF;
using namespace lld;
using namespace lld::elf;
namespace {
class SPARCV9 final : public TargetInfo {
public:
SPARCV9();
RelExpr getRelExpr(RelType Type, const Symbol &S,
const uint8_t *Loc) const override;
void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
int32_t Index, unsigned RelOff) const override;
void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override;
};
} // namespace
SPARCV9::SPARCV9() {
CopyRel = R_SPARC_COPY;
GotRel = R_SPARC_GLOB_DAT;
PltRel = R_SPARC_JMP_SLOT;
RelativeRel = R_SPARC_RELATIVE;
GotEntrySize = 8;
PltEntrySize = 32;
PltHeaderSize = 4 * PltEntrySize;
PageSize = 8192;
DefaultMaxPageSize = 0x100000;
DefaultImageBase = 0x100000;
}
RelExpr SPARCV9::getRelExpr(RelType Type, const Symbol &S,
const uint8_t *Loc) const {
switch (Type) {
case R_SPARC_32:
case R_SPARC_UA32:
case R_SPARC_64:
case R_SPARC_UA64:
return R_ABS;
case R_SPARC_PC10:
case R_SPARC_PC22:
case R_SPARC_DISP32:
case R_SPARC_WDISP30:
return R_PC;
case R_SPARC_GOT10:
return R_GOT_OFF;
case R_SPARC_GOT22:
return R_GOT_OFF;
case R_SPARC_WPLT30:
return R_PLT_PC;
case R_SPARC_NONE:
return R_NONE;
default:
return R_INVALID;
}
}
void SPARCV9::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
switch (Type) {
case R_SPARC_32:
case R_SPARC_UA32:
// V-word32
checkUInt<32>(Loc, Val, Type);
write32be(Loc, Val);
break;
case R_SPARC_DISP32:
// V-disp32
checkInt<32>(Loc, Val, Type);
write32be(Loc, Val);
break;
case R_SPARC_WDISP30:
case R_SPARC_WPLT30:
// V-disp30
checkInt<32>(Loc, Val, Type);
write32be(Loc, (read32be(Loc) & ~0x3fffffff) | ((Val >> 2) & 0x3fffffff));
break;
case R_SPARC_22:
// V-imm22
checkUInt<22>(Loc, Val, Type);
write32be(Loc, (read32be(Loc) & ~0x003fffff) | (Val & 0x003fffff));
break;
case R_SPARC_GOT22:
case R_SPARC_PC22:
// T-imm22
write32be(Loc, (read32be(Loc) & ~0x003fffff) | ((Val >> 10) & 0x003fffff));
break;
case R_SPARC_WDISP19:
// V-disp19
checkInt<21>(Loc, Val, Type);
write32be(Loc, (read32be(Loc) & ~0x0007ffff) | ((Val >> 2) & 0x0007ffff));
break;
case R_SPARC_GOT10:
case R_SPARC_PC10:
// T-simm10
write32be(Loc, (read32be(Loc) & ~0x000003ff) | (Val & 0x000003ff));
break;
case R_SPARC_64:
case R_SPARC_UA64:
case R_SPARC_GLOB_DAT:
// V-xword64
write64be(Loc, Val);
break;
default:
error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
}
}
void SPARCV9::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
uint64_t PltEntryAddr, int32_t Index,
unsigned RelOff) const {
const uint8_t PltData[] = {
0x03, 0x00, 0x00, 0x00, // sethi (. - .PLT0), %g1
0x30, 0x68, 0x00, 0x00, // ba,a %xcc, .PLT1
0x01, 0x00, 0x00, 0x00, // nop
0x01, 0x00, 0x00, 0x00, // nop
0x01, 0x00, 0x00, 0x00, // nop
0x01, 0x00, 0x00, 0x00, // nop
0x01, 0x00, 0x00, 0x00, // nop
0x01, 0x00, 0x00, 0x00 // nop
};
memcpy(Buf, PltData, sizeof(PltData));
uint64_t Off = PltHeaderSize + Index * PltEntrySize;
relocateOne(Buf, R_SPARC_22, Off);
relocateOne(Buf + 4, R_SPARC_WDISP19, -(Off + 4 - PltEntrySize));
}
TargetInfo *elf::getSPARCV9TargetInfo() {
static SPARCV9 Target;
return &Target;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

35
external/llvm-project/lld/ELF/Bits.h vendored Normal file
View File

@@ -0,0 +1,35 @@
//===- Bits.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_BITS_H
#define LLD_ELF_BITS_H
#include "Config.h"
#include "llvm/Support/Endian.h"
namespace lld {
namespace elf {
inline uint64_t readUint(uint8_t *Buf) {
if (Config->Is64)
return llvm::support::endian::read64(Buf, Config->Endianness);
return llvm::support::endian::read32(Buf, Config->Endianness);
}
inline void writeUint(uint8_t *Buf, uint64_t Val) {
if (Config->Is64)
llvm::support::endian::write64(Buf, Val, Config->Endianness);
else
llvm::support::endian::write32(Buf, Val, Config->Endianness);
}
} // namespace elf
} // namespace lld
#endif

View File

@@ -0,0 +1,64 @@
set(LLVM_TARGET_DEFINITIONS Options.td)
tablegen(LLVM Options.inc -gen-opt-parser-defs)
add_public_tablegen_target(ELFOptionsTableGen)
if(NOT LLD_BUILT_STANDALONE)
set(tablegen_deps intrinsics_gen)
endif()
add_lld_library(lldELF
AArch64ErrataFix.cpp
Arch/AArch64.cpp
Arch/AMDGPU.cpp
Arch/ARM.cpp
Arch/AVR.cpp
Arch/Mips.cpp
Arch/MipsArchTree.cpp
Arch/PPC.cpp
Arch/PPC64.cpp
Arch/SPARCV9.cpp
Arch/X86.cpp
Arch/X86_64.cpp
Driver.cpp
DriverUtils.cpp
EhFrame.cpp
Filesystem.cpp
GdbIndex.cpp
ICF.cpp
InputFiles.cpp
InputSection.cpp
LTO.cpp
LinkerScript.cpp
MapFile.cpp
MarkLive.cpp
OutputSections.cpp
Relocations.cpp
ScriptLexer.cpp
ScriptParser.cpp
Strings.cpp
SymbolTable.cpp
Symbols.cpp
SyntheticSections.cpp
Target.cpp
Thunks.cpp
Writer.cpp
LINK_COMPONENTS
${LLVM_TARGETS_TO_BUILD}
BinaryFormat
Core
DebugInfoDWARF
LTO
MC
Object
Option
Support
LINK_LIBS
lldCommon
${LLVM_PTHREAD_LIB}
DEPENDS
ELFOptionsTableGen
${tablegen_deps}
)

246
external/llvm-project/lld/ELF/Config.h vendored Normal file
View File

@@ -0,0 +1,246 @@
//===- Config.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_CONFIG_H
#define LLD_ELF_CONFIG_H
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/BinaryFormat/ELF.h"
#include "llvm/Support/CachePruning.h"
#include "llvm/Support/CodeGen.h"
#include "llvm/Support/Endian.h"
#include <vector>
namespace lld {
namespace elf {
class InputFile;
enum ELFKind {
ELFNoneKind,
ELF32LEKind,
ELF32BEKind,
ELF64LEKind,
ELF64BEKind
};
// For --build-id.
enum class BuildIdKind { None, Fast, Md5, Sha1, Hexstring, Uuid };
// For --discard-{all,locals,none}.
enum class DiscardPolicy { Default, All, Locals, None };
// For --strip-{all,debug}.
enum class StripPolicy { None, All, Debug };
// For --unresolved-symbols.
enum class UnresolvedPolicy { ReportError, Warn, Ignore, IgnoreAll };
// For --orphan-handling.
enum class OrphanHandlingPolicy { Place, Warn, Error };
// For --sort-section and linkerscript sorting rules.
enum class SortSectionPolicy { Default, None, Alignment, Name, Priority };
// For --target2
enum class Target2Policy { Abs, Rel, GotRel };
struct SymbolVersion {
llvm::StringRef Name;
bool IsExternCpp;
bool HasWildcard;
};
// This struct contains symbols version definition that
// can be found in version script if it is used for link.
struct VersionDefinition {
llvm::StringRef Name;
uint16_t Id = 0;
std::vector<SymbolVersion> Globals;
size_t NameOff = 0; // Offset in the string table
};
// This struct contains the global configuration for the linker.
// Most fields are direct mapping from the command line options
// and such fields have the same name as the corresponding options.
// Most fields are initialized by the driver.
struct Configuration {
uint8_t OSABI = 0;
llvm::CachePruningPolicy ThinLTOCachePolicy;
llvm::StringMap<uint64_t> SectionStartMap;
llvm::StringRef Chroot;
llvm::StringRef DynamicLinker;
llvm::StringRef Entry;
llvm::StringRef Emulation;
llvm::StringRef Fini;
llvm::StringRef Init;
llvm::StringRef LTOAAPipeline;
llvm::StringRef LTONewPmPasses;
llvm::StringRef MapFile;
llvm::StringRef OutputFile;
llvm::StringRef OptRemarksFilename;
llvm::StringRef SoName;
llvm::StringRef Sysroot;
llvm::StringRef ThinLTOCacheDir;
std::string Rpath;
std::vector<VersionDefinition> VersionDefinitions;
std::vector<llvm::StringRef> Argv;
std::vector<llvm::StringRef> AuxiliaryList;
std::vector<llvm::StringRef> FilterList;
std::vector<llvm::StringRef> SearchPaths;
std::vector<llvm::StringRef> SymbolOrderingFile;
std::vector<llvm::StringRef> Undefined;
std::vector<SymbolVersion> DynamicList;
std::vector<SymbolVersion> VersionScriptGlobals;
std::vector<SymbolVersion> VersionScriptLocals;
std::vector<uint8_t> BuildIdVector;
bool AllowMultipleDefinition;
bool AndroidPackDynRelocs = false;
bool ARMHasBlx = false;
bool ARMHasMovtMovw = false;
bool ARMJ1J2BranchEncoding = false;
bool AsNeeded = false;
bool Bsymbolic;
bool BsymbolicFunctions;
bool CompressDebugSections;
bool DefineCommon;
bool Demangle = true;
bool DisableVerify;
bool EhFrameHdr;
bool EmitRelocs;
bool EnableNewDtags;
bool ExportDynamic;
bool FixCortexA53Errata843419;
bool GcSections;
bool GdbIndex;
bool GnuHash = false;
bool HasDynamicList = false;
bool HasDynSymTab;
bool ICF;
bool ICFData;
bool MergeArmExidx;
bool MipsN32Abi = false;
bool NoGnuUnique;
bool NoUndefinedVersion;
bool NoinhibitExec;
bool Nostdlib;
bool OFormatBinary;
bool Omagic;
bool OptRemarksWithHotness;
bool Pie;
bool PrintGcSections;
bool Relocatable;
bool SaveTemps;
bool SingleRoRx;
bool Shared;
bool Static = false;
bool SysvHash = false;
bool Target1Rel;
bool Trace;
bool Verbose;
bool WarnCommon;
bool WarnMissingEntry;
bool ZCombreloc;
bool ZExecstack;
bool ZHazardplt;
bool ZNocopyreloc;
bool ZNodelete;
bool ZNodlopen;
bool ZNow;
bool ZOrigin;
bool ZRelro;
bool ZRodynamic;
bool ZText;
bool ZRetpolineplt;
bool ExitEarly;
bool ZWxneeded;
DiscardPolicy Discard;
OrphanHandlingPolicy OrphanHandling;
SortSectionPolicy SortSection;
StripPolicy Strip;
UnresolvedPolicy UnresolvedSymbols;
Target2Policy Target2;
BuildIdKind BuildId = BuildIdKind::None;
ELFKind EKind = ELFNoneKind;
uint16_t DefaultSymbolVersion = llvm::ELF::VER_NDX_GLOBAL;
uint16_t EMachine = llvm::ELF::EM_NONE;
llvm::Optional<uint64_t> ImageBase;
uint64_t MaxPageSize;
uint64_t ZStackSize;
unsigned LTOPartitions;
unsigned LTOO;
unsigned Optimize;
unsigned ThinLTOJobs;
// The following config options do not directly correspond to any
// particualr command line options.
// True if we need to pass through relocations in input files to the
// output file. Usually false because we consume relocations.
bool CopyRelocs;
// True if the target is ELF64. False if ELF32.
bool Is64;
// True if the target is little-endian. False if big-endian.
bool IsLE;
// endianness::little if IsLE is true. endianness::big otherwise.
llvm::support::endianness Endianness;
// True if the target is the little-endian MIPS64.
//
// The reason why we have this variable only for the MIPS is because
// we use this often. Some ELF headers for MIPS64EL are in a
// mixed-endian (which is horrible and I'd say that's a serious spec
// bug), and we need to know whether we are reading MIPS ELF files or
// not in various places.
//
// (Note that MIPS64EL is not a typo for MIPS64LE. This is the official
// name whatever that means. A fun hypothesis is that "EL" is short for
// little-endian written in the little-endian order, but I don't know
// if that's true.)
bool IsMips64EL;
// Holds set of ELF header flags for the target.
uint32_t EFlags = 0;
// The ELF spec defines two types of relocation table entries, RELA and
// REL. RELA is a triplet of (offset, info, addend) while REL is a
// tuple of (offset, info). Addends for REL are implicit and read from
// the location where the relocations are applied. So, REL is more
// compact than RELA but requires a bit of more work to process.
//
// (From the linker writer's view, this distinction is not necessary.
// If the ELF had chosen whichever and sticked with it, it would have
// been easier to write code to process relocations, but it's too late
// to change the spec.)
//
// Each ABI defines its relocation type. IsRela is true if target
// uses RELA. As far as we know, all 64-bit ABIs are using RELA. A
// few 32-bit ABIs are using RELA too.
bool IsRela;
// True if we are creating position-independent code.
bool Pic;
// 4 for ELF32, 8 for ELF64.
int Wordsize;
};
// The only instance of Configuration struct.
extern Configuration *Config;
} // namespace elf
} // namespace lld
#endif

1134
external/llvm-project/lld/ELF/Driver.cpp vendored Normal file

File diff suppressed because it is too large Load Diff

76
external/llvm-project/lld/ELF/Driver.h vendored Normal file
View File

@@ -0,0 +1,76 @@
//===- Driver.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_DRIVER_H
#define LLD_ELF_DRIVER_H
#include "SymbolTable.h"
#include "lld/Common/LLVM.h"
#include "lld/Common/Reproduce.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/raw_ostream.h"
namespace lld {
namespace elf {
extern class LinkerDriver *Driver;
class LinkerDriver {
public:
void main(ArrayRef<const char *> Args, bool CanExitEarly);
void addFile(StringRef Path, bool WithLOption);
void addLibrary(StringRef Name);
private:
void readConfigs(llvm::opt::InputArgList &Args);
void createFiles(llvm::opt::InputArgList &Args);
void inferMachineType();
template <class ELFT> void link(llvm::opt::InputArgList &Args);
// True if we are in --whole-archive and --no-whole-archive.
bool InWholeArchive = false;
// True if we are in --start-lib and --end-lib.
bool InLib = false;
// True if we are in -format=binary and -format=elf.
bool InBinary = false;
std::vector<InputFile *> Files;
};
// Parses command line options.
class ELFOptTable : public llvm::opt::OptTable {
public:
ELFOptTable();
llvm::opt::InputArgList parse(ArrayRef<const char *> Argv);
};
// Create enum with OPT_xxx values for each option in Options.td
enum {
OPT_INVALID = 0,
#define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11, _12) OPT_##ID,
#include "Options.inc"
#undef OPTION
};
void printHelp(const char *Argv0);
std::string createResponseFile(const llvm::opt::InputArgList &Args);
llvm::Optional<std::string> findFromSearchPaths(StringRef Path);
llvm::Optional<std::string> searchLinkerScript(StringRef Path);
llvm::Optional<std::string> searchLibrary(StringRef Path);
} // namespace elf
} // namespace lld
#endif

View File

@@ -0,0 +1,218 @@
//===- DriverUtils.cpp ----------------------------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains utility functions for the driver. Because there
// are so many small functions, we created this separate file to make
// Driver.cpp less cluttered.
//
//===----------------------------------------------------------------------===//
#include "Driver.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"
#include "lld/Common/Reproduce.h"
#include "lld/Common/Version.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Option/Option.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
using namespace llvm;
using namespace llvm::sys;
using namespace lld;
using namespace lld::elf;
// Create OptTable
// Create prefix string literals used in Options.td
#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
#include "Options.inc"
#undef PREFIX
// Create table mapping all options defined in Options.td
static const opt::OptTable::Info OptInfo[] = {
#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12) \
{X1, X2, X10, X11, OPT_##ID, opt::Option::KIND##Class, \
X9, X8, OPT_##GROUP, OPT_##ALIAS, X7, X12},
#include "Options.inc"
#undef OPTION
};
ELFOptTable::ELFOptTable() : OptTable(OptInfo) {}
// Set color diagnostics according to -color-diagnostics={auto,always,never}
// or -no-color-diagnostics flags.
static void handleColorDiagnostics(opt::InputArgList &Args) {
auto *Arg = Args.getLastArg(OPT_color_diagnostics, OPT_color_diagnostics_eq,
OPT_no_color_diagnostics);
if (!Arg)
return;
else if (Arg->getOption().getID() == OPT_color_diagnostics)
errorHandler().ColorDiagnostics = true;
else if (Arg->getOption().getID() == OPT_no_color_diagnostics)
errorHandler().ColorDiagnostics = false;
else {
StringRef S = Arg->getValue();
if (S == "always")
errorHandler().ColorDiagnostics = true;
else if (S == "never")
errorHandler().ColorDiagnostics = false;
else if (S != "auto")
error("unknown option: -color-diagnostics=" + S);
}
}
static cl::TokenizerCallback getQuotingStyle(opt::InputArgList &Args) {
if (auto *Arg = Args.getLastArg(OPT_rsp_quoting)) {
StringRef S = Arg->getValue();
if (S != "windows" && S != "posix")
error("invalid response file quoting: " + S);
if (S == "windows")
return cl::TokenizeWindowsCommandLine;
return cl::TokenizeGNUCommandLine;
}
if (Triple(sys::getProcessTriple()).getOS() == Triple::Win32)
return cl::TokenizeWindowsCommandLine;
return cl::TokenizeGNUCommandLine;
}
// Parses a given list of options.
opt::InputArgList ELFOptTable::parse(ArrayRef<const char *> Argv) {
// Make InputArgList from string vectors.
unsigned MissingIndex;
unsigned MissingCount;
SmallVector<const char *, 256> Vec(Argv.data(), Argv.data() + Argv.size());
// We need to get the quoting style for response files before parsing all
// options so we parse here before and ignore all the options but
// --rsp-quoting.
opt::InputArgList Args = this->ParseArgs(Vec, MissingIndex, MissingCount);
// Expand response files (arguments in the form of @<filename>)
// and then parse the argument again.
cl::ExpandResponseFiles(Saver, getQuotingStyle(Args), Vec);
Args = this->ParseArgs(Vec, MissingIndex, MissingCount);
handleColorDiagnostics(Args);
if (MissingCount)
error(Twine(Args.getArgString(MissingIndex)) + ": missing argument");
for (auto *Arg : Args.filtered(OPT_UNKNOWN))
error("unknown argument: " + Arg->getSpelling());
return Args;
}
void elf::printHelp(const char *Argv0) {
ELFOptTable().PrintHelp(outs(), Argv0, "lld", false /*ShowHidden*/,
true /*ShowAllAliases*/);
outs() << "\n";
// Scripts generated by Libtool versions up to at least 2.4.6 (the most
// recent version as of March 2017) expect /: supported targets:.* elf/
// in a message for the -help option. If it doesn't match, the scripts
// assume that the linker doesn't support very basic features such as
// shared libraries. Therefore, we need to print out at least "elf".
// Here, we print out all the targets that we support.
outs() << Argv0 << ": supported targets: "
<< "elf32-i386 elf32-iamcu elf32-littlearm elf32-ntradbigmips "
<< "elf32-ntradlittlemips elf32-powerpc elf32-tradbigmips "
<< "elf32-tradlittlemips elf32-x86-64 "
<< "elf64-amdgpu elf64-littleaarch64 elf64-powerpc elf64-tradbigmips "
<< "elf64-tradlittlemips elf64-x86-64\n";
}
// Reconstructs command line arguments so that so that you can re-run
// the same command with the same inputs. This is for --reproduce.
std::string elf::createResponseFile(const opt::InputArgList &Args) {
SmallString<0> Data;
raw_svector_ostream OS(Data);
OS << "--chroot .\n";
// Copy the command line to the output while rewriting paths.
for (auto *Arg : Args) {
switch (Arg->getOption().getUnaliasedOption().getID()) {
case OPT_reproduce:
break;
case OPT_INPUT:
OS << quote(rewritePath(Arg->getValue())) << "\n";
break;
case OPT_o:
// If -o path contains directories, "lld @response.txt" will likely
// fail because the archive we are creating doesn't contain empty
// directories for the output path (-o doesn't create directories).
// Strip directories to prevent the issue.
OS << "-o " << quote(sys::path::filename(Arg->getValue())) << "\n";
break;
case OPT_dynamic_list:
case OPT_library_path:
case OPT_rpath:
case OPT_script:
case OPT_symbol_ordering_file:
case OPT_sysroot:
case OPT_version_script:
OS << Arg->getSpelling() << " " << quote(rewritePath(Arg->getValue()))
<< "\n";
break;
default:
OS << toString(*Arg) << "\n";
}
}
return Data.str();
}
// Find a file by concatenating given paths. If a resulting path
// starts with "=", the character is replaced with a --sysroot value.
static Optional<std::string> findFile(StringRef Path1, const Twine &Path2) {
SmallString<128> S;
if (Path1.startswith("="))
path::append(S, Config->Sysroot, Path1.substr(1), Path2);
else
path::append(S, Path1, Path2);
if (fs::exists(S))
return S.str().str();
return None;
}
Optional<std::string> elf::findFromSearchPaths(StringRef Path) {
for (StringRef Dir : Config->SearchPaths)
if (Optional<std::string> S = findFile(Dir, Path))
return S;
return None;
}
// This is for -lfoo. We'll look for libfoo.so or libfoo.a from
// search paths.
Optional<std::string> elf::searchLibrary(StringRef Name) {
if (Name.startswith(":"))
return findFromSearchPaths(Name.substr(1));
for (StringRef Dir : Config->SearchPaths) {
if (!Config->Static)
if (Optional<std::string> S = findFile(Dir, "lib" + Name + ".so"))
return S;
if (Optional<std::string> S = findFile(Dir, "lib" + Name + ".a"))
return S;
}
return None;
}
// If a linker script doesn't exist in the current directory, we also look for
// the script in the '-L' search paths. This matches the behaviour of both '-T'
// and linker script INPUT() directives in ld.bfd.
Optional<std::string> elf::searchLinkerScript(StringRef Name) {
if (fs::exists(Name))
return Name.str();
return findFromSearchPaths(Name);
}

View File

@@ -0,0 +1,200 @@
//===- EhFrame.cpp -------------------------------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// .eh_frame section contains information on how to unwind the stack when
// an exception is thrown. The section consists of sequence of CIE and FDE
// records. The linker needs to merge CIEs and associate FDEs to CIEs.
// That means the linker has to understand the format of the section.
//
// This file contains a few utility functions to read .eh_frame contents.
//
//===----------------------------------------------------------------------===//
#include "EhFrame.h"
#include "Config.h"
#include "InputSection.h"
#include "Relocations.h"
#include "Strings.h"
#include "lld/Common/ErrorHandler.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/Object/ELF.h"
#include "llvm/Support/Endian.h"
using namespace llvm;
using namespace llvm::ELF;
using namespace llvm::dwarf;
using namespace llvm::object;
using namespace llvm::support::endian;
using namespace lld;
using namespace lld::elf;
namespace {
class EhReader {
public:
EhReader(InputSectionBase *S, ArrayRef<uint8_t> D) : IS(S), D(D) {}
size_t readEhRecordSize();
uint8_t getFdeEncoding();
private:
template <class P> void failOn(const P *Loc, const Twine &Msg) {
fatal("corrupted .eh_frame: " + Msg + "\n>>> defined in " +
IS->getObjMsg((const uint8_t *)Loc - IS->Data.data()));
}
uint8_t readByte();
void skipBytes(size_t Count);
StringRef readString();
void skipLeb128();
void skipAugP();
InputSectionBase *IS;
ArrayRef<uint8_t> D;
};
}
size_t elf::readEhRecordSize(InputSectionBase *S, size_t Off) {
return EhReader(S, S->Data.slice(Off)).readEhRecordSize();
}
// .eh_frame section is a sequence of records. Each record starts with
// a 4 byte length field. This function reads the length.
size_t EhReader::readEhRecordSize() {
if (D.size() < 4)
failOn(D.data(), "CIE/FDE too small");
// First 4 bytes of CIE/FDE is the size of the record.
// If it is 0xFFFFFFFF, the next 8 bytes contain the size instead,
// but we do not support that format yet.
uint64_t V = read32(D.data(), Config->Endianness);
if (V == UINT32_MAX)
failOn(D.data(), "CIE/FDE too large");
uint64_t Size = V + 4;
if (Size > D.size())
failOn(D.data(), "CIE/FDE ends past the end of the section");
return Size;
}
// Read a byte and advance D by one byte.
uint8_t EhReader::readByte() {
if (D.empty())
failOn(D.data(), "unexpected end of CIE");
uint8_t B = D.front();
D = D.slice(1);
return B;
}
void EhReader::skipBytes(size_t Count) {
if (D.size() < Count)
failOn(D.data(), "CIE is too small");
D = D.slice(Count);
}
// Read a null-terminated string.
StringRef EhReader::readString() {
const uint8_t *End = std::find(D.begin(), D.end(), '\0');
if (End == D.end())
failOn(D.data(), "corrupted CIE (failed to read string)");
StringRef S = toStringRef(D.slice(0, End - D.begin()));
D = D.slice(S.size() + 1);
return S;
}
// Skip an integer encoded in the LEB128 format.
// Actual number is not of interest because only the runtime needs it.
// But we need to be at least able to skip it so that we can read
// the field that follows a LEB128 number.
void EhReader::skipLeb128() {
const uint8_t *ErrPos = D.data();
while (!D.empty()) {
uint8_t Val = D.front();
D = D.slice(1);
if ((Val & 0x80) == 0)
return;
}
failOn(ErrPos, "corrupted CIE (failed to read LEB128)");
}
static size_t getAugPSize(unsigned Enc) {
switch (Enc & 0x0f) {
case DW_EH_PE_absptr:
case DW_EH_PE_signed:
return Config->Wordsize;
case DW_EH_PE_udata2:
case DW_EH_PE_sdata2:
return 2;
case DW_EH_PE_udata4:
case DW_EH_PE_sdata4:
return 4;
case DW_EH_PE_udata8:
case DW_EH_PE_sdata8:
return 8;
}
return 0;
}
void EhReader::skipAugP() {
uint8_t Enc = readByte();
if ((Enc & 0xf0) == DW_EH_PE_aligned)
failOn(D.data() - 1, "DW_EH_PE_aligned encoding is not supported");
size_t Size = getAugPSize(Enc);
if (Size == 0)
failOn(D.data() - 1, "unknown FDE encoding");
if (Size >= D.size())
failOn(D.data() - 1, "corrupted CIE");
D = D.slice(Size);
}
uint8_t elf::getFdeEncoding(EhSectionPiece *P) {
return EhReader(P->Sec, P->data()).getFdeEncoding();
}
uint8_t EhReader::getFdeEncoding() {
skipBytes(8);
int Version = readByte();
if (Version != 1 && Version != 3)
failOn(D.data() - 1,
"FDE version 1 or 3 expected, but got " + Twine(Version));
StringRef Aug = readString();
// Skip code and data alignment factors.
skipLeb128();
skipLeb128();
// Skip the return address register. In CIE version 1 this is a single
// byte. In CIE version 3 this is an unsigned LEB128.
if (Version == 1)
readByte();
else
skipLeb128();
// We only care about an 'R' value, but other records may precede an 'R'
// record. Unfortunately records are not in TLV (type-length-value) format,
// so we need to teach the linker how to skip records for each type.
for (char C : Aug) {
if (C == 'R')
return readByte();
if (C == 'z') {
skipLeb128();
continue;
}
if (C == 'P') {
skipAugP();
continue;
}
if (C == 'L') {
readByte();
continue;
}
failOn(Aug.data(), "unknown .eh_frame augmentation string: " + Aug);
}
return DW_EH_PE_absptr;
}

Some files were not shown because too many files have changed in this diff Show More