1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
|
//===- SPARCV9.cpp --------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#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, const Symbol &sym,
uint64_t pltEntryAddr) const override;
void relocate(uint8_t *loc, const Relocation &rel,
uint64_t val) const override;
};
} // namespace
SPARCV9::SPARCV9() {
copyRel = R_SPARC_COPY;
gotRel = R_SPARC_GLOB_DAT;
noneRel = R_SPARC_NONE;
pltRel = R_SPARC_JMP_SLOT;
relativeRel = R_SPARC_RELATIVE;
symbolicRel = R_SPARC_64;
pltEntrySize = 32;
pltHeaderSize = 4 * pltEntrySize;
defaultCommonPageSize = 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:
case R_SPARC_H44:
case R_SPARC_M44:
case R_SPARC_L44:
case R_SPARC_HH22:
case R_SPARC_HM10:
case R_SPARC_LM22:
case R_SPARC_HI22:
case R_SPARC_LO10:
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;
case R_SPARC_TLS_LE_HIX22:
case R_SPARC_TLS_LE_LOX10:
return R_TLS;
default:
error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) +
") against symbol " + toString(s));
return R_NONE;
}
}
void SPARCV9::relocate(uint8_t *loc, const Relocation &rel,
uint64_t val) const {
switch (rel.type) {
case R_SPARC_32:
case R_SPARC_UA32:
// V-word32
checkUInt(loc, val, 32, rel);
write32be(loc, val);
break;
case R_SPARC_DISP32:
// V-disp32
checkInt(loc, val, 32, rel);
write32be(loc, val);
break;
case R_SPARC_WDISP30:
case R_SPARC_WPLT30:
// V-disp30
checkInt(loc, val, 32, rel);
write32be(loc, (read32be(loc) & ~0x3fffffff) | ((val >> 2) & 0x3fffffff));
break;
case R_SPARC_22:
// V-imm22
checkUInt(loc, val, 22, rel);
write32be(loc, (read32be(loc) & ~0x003fffff) | (val & 0x003fffff));
break;
case R_SPARC_GOT22:
case R_SPARC_PC22:
case R_SPARC_LM22:
// T-imm22
write32be(loc, (read32be(loc) & ~0x003fffff) | ((val >> 10) & 0x003fffff));
break;
case R_SPARC_HI22:
// V-imm22
checkUInt(loc, val >> 10, 22, rel);
write32be(loc, (read32be(loc) & ~0x003fffff) | ((val >> 10) & 0x003fffff));
break;
case R_SPARC_WDISP19:
// V-disp19
checkInt(loc, val, 21, rel);
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_LO10:
// T-simm13
write32be(loc, (read32be(loc) & ~0x00001fff) | (val & 0x000003ff));
break;
case R_SPARC_64:
case R_SPARC_UA64:
// V-xword64
write64be(loc, val);
break;
case R_SPARC_HH22:
// V-imm22
checkUInt(loc, val >> 42, 22, rel);
write32be(loc, (read32be(loc) & ~0x003fffff) | ((val >> 42) & 0x003fffff));
break;
case R_SPARC_HM10:
// T-simm13
write32be(loc, (read32be(loc) & ~0x00001fff) | ((val >> 32) & 0x000003ff));
break;
case R_SPARC_H44:
// V-imm22
checkUInt(loc, val >> 22, 22, rel);
write32be(loc, (read32be(loc) & ~0x003fffff) | ((val >> 22) & 0x003fffff));
break;
case R_SPARC_M44:
// T-imm10
write32be(loc, (read32be(loc) & ~0x000003ff) | ((val >> 12) & 0x000003ff));
break;
case R_SPARC_L44:
// T-imm13
write32be(loc, (read32be(loc) & ~0x00001fff) | (val & 0x00000fff));
break;
case R_SPARC_TLS_LE_HIX22:
// T-imm22
write32be(loc, (read32be(loc) & ~0x003fffff) | ((~val >> 10) & 0x003fffff));
break;
case R_SPARC_TLS_LE_LOX10:
// T-simm13
write32be(loc, (read32be(loc) & ~0x00001fff) | (val & 0x000003ff) | 0x1C00);
break;
default:
llvm_unreachable("unknown relocation");
}
}
void SPARCV9::writePlt(uint8_t *buf, const Symbol & /*sym*/,
uint64_t pltEntryAddr) 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 = pltEntryAddr - in.plt->getVA();
relocateNoSym(buf, R_SPARC_22, off);
relocateNoSym(buf + 4, R_SPARC_WDISP19, -(off + 4 - pltEntrySize));
}
TargetInfo *elf::getSPARCV9TargetInfo() {
static SPARCV9 target;
return ⌖
}
|