1320541Sdim//===- SPARCV9.cpp --------------------------------------------------------===//
2320541Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6320541Sdim//
7320541Sdim//===----------------------------------------------------------------------===//
8320541Sdim
9320541Sdim#include "InputFiles.h"
10320541Sdim#include "Symbols.h"
11320541Sdim#include "SyntheticSections.h"
12320541Sdim#include "Target.h"
13327952Sdim#include "lld/Common/ErrorHandler.h"
14320541Sdim#include "llvm/Support/Endian.h"
15320541Sdim
16320541Sdimusing namespace llvm;
17320541Sdimusing namespace llvm::support::endian;
18320541Sdimusing namespace llvm::ELF;
19320541Sdim
20360784Sdimnamespace lld {
21360784Sdimnamespace elf {
22360784Sdim
23320541Sdimnamespace {
24320541Sdimclass SPARCV9 final : public TargetInfo {
25320541Sdimpublic:
26320541Sdim  SPARCV9();
27353358Sdim  RelExpr getRelExpr(RelType type, const Symbol &s,
28353358Sdim                     const uint8_t *loc) const override;
29360784Sdim  void writePlt(uint8_t *buf, const Symbol &sym,
30360784Sdim                uint64_t pltEntryAddr) const override;
31353358Sdim  void relocateOne(uint8_t *loc, RelType type, uint64_t val) const override;
32320541Sdim};
33320541Sdim} // namespace
34320541Sdim
35320541SdimSPARCV9::SPARCV9() {
36353358Sdim  copyRel = R_SPARC_COPY;
37353358Sdim  gotRel = R_SPARC_GLOB_DAT;
38353358Sdim  noneRel = R_SPARC_NONE;
39353358Sdim  pltRel = R_SPARC_JMP_SLOT;
40353358Sdim  relativeRel = R_SPARC_RELATIVE;
41353358Sdim  symbolicRel = R_SPARC_64;
42353358Sdim  pltEntrySize = 32;
43353358Sdim  pltHeaderSize = 4 * pltEntrySize;
44320541Sdim
45353358Sdim  defaultCommonPageSize = 8192;
46353358Sdim  defaultMaxPageSize = 0x100000;
47353358Sdim  defaultImageBase = 0x100000;
48320541Sdim}
49320541Sdim
50353358SdimRelExpr SPARCV9::getRelExpr(RelType type, const Symbol &s,
51353358Sdim                            const uint8_t *loc) const {
52353358Sdim  switch (type) {
53320541Sdim  case R_SPARC_32:
54320541Sdim  case R_SPARC_UA32:
55320541Sdim  case R_SPARC_64:
56320541Sdim  case R_SPARC_UA64:
57320541Sdim    return R_ABS;
58320541Sdim  case R_SPARC_PC10:
59320541Sdim  case R_SPARC_PC22:
60320541Sdim  case R_SPARC_DISP32:
61320541Sdim  case R_SPARC_WDISP30:
62320541Sdim    return R_PC;
63320541Sdim  case R_SPARC_GOT10:
64320541Sdim    return R_GOT_OFF;
65320541Sdim  case R_SPARC_GOT22:
66320541Sdim    return R_GOT_OFF;
67320541Sdim  case R_SPARC_WPLT30:
68320541Sdim    return R_PLT_PC;
69320541Sdim  case R_SPARC_NONE:
70320541Sdim    return R_NONE;
71320541Sdim  default:
72353358Sdim    error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) +
73353358Sdim          ") against symbol " + toString(s));
74353358Sdim    return R_NONE;
75320541Sdim  }
76320541Sdim}
77320541Sdim
78353358Sdimvoid SPARCV9::relocateOne(uint8_t *loc, RelType type, uint64_t val) const {
79353358Sdim  switch (type) {
80320541Sdim  case R_SPARC_32:
81320541Sdim  case R_SPARC_UA32:
82320541Sdim    // V-word32
83353358Sdim    checkUInt(loc, val, 32, type);
84353358Sdim    write32be(loc, val);
85320541Sdim    break;
86320541Sdim  case R_SPARC_DISP32:
87320541Sdim    // V-disp32
88353358Sdim    checkInt(loc, val, 32, type);
89353358Sdim    write32be(loc, val);
90320541Sdim    break;
91320541Sdim  case R_SPARC_WDISP30:
92320541Sdim  case R_SPARC_WPLT30:
93320541Sdim    // V-disp30
94353358Sdim    checkInt(loc, val, 32, type);
95353358Sdim    write32be(loc, (read32be(loc) & ~0x3fffffff) | ((val >> 2) & 0x3fffffff));
96320541Sdim    break;
97320541Sdim  case R_SPARC_22:
98320541Sdim    // V-imm22
99353358Sdim    checkUInt(loc, val, 22, type);
100353358Sdim    write32be(loc, (read32be(loc) & ~0x003fffff) | (val & 0x003fffff));
101320541Sdim    break;
102320541Sdim  case R_SPARC_GOT22:
103320541Sdim  case R_SPARC_PC22:
104320541Sdim    // T-imm22
105353358Sdim    write32be(loc, (read32be(loc) & ~0x003fffff) | ((val >> 10) & 0x003fffff));
106320541Sdim    break;
107320541Sdim  case R_SPARC_WDISP19:
108320541Sdim    // V-disp19
109353358Sdim    checkInt(loc, val, 21, type);
110353358Sdim    write32be(loc, (read32be(loc) & ~0x0007ffff) | ((val >> 2) & 0x0007ffff));
111320541Sdim    break;
112320541Sdim  case R_SPARC_GOT10:
113320541Sdim  case R_SPARC_PC10:
114320541Sdim    // T-simm10
115353358Sdim    write32be(loc, (read32be(loc) & ~0x000003ff) | (val & 0x000003ff));
116320541Sdim    break;
117320541Sdim  case R_SPARC_64:
118320541Sdim  case R_SPARC_UA64:
119320541Sdim    // V-xword64
120353358Sdim    write64be(loc, val);
121320541Sdim    break;
122320541Sdim  default:
123353358Sdim    llvm_unreachable("unknown relocation");
124320541Sdim  }
125320541Sdim}
126320541Sdim
127360784Sdimvoid SPARCV9::writePlt(uint8_t *buf, const Symbol & /*sym*/,
128360784Sdim                       uint64_t pltEntryAddr) const {
129353358Sdim  const uint8_t pltData[] = {
130320541Sdim      0x03, 0x00, 0x00, 0x00, // sethi   (. - .PLT0), %g1
131320541Sdim      0x30, 0x68, 0x00, 0x00, // ba,a    %xcc, .PLT1
132320541Sdim      0x01, 0x00, 0x00, 0x00, // nop
133320541Sdim      0x01, 0x00, 0x00, 0x00, // nop
134320541Sdim      0x01, 0x00, 0x00, 0x00, // nop
135320541Sdim      0x01, 0x00, 0x00, 0x00, // nop
136320541Sdim      0x01, 0x00, 0x00, 0x00, // nop
137320541Sdim      0x01, 0x00, 0x00, 0x00  // nop
138320541Sdim  };
139353358Sdim  memcpy(buf, pltData, sizeof(pltData));
140320541Sdim
141360784Sdim  uint64_t off = pltEntryAddr - in.plt->getVA();
142353358Sdim  relocateOne(buf, R_SPARC_22, off);
143353358Sdim  relocateOne(buf + 4, R_SPARC_WDISP19, -(off + 4 - pltEntrySize));
144320541Sdim}
145320541Sdim
146360784SdimTargetInfo *getSPARCV9TargetInfo() {
147353358Sdim  static SPARCV9 target;
148353358Sdim  return ⌖
149320541Sdim}
150360784Sdim
151360784Sdim} // namespace elf
152360784Sdim} // namespace lld
153