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