1 | //===-- ARMELFObjectWriter.cpp - ARM 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/ARMFixupKinds.h" |
10 | #include "MCTargetDesc/ARMMCAsmInfo.h" |
11 | #include "MCTargetDesc/ARMMCTargetDesc.h" |
12 | #include "llvm/BinaryFormat/ELF.h" |
13 | #include "llvm/MC/MCAssembler.h" |
14 | #include "llvm/MC/MCContext.h" |
15 | #include "llvm/MC/MCELFObjectWriter.h" |
16 | #include "llvm/MC/MCExpr.h" |
17 | #include "llvm/MC/MCFixup.h" |
18 | #include "llvm/MC/MCObjectWriter.h" |
19 | #include "llvm/MC/MCValue.h" |
20 | #include "llvm/Object/ELF.h" |
21 | #include "llvm/Support/ErrorHandling.h" |
22 | #include <cstdint> |
23 | |
24 | using namespace llvm; |
25 | |
26 | namespace { |
27 | |
28 | class ARMELFObjectWriter : public MCELFObjectTargetWriter { |
29 | enum { DefaultEABIVersion = 0x05000000U }; |
30 | |
31 | public: |
32 | ARMELFObjectWriter(uint8_t OSABI); |
33 | |
34 | ~ARMELFObjectWriter() override = default; |
35 | |
36 | unsigned getRelocType(const MCFixup &, const MCValue &, |
37 | bool IsPCRel) const override; |
38 | |
39 | bool needsRelocateWithSymbol(const MCValue &Val, |
40 | unsigned Type) const override; |
41 | }; |
42 | |
43 | } // end anonymous namespace |
44 | |
45 | ARMELFObjectWriter::ARMELFObjectWriter(uint8_t OSABI) |
46 | : MCELFObjectTargetWriter(/*Is64Bit*/ false, OSABI, |
47 | ELF::EM_ARM, |
48 | /*HasRelocationAddend*/ false) {} |
49 | |
50 | bool ARMELFObjectWriter::needsRelocateWithSymbol(const MCValue &V, |
51 | unsigned Type) const { |
52 | // If the symbol is a thumb function the final relocation must set the lowest |
53 | // bit. With a symbol that is done by just having the symbol have that bit |
54 | // set, so we would lose the bit if we relocated with the section. |
55 | // We could use the section but add the bit to the relocation value. |
56 | if (Asm->isThumbFunc(Func: V.getAddSym())) |
57 | return true; |
58 | |
59 | // FIXME: This is extremely conservative. This really needs to use an |
60 | // explicit list with a clear explanation for why each realocation needs to |
61 | // point to the symbol, not to the section. |
62 | switch (Type) { |
63 | default: |
64 | return true; |
65 | |
66 | case ELF::R_ARM_PREL31: |
67 | case ELF::R_ARM_ABS32: |
68 | return false; |
69 | } |
70 | } |
71 | |
72 | // Need to examine the Fixup when determining whether to |
73 | // emit the relocation as an explicit symbol or as a section relative |
74 | // offset |
75 | unsigned ARMELFObjectWriter::getRelocType(const MCFixup &Fixup, |
76 | const MCValue &Target, |
77 | bool IsPCRel) const { |
78 | unsigned Kind = Fixup.getTargetKind(); |
79 | uint8_t Specifier = Target.getSpecifier(); |
80 | auto CheckFDPIC = [&](uint32_t Type) { |
81 | if (getOSABI() != ELF::ELFOSABI_ARM_FDPIC) |
82 | reportError(L: Fixup.getLoc(), |
83 | Msg: "relocation " + |
84 | object::getELFRelocationTypeName(Machine: ELF::EM_ARM, Type) + |
85 | " only supported in FDPIC mode" ); |
86 | return Type; |
87 | }; |
88 | |
89 | switch (Specifier) { |
90 | case ARM::S_GOTTPOFF: |
91 | case ARM::S_GOTTPOFF_FDPIC: |
92 | case ARM::S_TLSCALL: |
93 | case ARM::S_TLSDESC: |
94 | case ARM::S_TLSGD: |
95 | case ARM::S_TLSGD_FDPIC: |
96 | case ARM::S_TLSLDM: |
97 | case ARM::S_TLSLDM_FDPIC: |
98 | case ARM::S_TLSLDO: |
99 | case ARM::S_TPOFF: |
100 | if (auto *SA = Target.getAddSym()) |
101 | cast<MCSymbolELF>(Val: SA)->setType(ELF::STT_TLS); |
102 | break; |
103 | default: |
104 | break; |
105 | } |
106 | |
107 | if (IsPCRel) { |
108 | switch (Fixup.getTargetKind()) { |
109 | default: |
110 | reportError(L: Fixup.getLoc(), Msg: "unsupported relocation type" ); |
111 | return ELF::R_ARM_NONE; |
112 | case FK_Data_4: |
113 | switch (Specifier) { |
114 | default: |
115 | reportError(L: Fixup.getLoc(), |
116 | Msg: "invalid fixup for 4-byte pc-relative data relocation" ); |
117 | return ELF::R_ARM_NONE; |
118 | case ARM::S_None: { |
119 | if (const auto *SA = Target.getAddSym()) { |
120 | // For GNU AS compatibility expressions such as |
121 | // _GLOBAL_OFFSET_TABLE_ - label emit a R_ARM_BASE_PREL relocation. |
122 | if (SA->getName() == "_GLOBAL_OFFSET_TABLE_" ) |
123 | return ELF::R_ARM_BASE_PREL; |
124 | } |
125 | return ELF::R_ARM_REL32; |
126 | } |
127 | case ARM::S_GOTTPOFF: |
128 | return ELF::R_ARM_TLS_IE32; |
129 | case ARM::S_GOT_PREL: |
130 | return ELF::R_ARM_GOT_PREL; |
131 | case ARM::S_PREL31: |
132 | return ELF::R_ARM_PREL31; |
133 | } |
134 | case ARM::fixup_arm_blx: |
135 | case ARM::fixup_arm_uncondbl: |
136 | switch (Specifier) { |
137 | case ARM::S_PLT: |
138 | return ELF::R_ARM_CALL; |
139 | case ARM::S_TLSCALL: |
140 | return ELF::R_ARM_TLS_CALL; |
141 | default: |
142 | return ELF::R_ARM_CALL; |
143 | } |
144 | case ARM::fixup_arm_condbl: |
145 | case ARM::fixup_arm_condbranch: |
146 | case ARM::fixup_arm_uncondbranch: |
147 | return ELF::R_ARM_JUMP24; |
148 | case ARM::fixup_t2_condbranch: |
149 | return ELF::R_ARM_THM_JUMP19; |
150 | case ARM::fixup_t2_uncondbranch: |
151 | return ELF::R_ARM_THM_JUMP24; |
152 | case ARM::fixup_arm_movt_hi16: |
153 | return ELF::R_ARM_MOVT_PREL; |
154 | case ARM::fixup_arm_movw_lo16: |
155 | return ELF::R_ARM_MOVW_PREL_NC; |
156 | case ARM::fixup_t2_movt_hi16: |
157 | return ELF::R_ARM_THM_MOVT_PREL; |
158 | case ARM::fixup_t2_movw_lo16: |
159 | return ELF::R_ARM_THM_MOVW_PREL_NC; |
160 | case ARM::fixup_arm_thumb_upper_8_15: |
161 | return ELF::R_ARM_THM_ALU_ABS_G3; |
162 | case ARM::fixup_arm_thumb_upper_0_7: |
163 | return ELF::R_ARM_THM_ALU_ABS_G2_NC; |
164 | case ARM::fixup_arm_thumb_lower_8_15: |
165 | return ELF::R_ARM_THM_ALU_ABS_G1_NC; |
166 | case ARM::fixup_arm_thumb_lower_0_7: |
167 | return ELF::R_ARM_THM_ALU_ABS_G0_NC; |
168 | case ARM::fixup_arm_thumb_br: |
169 | return ELF::R_ARM_THM_JUMP11; |
170 | case ARM::fixup_arm_thumb_bcc: |
171 | return ELF::R_ARM_THM_JUMP8; |
172 | case ARM::fixup_arm_thumb_bl: |
173 | case ARM::fixup_arm_thumb_blx: |
174 | switch (Specifier) { |
175 | case ARM::S_TLSCALL: |
176 | return ELF::R_ARM_THM_TLS_CALL; |
177 | default: |
178 | return ELF::R_ARM_THM_CALL; |
179 | } |
180 | case ARM::fixup_arm_ldst_pcrel_12: |
181 | return ELF::R_ARM_LDR_PC_G0; |
182 | case ARM::fixup_arm_pcrel_10_unscaled: |
183 | return ELF::R_ARM_LDRS_PC_G0; |
184 | case ARM::fixup_t2_ldst_pcrel_12: |
185 | return ELF::R_ARM_THM_PC12; |
186 | case ARM::fixup_arm_adr_pcrel_12: |
187 | return ELF::R_ARM_ALU_PC_G0; |
188 | case ARM::fixup_thumb_adr_pcrel_10: |
189 | return ELF::R_ARM_THM_PC8; |
190 | case ARM::fixup_t2_adr_pcrel_12: |
191 | return ELF::R_ARM_THM_ALU_PREL_11_0; |
192 | case ARM::fixup_bf_target: |
193 | return ELF::R_ARM_THM_BF16; |
194 | case ARM::fixup_bfc_target: |
195 | return ELF::R_ARM_THM_BF12; |
196 | case ARM::fixup_bfl_target: |
197 | return ELF::R_ARM_THM_BF18; |
198 | } |
199 | } |
200 | switch (Kind) { |
201 | default: |
202 | reportError(L: Fixup.getLoc(), Msg: "unsupported relocation type" ); |
203 | return ELF::R_ARM_NONE; |
204 | case FK_Data_1: |
205 | switch (Specifier) { |
206 | default: |
207 | reportError(L: Fixup.getLoc(), Msg: "invalid fixup for 1-byte data relocation" ); |
208 | return ELF::R_ARM_NONE; |
209 | case ARM::S_None: |
210 | return ELF::R_ARM_ABS8; |
211 | } |
212 | case FK_Data_2: |
213 | switch (Specifier) { |
214 | default: |
215 | reportError(L: Fixup.getLoc(), Msg: "invalid fixup for 2-byte data relocation" ); |
216 | return ELF::R_ARM_NONE; |
217 | case ARM::S_None: |
218 | return ELF::R_ARM_ABS16; |
219 | } |
220 | case FK_Data_4: |
221 | switch (Specifier) { |
222 | default: |
223 | reportError(L: Fixup.getLoc(), Msg: "invalid fixup for 4-byte data relocation" ); |
224 | return ELF::R_ARM_NONE; |
225 | case ARM::S_ARM_NONE: |
226 | return ELF::R_ARM_NONE; |
227 | case ARM::S_GOT: |
228 | return ELF::R_ARM_GOT_BREL; |
229 | case ARM::S_TLSGD: |
230 | return ELF::R_ARM_TLS_GD32; |
231 | case ARM::S_TPOFF: |
232 | return ELF::R_ARM_TLS_LE32; |
233 | case ARM::S_GOTTPOFF: |
234 | return ELF::R_ARM_TLS_IE32; |
235 | case ARM::S_None: |
236 | return ELF::R_ARM_ABS32; |
237 | case ARM::S_GOTOFF: |
238 | return ELF::R_ARM_GOTOFF32; |
239 | case ARM::S_GOT_PREL: |
240 | return ELF::R_ARM_GOT_PREL; |
241 | case ARM::S_TARGET1: |
242 | return ELF::R_ARM_TARGET1; |
243 | case ARM::S_TARGET2: |
244 | return ELF::R_ARM_TARGET2; |
245 | case ARM::S_PREL31: |
246 | return ELF::R_ARM_PREL31; |
247 | case ARM::S_SBREL: |
248 | return ELF::R_ARM_SBREL32; |
249 | case ARM::S_TLSLDO: |
250 | return ELF::R_ARM_TLS_LDO32; |
251 | case ARM::S_TLSCALL: |
252 | return ELF::R_ARM_TLS_CALL; |
253 | case ARM::S_TLSDESC: |
254 | return ELF::R_ARM_TLS_GOTDESC; |
255 | case ARM::S_TLSLDM: |
256 | return ELF::R_ARM_TLS_LDM32; |
257 | case ARM::S_TLSDESCSEQ: |
258 | return ELF::R_ARM_TLS_DESCSEQ; |
259 | case ARM::S_FUNCDESC: |
260 | return CheckFDPIC(ELF::R_ARM_FUNCDESC); |
261 | case ARM::S_GOTFUNCDESC: |
262 | return CheckFDPIC(ELF::R_ARM_GOTFUNCDESC); |
263 | case ARM::S_GOTOFFFUNCDESC: |
264 | return CheckFDPIC(ELF::R_ARM_GOTOFFFUNCDESC); |
265 | case ARM::S_TLSGD_FDPIC: |
266 | return CheckFDPIC(ELF::R_ARM_TLS_GD32_FDPIC); |
267 | case ARM::S_TLSLDM_FDPIC: |
268 | return CheckFDPIC(ELF::R_ARM_TLS_LDM32_FDPIC); |
269 | case ARM::S_GOTTPOFF_FDPIC: |
270 | return CheckFDPIC(ELF::R_ARM_TLS_IE32_FDPIC); |
271 | } |
272 | case ARM::fixup_arm_condbranch: |
273 | case ARM::fixup_arm_uncondbranch: |
274 | return ELF::R_ARM_JUMP24; |
275 | case ARM::fixup_arm_movt_hi16: |
276 | switch (Specifier) { |
277 | default: |
278 | reportError(L: Fixup.getLoc(), Msg: "invalid fixup for ARM MOVT instruction" ); |
279 | return ELF::R_ARM_NONE; |
280 | case ARM::S_None: |
281 | return ELF::R_ARM_MOVT_ABS; |
282 | case ARM::S_SBREL: |
283 | return ELF::R_ARM_MOVT_BREL; |
284 | } |
285 | case ARM::fixup_arm_movw_lo16: |
286 | switch (Specifier) { |
287 | default: |
288 | reportError(L: Fixup.getLoc(), Msg: "invalid fixup for ARM MOVW instruction" ); |
289 | return ELF::R_ARM_NONE; |
290 | case ARM::S_None: |
291 | return ELF::R_ARM_MOVW_ABS_NC; |
292 | case ARM::S_SBREL: |
293 | return ELF::R_ARM_MOVW_BREL_NC; |
294 | } |
295 | case ARM::fixup_t2_movt_hi16: |
296 | switch (Specifier) { |
297 | default: |
298 | reportError(L: Fixup.getLoc(), Msg: "invalid fixup for Thumb MOVT instruction" ); |
299 | return ELF::R_ARM_NONE; |
300 | case ARM::S_None: |
301 | return ELF::R_ARM_THM_MOVT_ABS; |
302 | case ARM::S_SBREL: |
303 | return ELF::R_ARM_THM_MOVT_BREL; |
304 | } |
305 | case ARM::fixup_t2_movw_lo16: |
306 | switch (Specifier) { |
307 | default: |
308 | reportError(L: Fixup.getLoc(), Msg: "invalid fixup for Thumb MOVW instruction" ); |
309 | return ELF::R_ARM_NONE; |
310 | case ARM::S_None: |
311 | return ELF::R_ARM_THM_MOVW_ABS_NC; |
312 | case ARM::S_SBREL: |
313 | return ELF::R_ARM_THM_MOVW_BREL_NC; |
314 | } |
315 | |
316 | case ARM::fixup_arm_thumb_upper_8_15: |
317 | return ELF::R_ARM_THM_ALU_ABS_G3; |
318 | case ARM::fixup_arm_thumb_upper_0_7: |
319 | return ELF::R_ARM_THM_ALU_ABS_G2_NC; |
320 | case ARM::fixup_arm_thumb_lower_8_15: |
321 | return ELF::R_ARM_THM_ALU_ABS_G1_NC; |
322 | case ARM::fixup_arm_thumb_lower_0_7: |
323 | return ELF::R_ARM_THM_ALU_ABS_G0_NC; |
324 | } |
325 | } |
326 | |
327 | std::unique_ptr<MCObjectTargetWriter> |
328 | llvm::createARMELFObjectWriter(uint8_t OSABI) { |
329 | return std::make_unique<ARMELFObjectWriter>(args&: OSABI); |
330 | } |
331 | |