1//===-- SystemZELFObjectWriter.cpp - SystemZ ELF writer -------------------===//
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 "MCTargetDesc/SystemZMCAsmInfo.h"
10#include "MCTargetDesc/SystemZMCFixups.h"
11#include "MCTargetDesc/SystemZMCTargetDesc.h"
12#include "llvm/BinaryFormat/ELF.h"
13#include "llvm/MC/MCContext.h"
14#include "llvm/MC/MCELFObjectWriter.h"
15#include "llvm/MC/MCExpr.h"
16#include "llvm/MC/MCFixup.h"
17#include "llvm/MC/MCObjectWriter.h"
18#include "llvm/MC/MCValue.h"
19#include "llvm/Support/ErrorHandling.h"
20#include <cassert>
21#include <cstdint>
22#include <memory>
23
24using namespace llvm;
25
26namespace {
27
28class SystemZELFObjectWriter : public MCELFObjectTargetWriter {
29public:
30 SystemZELFObjectWriter(uint8_t OSABI);
31 ~SystemZELFObjectWriter() override = default;
32
33protected:
34 // Override MCELFObjectTargetWriter.
35 unsigned getRelocType(const MCFixup &, const MCValue &,
36 bool IsPCRel) const override;
37 bool needsRelocateWithSymbol(const MCValue &, unsigned Type) const override;
38 unsigned getAbsoluteReloc(SMLoc Loc, unsigned Kind) const;
39 unsigned getPCRelReloc(SMLoc Loc, unsigned Kind) const;
40};
41
42} // end anonymous namespace
43
44SystemZELFObjectWriter::SystemZELFObjectWriter(uint8_t OSABI)
45 : MCELFObjectTargetWriter(/*Is64Bit_=*/true, OSABI, ELF::EM_S390,
46 /*HasRelocationAddend_=*/true) {}
47
48// Return the relocation type for an absolute value of MCFixupKind Kind.
49unsigned SystemZELFObjectWriter::getAbsoluteReloc(SMLoc Loc,
50 unsigned Kind) const {
51 switch (Kind) {
52 case FK_Data_1:
53 case SystemZ::FK_390_U8Imm:
54 case SystemZ::FK_390_S8Imm:
55 return ELF::R_390_8;
56 case SystemZ::FK_390_U12Imm:
57 return ELF::R_390_12;
58 case FK_Data_2:
59 case SystemZ::FK_390_U16Imm:
60 case SystemZ::FK_390_S16Imm:
61 return ELF::R_390_16;
62 case SystemZ::FK_390_S20Imm:
63 return ELF::R_390_20;
64 case FK_Data_4:
65 case SystemZ::FK_390_U32Imm:
66 case SystemZ::FK_390_S32Imm:
67 return ELF::R_390_32;
68 case FK_Data_8:
69 return ELF::R_390_64;
70 }
71 reportError(L: Loc, Msg: "Unsupported absolute address");
72 return 0;
73}
74
75// Return the relocation type for a PC-relative value of MCFixupKind Kind.
76unsigned SystemZELFObjectWriter::getPCRelReloc(SMLoc Loc, unsigned Kind) const {
77 switch (Kind) {
78 case FK_Data_2:
79 case SystemZ::FK_390_U16Imm:
80 case SystemZ::FK_390_S16Imm:
81 return ELF::R_390_PC16;
82 case FK_Data_4:
83 case SystemZ::FK_390_U32Imm:
84 case SystemZ::FK_390_S32Imm:
85 return ELF::R_390_PC32;
86 case FK_Data_8:
87 return ELF::R_390_PC64;
88 case SystemZ::FK_390_PC12DBL:
89 return ELF::R_390_PC12DBL;
90 case SystemZ::FK_390_PC16DBL:
91 return ELF::R_390_PC16DBL;
92 case SystemZ::FK_390_PC24DBL:
93 return ELF::R_390_PC24DBL;
94 case SystemZ::FK_390_PC32DBL:
95 return ELF::R_390_PC32DBL;
96 }
97 reportError(L: Loc, Msg: "Unsupported PC-relative address");
98 return 0;
99}
100
101unsigned SystemZELFObjectWriter::getRelocType(const MCFixup &Fixup,
102 const MCValue &Target,
103 bool IsPCRel) const {
104 SMLoc Loc = Fixup.getLoc();
105 unsigned Kind = Fixup.getKind();
106 auto Specifier = SystemZ::Specifier(Target.getSpecifier());
107 switch (Specifier) {
108 case SystemZ::S_INDNTPOFF:
109 case SystemZ::S_NTPOFF:
110 case SystemZ::S_TLSGD:
111 case SystemZ::S_TLSLD:
112 case SystemZ::S_TLSLDM:
113 case SystemZ::S_DTPOFF:
114 if (auto *SA = Target.getAddSym())
115 cast<MCSymbolELF>(Val: SA)->setType(ELF::STT_TLS);
116 break;
117 default:
118 break;
119 }
120
121 switch (Specifier) {
122 case SystemZ::S_None:
123 if (IsPCRel)
124 return getPCRelReloc(Loc, Kind);
125 return getAbsoluteReloc(Loc, Kind);
126
127 case SystemZ::S_NTPOFF:
128 assert(!IsPCRel && "NTPOFF shouldn't be PC-relative");
129 switch (Kind) {
130 case FK_Data_4:
131 return ELF::R_390_TLS_LE32;
132 case FK_Data_8:
133 return ELF::R_390_TLS_LE64;
134 }
135 reportError(L: Loc, Msg: "Unsupported thread-local address (local-exec)");
136 return 0;
137
138 case SystemZ::S_INDNTPOFF:
139 if (IsPCRel && Kind == SystemZ::FK_390_PC32DBL)
140 return ELF::R_390_TLS_IEENT;
141 reportError(L: Loc,
142 Msg: "Only PC-relative INDNTPOFF accesses are supported for now");
143 return 0;
144
145 case SystemZ::S_DTPOFF:
146 assert(!IsPCRel && "DTPOFF shouldn't be PC-relative");
147 switch (Kind) {
148 case FK_Data_4:
149 return ELF::R_390_TLS_LDO32;
150 case FK_Data_8:
151 return ELF::R_390_TLS_LDO64;
152 }
153 reportError(L: Loc, Msg: "Unsupported thread-local address (local-dynamic)");
154 return 0;
155
156 case SystemZ::S_TLSLDM:
157 assert(!IsPCRel && "TLSLDM shouldn't be PC-relative");
158 switch (Kind) {
159 case FK_Data_4:
160 return ELF::R_390_TLS_LDM32;
161 case FK_Data_8:
162 return ELF::R_390_TLS_LDM64;
163 case SystemZ::FK_390_TLS_CALL:
164 return ELF::R_390_TLS_LDCALL;
165 }
166 reportError(L: Loc, Msg: "Unsupported thread-local address (local-dynamic)");
167 return 0;
168
169 case SystemZ::S_TLSGD:
170 assert(!IsPCRel && "TLSGD shouldn't be PC-relative");
171 switch (Kind) {
172 case FK_Data_4:
173 return ELF::R_390_TLS_GD32;
174 case FK_Data_8:
175 return ELF::R_390_TLS_GD64;
176 case SystemZ::FK_390_TLS_CALL:
177 return ELF::R_390_TLS_GDCALL;
178 }
179 reportError(L: Loc, Msg: "Unsupported thread-local address (general-dynamic)");
180 return 0;
181
182 case SystemZ::S_GOT:
183 case SystemZ::S_GOTENT:
184 if (IsPCRel && Kind == SystemZ::FK_390_PC32DBL)
185 return ELF::R_390_GOTENT;
186 reportError(L: Loc, Msg: "Only PC-relative GOT accesses are supported for now");
187 return 0;
188
189 case SystemZ::S_PLT:
190 assert(IsPCRel && "@PLT shouldn't be PC-relative");
191 switch (Kind) {
192 case SystemZ::FK_390_PC12DBL:
193 return ELF::R_390_PLT12DBL;
194 case SystemZ::FK_390_PC16DBL:
195 return ELF::R_390_PLT16DBL;
196 case SystemZ::FK_390_PC24DBL:
197 return ELF::R_390_PLT24DBL;
198 case SystemZ::FK_390_PC32DBL:
199 return ELF::R_390_PLT32DBL;
200 }
201 reportError(L: Loc, Msg: "Unsupported PC-relative PLT address");
202 return 0;
203
204 default:
205 llvm_unreachable("Modifier not supported");
206 }
207}
208
209bool SystemZELFObjectWriter::needsRelocateWithSymbol(const MCValue &V,
210 unsigned Type) const {
211 switch (V.getSpecifier()) {
212 case SystemZ::S_GOT:
213 case SystemZ::S_PLT:
214 return true;
215 default:
216 return false;
217 }
218}
219
220std::unique_ptr<MCObjectTargetWriter>
221llvm::createSystemZELFObjectWriter(uint8_t OSABI) {
222 return std::make_unique<SystemZELFObjectWriter>(args&: OSABI);
223}
224