1//===- SPARCV9.cpp --------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "InputFiles.h"
10#include "Symbols.h"
11#include "SyntheticSections.h"
12#include "Target.h"
13#include "lld/Common/ErrorHandler.h"
14#include "llvm/Support/Endian.h"
15
16using namespace llvm;
17using namespace llvm::support::endian;
18using namespace llvm::ELF;
19
20namespace lld {
21namespace elf {
22
23namespace {
24class SPARCV9 final : public TargetInfo {
25public:
26  SPARCV9();
27  RelExpr getRelExpr(RelType type, const Symbol &s,
28                     const uint8_t *loc) const override;
29  void writePlt(uint8_t *buf, const Symbol &sym,
30                uint64_t pltEntryAddr) const override;
31  void relocateOne(uint8_t *loc, RelType type, uint64_t val) const override;
32};
33} // namespace
34
35SPARCV9::SPARCV9() {
36  copyRel = R_SPARC_COPY;
37  gotRel = R_SPARC_GLOB_DAT;
38  noneRel = R_SPARC_NONE;
39  pltRel = R_SPARC_JMP_SLOT;
40  relativeRel = R_SPARC_RELATIVE;
41  symbolicRel = R_SPARC_64;
42  pltEntrySize = 32;
43  pltHeaderSize = 4 * pltEntrySize;
44
45  defaultCommonPageSize = 8192;
46  defaultMaxPageSize = 0x100000;
47  defaultImageBase = 0x100000;
48}
49
50RelExpr SPARCV9::getRelExpr(RelType type, const Symbol &s,
51                            const uint8_t *loc) const {
52  switch (type) {
53  case R_SPARC_32:
54  case R_SPARC_UA32:
55  case R_SPARC_64:
56  case R_SPARC_UA64:
57    return R_ABS;
58  case R_SPARC_PC10:
59  case R_SPARC_PC22:
60  case R_SPARC_DISP32:
61  case R_SPARC_WDISP30:
62    return R_PC;
63  case R_SPARC_GOT10:
64    return R_GOT_OFF;
65  case R_SPARC_GOT22:
66    return R_GOT_OFF;
67  case R_SPARC_WPLT30:
68    return R_PLT_PC;
69  case R_SPARC_NONE:
70    return R_NONE;
71  default:
72    error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) +
73          ") against symbol " + toString(s));
74    return R_NONE;
75  }
76}
77
78void SPARCV9::relocateOne(uint8_t *loc, RelType type, uint64_t val) const {
79  switch (type) {
80  case R_SPARC_32:
81  case R_SPARC_UA32:
82    // V-word32
83    checkUInt(loc, val, 32, type);
84    write32be(loc, val);
85    break;
86  case R_SPARC_DISP32:
87    // V-disp32
88    checkInt(loc, val, 32, type);
89    write32be(loc, val);
90    break;
91  case R_SPARC_WDISP30:
92  case R_SPARC_WPLT30:
93    // V-disp30
94    checkInt(loc, val, 32, type);
95    write32be(loc, (read32be(loc) & ~0x3fffffff) | ((val >> 2) & 0x3fffffff));
96    break;
97  case R_SPARC_22:
98    // V-imm22
99    checkUInt(loc, val, 22, type);
100    write32be(loc, (read32be(loc) & ~0x003fffff) | (val & 0x003fffff));
101    break;
102  case R_SPARC_GOT22:
103  case R_SPARC_PC22:
104    // T-imm22
105    write32be(loc, (read32be(loc) & ~0x003fffff) | ((val >> 10) & 0x003fffff));
106    break;
107  case R_SPARC_WDISP19:
108    // V-disp19
109    checkInt(loc, val, 21, type);
110    write32be(loc, (read32be(loc) & ~0x0007ffff) | ((val >> 2) & 0x0007ffff));
111    break;
112  case R_SPARC_GOT10:
113  case R_SPARC_PC10:
114    // T-simm10
115    write32be(loc, (read32be(loc) & ~0x000003ff) | (val & 0x000003ff));
116    break;
117  case R_SPARC_64:
118  case R_SPARC_UA64:
119    // V-xword64
120    write64be(loc, val);
121    break;
122  default:
123    llvm_unreachable("unknown relocation");
124  }
125}
126
127void SPARCV9::writePlt(uint8_t *buf, const Symbol & /*sym*/,
128                       uint64_t pltEntryAddr) const {
129  const uint8_t pltData[] = {
130      0x03, 0x00, 0x00, 0x00, // sethi   (. - .PLT0), %g1
131      0x30, 0x68, 0x00, 0x00, // ba,a    %xcc, .PLT1
132      0x01, 0x00, 0x00, 0x00, // nop
133      0x01, 0x00, 0x00, 0x00, // nop
134      0x01, 0x00, 0x00, 0x00, // nop
135      0x01, 0x00, 0x00, 0x00, // nop
136      0x01, 0x00, 0x00, 0x00, // nop
137      0x01, 0x00, 0x00, 0x00  // nop
138  };
139  memcpy(buf, pltData, sizeof(pltData));
140
141  uint64_t off = pltEntryAddr - in.plt->getVA();
142  relocateOne(buf, R_SPARC_22, off);
143  relocateOne(buf + 4, R_SPARC_WDISP19, -(off + 4 - pltEntrySize));
144}
145
146TargetInfo *getSPARCV9TargetInfo() {
147  static SPARCV9 target;
148  return ⌖
149}
150
151} // namespace elf
152} // namespace lld
153