10cc14835SRui Ueyama //===- SPARCV9.cpp --------------------------------------------------------===//
20cc14835SRui Ueyama //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60cc14835SRui Ueyama //
70cc14835SRui Ueyama //===----------------------------------------------------------------------===//
80cc14835SRui Ueyama
90cc14835SRui Ueyama #include "Symbols.h"
100cc14835SRui Ueyama #include "SyntheticSections.h"
110cc14835SRui Ueyama #include "Target.h"
12b8a59c8aSBob Haarman #include "lld/Common/ErrorHandler.h"
130cc14835SRui Ueyama #include "llvm/Support/Endian.h"
140cc14835SRui Ueyama
150cc14835SRui Ueyama using namespace llvm;
160cc14835SRui Ueyama using namespace llvm::support::endian;
170cc14835SRui Ueyama using namespace llvm::ELF;
1807837b8fSFangrui Song using namespace lld;
1907837b8fSFangrui Song using namespace lld::elf;
200cc14835SRui Ueyama
210cc14835SRui Ueyama namespace {
220cc14835SRui Ueyama class SPARCV9 final : public TargetInfo {
230cc14835SRui Ueyama public:
240cc14835SRui Ueyama SPARCV9();
253837f427SRui Ueyama RelExpr getRelExpr(RelType type, const Symbol &s,
263837f427SRui Ueyama const uint8_t *loc) const override;
2737b28080SFangrui Song void writePlt(uint8_t *buf, const Symbol &sym,
2837b28080SFangrui Song uint64_t pltEntryAddr) const override;
29deb5819dSFangrui Song void relocate(uint8_t *loc, const Relocation &rel,
30deb5819dSFangrui Song uint64_t val) const override;
310cc14835SRui Ueyama };
320cc14835SRui Ueyama } // namespace
330cc14835SRui Ueyama
SPARCV9()340cc14835SRui Ueyama SPARCV9::SPARCV9() {
353837f427SRui Ueyama copyRel = R_SPARC_COPY;
363837f427SRui Ueyama gotRel = R_SPARC_GLOB_DAT;
373837f427SRui Ueyama pltRel = R_SPARC_JMP_SLOT;
383837f427SRui Ueyama relativeRel = R_SPARC_RELATIVE;
393837f427SRui Ueyama symbolicRel = R_SPARC_64;
403837f427SRui Ueyama pltEntrySize = 32;
413837f427SRui Ueyama pltHeaderSize = 4 * pltEntrySize;
420cc14835SRui Ueyama
433837f427SRui Ueyama defaultCommonPageSize = 8192;
443837f427SRui Ueyama defaultMaxPageSize = 0x100000;
453837f427SRui Ueyama defaultImageBase = 0x100000;
460cc14835SRui Ueyama }
470cc14835SRui Ueyama
getRelExpr(RelType type,const Symbol & s,const uint8_t * loc) const483837f427SRui Ueyama RelExpr SPARCV9::getRelExpr(RelType type, const Symbol &s,
493837f427SRui Ueyama const uint8_t *loc) const {
503837f427SRui Ueyama switch (type) {
510cc14835SRui Ueyama case R_SPARC_32:
520cc14835SRui Ueyama case R_SPARC_UA32:
530cc14835SRui Ueyama case R_SPARC_64:
540cc14835SRui Ueyama case R_SPARC_UA64:
55aff950e9SLemonBoy case R_SPARC_H44:
56aff950e9SLemonBoy case R_SPARC_M44:
57aff950e9SLemonBoy case R_SPARC_L44:
58aff950e9SLemonBoy case R_SPARC_HH22:
59aff950e9SLemonBoy case R_SPARC_HM10:
60aff950e9SLemonBoy case R_SPARC_LM22:
61aff950e9SLemonBoy case R_SPARC_HI22:
62aff950e9SLemonBoy case R_SPARC_LO10:
630cc14835SRui Ueyama return R_ABS;
640cc14835SRui Ueyama case R_SPARC_PC10:
650cc14835SRui Ueyama case R_SPARC_PC22:
660cc14835SRui Ueyama case R_SPARC_DISP32:
670cc14835SRui Ueyama case R_SPARC_WDISP30:
680cc14835SRui Ueyama return R_PC;
690cc14835SRui Ueyama case R_SPARC_GOT10:
700cc14835SRui Ueyama return R_GOT_OFF;
710cc14835SRui Ueyama case R_SPARC_GOT22:
720cc14835SRui Ueyama return R_GOT_OFF;
730cc14835SRui Ueyama case R_SPARC_WPLT30:
740cc14835SRui Ueyama return R_PLT_PC;
750cc14835SRui Ueyama case R_SPARC_NONE:
760cc14835SRui Ueyama return R_NONE;
77aff950e9SLemonBoy case R_SPARC_TLS_LE_HIX22:
78aff950e9SLemonBoy case R_SPARC_TLS_LE_LOX10:
79*22c1bd57SFangrui Song return R_TPREL;
800cc14835SRui Ueyama default:
813837f427SRui Ueyama error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) +
823837f427SRui Ueyama ") against symbol " + toString(s));
83b8b81e9bSRui Ueyama return R_NONE;
840cc14835SRui Ueyama }
850cc14835SRui Ueyama }
860cc14835SRui Ueyama
relocate(uint8_t * loc,const Relocation & rel,uint64_t val) const87deb5819dSFangrui Song void SPARCV9::relocate(uint8_t *loc, const Relocation &rel,
88deb5819dSFangrui Song uint64_t val) const {
89deb5819dSFangrui Song switch (rel.type) {
900cc14835SRui Ueyama case R_SPARC_32:
910cc14835SRui Ueyama case R_SPARC_UA32:
920cc14835SRui Ueyama // V-word32
93deb5819dSFangrui Song checkUInt(loc, val, 32, rel);
943837f427SRui Ueyama write32be(loc, val);
950cc14835SRui Ueyama break;
960cc14835SRui Ueyama case R_SPARC_DISP32:
970cc14835SRui Ueyama // V-disp32
98deb5819dSFangrui Song checkInt(loc, val, 32, rel);
993837f427SRui Ueyama write32be(loc, val);
1000cc14835SRui Ueyama break;
1010cc14835SRui Ueyama case R_SPARC_WDISP30:
1020cc14835SRui Ueyama case R_SPARC_WPLT30:
1030cc14835SRui Ueyama // V-disp30
104deb5819dSFangrui Song checkInt(loc, val, 32, rel);
1053837f427SRui Ueyama write32be(loc, (read32be(loc) & ~0x3fffffff) | ((val >> 2) & 0x3fffffff));
1060cc14835SRui Ueyama break;
1070cc14835SRui Ueyama case R_SPARC_22:
1080cc14835SRui Ueyama // V-imm22
109deb5819dSFangrui Song checkUInt(loc, val, 22, rel);
1103837f427SRui Ueyama write32be(loc, (read32be(loc) & ~0x003fffff) | (val & 0x003fffff));
1110cc14835SRui Ueyama break;
1120cc14835SRui Ueyama case R_SPARC_GOT22:
1130cc14835SRui Ueyama case R_SPARC_PC22:
114aff950e9SLemonBoy case R_SPARC_LM22:
1150cc14835SRui Ueyama // T-imm22
1163837f427SRui Ueyama write32be(loc, (read32be(loc) & ~0x003fffff) | ((val >> 10) & 0x003fffff));
1170cc14835SRui Ueyama break;
118aff950e9SLemonBoy case R_SPARC_HI22:
119aff950e9SLemonBoy // V-imm22
120aff950e9SLemonBoy checkUInt(loc, val >> 10, 22, rel);
121aff950e9SLemonBoy write32be(loc, (read32be(loc) & ~0x003fffff) | ((val >> 10) & 0x003fffff));
122aff950e9SLemonBoy break;
1230cc14835SRui Ueyama case R_SPARC_WDISP19:
1240cc14835SRui Ueyama // V-disp19
125deb5819dSFangrui Song checkInt(loc, val, 21, rel);
1263837f427SRui Ueyama write32be(loc, (read32be(loc) & ~0x0007ffff) | ((val >> 2) & 0x0007ffff));
1270cc14835SRui Ueyama break;
1280cc14835SRui Ueyama case R_SPARC_GOT10:
1290cc14835SRui Ueyama case R_SPARC_PC10:
1300cc14835SRui Ueyama // T-simm10
1313837f427SRui Ueyama write32be(loc, (read32be(loc) & ~0x000003ff) | (val & 0x000003ff));
1320cc14835SRui Ueyama break;
133aff950e9SLemonBoy case R_SPARC_LO10:
134aff950e9SLemonBoy // T-simm13
135aff950e9SLemonBoy write32be(loc, (read32be(loc) & ~0x00001fff) | (val & 0x000003ff));
136aff950e9SLemonBoy break;
1370cc14835SRui Ueyama case R_SPARC_64:
1380cc14835SRui Ueyama case R_SPARC_UA64:
1390cc14835SRui Ueyama // V-xword64
1403837f427SRui Ueyama write64be(loc, val);
1410cc14835SRui Ueyama break;
142aff950e9SLemonBoy case R_SPARC_HH22:
143aff950e9SLemonBoy // V-imm22
144aff950e9SLemonBoy checkUInt(loc, val >> 42, 22, rel);
145aff950e9SLemonBoy write32be(loc, (read32be(loc) & ~0x003fffff) | ((val >> 42) & 0x003fffff));
146aff950e9SLemonBoy break;
147aff950e9SLemonBoy case R_SPARC_HM10:
148aff950e9SLemonBoy // T-simm13
149aff950e9SLemonBoy write32be(loc, (read32be(loc) & ~0x00001fff) | ((val >> 32) & 0x000003ff));
150aff950e9SLemonBoy break;
151aff950e9SLemonBoy case R_SPARC_H44:
152aff950e9SLemonBoy // V-imm22
153aff950e9SLemonBoy checkUInt(loc, val >> 22, 22, rel);
154aff950e9SLemonBoy write32be(loc, (read32be(loc) & ~0x003fffff) | ((val >> 22) & 0x003fffff));
155aff950e9SLemonBoy break;
156aff950e9SLemonBoy case R_SPARC_M44:
157aff950e9SLemonBoy // T-imm10
158aff950e9SLemonBoy write32be(loc, (read32be(loc) & ~0x000003ff) | ((val >> 12) & 0x000003ff));
159aff950e9SLemonBoy break;
160aff950e9SLemonBoy case R_SPARC_L44:
161aff950e9SLemonBoy // T-imm13
162aff950e9SLemonBoy write32be(loc, (read32be(loc) & ~0x00001fff) | (val & 0x00000fff));
163aff950e9SLemonBoy break;
164aff950e9SLemonBoy case R_SPARC_TLS_LE_HIX22:
165aff950e9SLemonBoy // T-imm22
166aff950e9SLemonBoy write32be(loc, (read32be(loc) & ~0x003fffff) | ((~val >> 10) & 0x003fffff));
167aff950e9SLemonBoy break;
168aff950e9SLemonBoy case R_SPARC_TLS_LE_LOX10:
169aff950e9SLemonBoy // T-simm13
170aff950e9SLemonBoy write32be(loc, (read32be(loc) & ~0x00001fff) | (val & 0x000003ff) | 0x1C00);
171aff950e9SLemonBoy break;
1720cc14835SRui Ueyama default:
173b8b81e9bSRui Ueyama llvm_unreachable("unknown relocation");
1740cc14835SRui Ueyama }
1750cc14835SRui Ueyama }
1760cc14835SRui Ueyama
writePlt(uint8_t * buf,const Symbol &,uint64_t pltEntryAddr) const17737b28080SFangrui Song void SPARCV9::writePlt(uint8_t *buf, const Symbol & /*sym*/,
17837b28080SFangrui Song uint64_t pltEntryAddr) const {
1793837f427SRui Ueyama const uint8_t pltData[] = {
1800cc14835SRui Ueyama 0x03, 0x00, 0x00, 0x00, // sethi (. - .PLT0), %g1
1810cc14835SRui Ueyama 0x30, 0x68, 0x00, 0x00, // ba,a %xcc, .PLT1
1820cc14835SRui Ueyama 0x01, 0x00, 0x00, 0x00, // nop
1830cc14835SRui Ueyama 0x01, 0x00, 0x00, 0x00, // nop
1840cc14835SRui Ueyama 0x01, 0x00, 0x00, 0x00, // nop
1850cc14835SRui Ueyama 0x01, 0x00, 0x00, 0x00, // nop
1860cc14835SRui Ueyama 0x01, 0x00, 0x00, 0x00, // nop
1870cc14835SRui Ueyama 0x01, 0x00, 0x00, 0x00 // nop
1880cc14835SRui Ueyama };
1893837f427SRui Ueyama memcpy(buf, pltData, sizeof(pltData));
1900cc14835SRui Ueyama
19137b28080SFangrui Song uint64_t off = pltEntryAddr - in.plt->getVA();
192deb5819dSFangrui Song relocateNoSym(buf, R_SPARC_22, off);
193deb5819dSFangrui Song relocateNoSym(buf + 4, R_SPARC_WDISP19, -(off + 4 - pltEntrySize));
1940cc14835SRui Ueyama }
1950cc14835SRui Ueyama
getSPARCV9TargetInfo()19607837b8fSFangrui Song TargetInfo *elf::getSPARCV9TargetInfo() {
1973837f427SRui Ueyama static SPARCV9 target;
1983837f427SRui Ueyama return ⌖
1990cc14835SRui Ueyama }
200