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/ARMMCTargetDesc.h" |
11 | #include "llvm/BinaryFormat/ELF.h" |
12 | #include "llvm/MC/MCContext.h" |
13 | #include "llvm/MC/MCELFObjectWriter.h" |
14 | #include "llvm/MC/MCExpr.h" |
15 | #include "llvm/MC/MCFixup.h" |
16 | #include "llvm/MC/MCObjectFileInfo.h" |
17 | #include "llvm/MC/MCObjectWriter.h" |
18 | #include "llvm/MC/MCValue.h" |
19 | #include "llvm/Object/ELF.h" |
20 | #include "llvm/Support/ErrorHandling.h" |
21 | #include "llvm/Support/raw_ostream.h" |
22 | #include <cstdint> |
23 | |
24 | using namespace llvm; |
25 | |
26 | namespace { |
27 | |
28 | class ARMELFObjectWriter : public MCELFObjectTargetWriter { |
29 | enum { DefaultEABIVersion = 0x05000000U }; |
30 | |
31 | unsigned GetRelocTypeInner(const MCValue &Target, const MCFixup &Fixup, |
32 | bool IsPCRel, MCContext &Ctx) const; |
33 | |
34 | public: |
35 | ARMELFObjectWriter(uint8_t OSABI); |
36 | |
37 | ~ARMELFObjectWriter() override = default; |
38 | |
39 | unsigned getRelocType(MCContext &Ctx, const MCValue &Target, |
40 | const MCFixup &Fixup, bool IsPCRel) const override; |
41 | |
42 | bool needsRelocateWithSymbol(const MCValue &Val, const MCSymbol &Sym, |
43 | unsigned Type) const override; |
44 | |
45 | void addTargetSectionFlags(MCContext &Ctx, MCSectionELF &Sec) override; |
46 | }; |
47 | |
48 | } // end anonymous namespace |
49 | |
50 | ARMELFObjectWriter::ARMELFObjectWriter(uint8_t OSABI) |
51 | : MCELFObjectTargetWriter(/*Is64Bit*/ false, OSABI, |
52 | ELF::EM_ARM, |
53 | /*HasRelocationAddend*/ false) {} |
54 | |
55 | bool ARMELFObjectWriter::needsRelocateWithSymbol(const MCValue &, |
56 | const MCSymbol &, |
57 | unsigned Type) const { |
58 | // FIXME: This is extremely conservative. This really needs to use an |
59 | // explicit list with a clear explanation for why each realocation needs to |
60 | // point to the symbol, not to the section. |
61 | switch (Type) { |
62 | default: |
63 | return true; |
64 | |
65 | case ELF::R_ARM_PREL31: |
66 | case ELF::R_ARM_ABS32: |
67 | return false; |
68 | } |
69 | } |
70 | |
71 | // Need to examine the Fixup when determining whether to |
72 | // emit the relocation as an explicit symbol or as a section relative |
73 | // offset |
74 | unsigned ARMELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target, |
75 | const MCFixup &Fixup, |
76 | bool IsPCRel) const { |
77 | return GetRelocTypeInner(Target, Fixup, IsPCRel, Ctx); |
78 | } |
79 | |
80 | unsigned ARMELFObjectWriter::GetRelocTypeInner(const MCValue &Target, |
81 | const MCFixup &Fixup, |
82 | bool IsPCRel, |
83 | MCContext &Ctx) const { |
84 | unsigned Kind = Fixup.getTargetKind(); |
85 | if (Kind >= FirstLiteralRelocationKind) |
86 | return Kind - FirstLiteralRelocationKind; |
87 | MCSymbolRefExpr::VariantKind Modifier = Target.getAccessVariant(); |
88 | auto CheckFDPIC = [&](uint32_t Type) { |
89 | if (getOSABI() != ELF::ELFOSABI_ARM_FDPIC) |
90 | Ctx.reportError(L: Fixup.getLoc(), |
91 | Msg: "relocation " + |
92 | object::getELFRelocationTypeName(Machine: ELF::EM_ARM, Type) + |
93 | " only supported in FDPIC mode" ); |
94 | return Type; |
95 | }; |
96 | |
97 | if (IsPCRel) { |
98 | switch (Fixup.getTargetKind()) { |
99 | default: |
100 | Ctx.reportError(L: Fixup.getLoc(), Msg: "unsupported relocation type" ); |
101 | return ELF::R_ARM_NONE; |
102 | case FK_Data_4: |
103 | switch (Modifier) { |
104 | default: |
105 | Ctx.reportError(L: Fixup.getLoc(), |
106 | Msg: "invalid fixup for 4-byte pc-relative data relocation" ); |
107 | return ELF::R_ARM_NONE; |
108 | case MCSymbolRefExpr::VK_None: { |
109 | if (const MCSymbolRefExpr *SymRef = Target.getSymA()) { |
110 | // For GNU AS compatibility expressions such as |
111 | // _GLOBAL_OFFSET_TABLE_ - label emit a R_ARM_BASE_PREL relocation. |
112 | if (SymRef->getSymbol().getName() == "_GLOBAL_OFFSET_TABLE_" ) |
113 | return ELF::R_ARM_BASE_PREL; |
114 | } |
115 | return ELF::R_ARM_REL32; |
116 | } |
117 | case MCSymbolRefExpr::VK_GOTTPOFF: |
118 | return ELF::R_ARM_TLS_IE32; |
119 | case MCSymbolRefExpr::VK_ARM_GOT_PREL: |
120 | return ELF::R_ARM_GOT_PREL; |
121 | case MCSymbolRefExpr::VK_ARM_PREL31: |
122 | return ELF::R_ARM_PREL31; |
123 | } |
124 | case ARM::fixup_arm_blx: |
125 | case ARM::fixup_arm_uncondbl: |
126 | switch (Modifier) { |
127 | case MCSymbolRefExpr::VK_PLT: |
128 | return ELF::R_ARM_CALL; |
129 | case MCSymbolRefExpr::VK_TLSCALL: |
130 | return ELF::R_ARM_TLS_CALL; |
131 | default: |
132 | return ELF::R_ARM_CALL; |
133 | } |
134 | case ARM::fixup_arm_condbl: |
135 | case ARM::fixup_arm_condbranch: |
136 | case ARM::fixup_arm_uncondbranch: |
137 | return ELF::R_ARM_JUMP24; |
138 | case ARM::fixup_t2_condbranch: |
139 | return ELF::R_ARM_THM_JUMP19; |
140 | case ARM::fixup_t2_uncondbranch: |
141 | return ELF::R_ARM_THM_JUMP24; |
142 | case ARM::fixup_arm_movt_hi16: |
143 | return ELF::R_ARM_MOVT_PREL; |
144 | case ARM::fixup_arm_movw_lo16: |
145 | return ELF::R_ARM_MOVW_PREL_NC; |
146 | case ARM::fixup_t2_movt_hi16: |
147 | return ELF::R_ARM_THM_MOVT_PREL; |
148 | case ARM::fixup_t2_movw_lo16: |
149 | return ELF::R_ARM_THM_MOVW_PREL_NC; |
150 | case ARM::fixup_arm_thumb_upper_8_15: |
151 | return ELF::R_ARM_THM_ALU_ABS_G3; |
152 | case ARM::fixup_arm_thumb_upper_0_7: |
153 | return ELF::R_ARM_THM_ALU_ABS_G2_NC; |
154 | case ARM::fixup_arm_thumb_lower_8_15: |
155 | return ELF::R_ARM_THM_ALU_ABS_G1_NC; |
156 | case ARM::fixup_arm_thumb_lower_0_7: |
157 | return ELF::R_ARM_THM_ALU_ABS_G0_NC; |
158 | case ARM::fixup_arm_thumb_br: |
159 | return ELF::R_ARM_THM_JUMP11; |
160 | case ARM::fixup_arm_thumb_bcc: |
161 | return ELF::R_ARM_THM_JUMP8; |
162 | case ARM::fixup_arm_thumb_bl: |
163 | case ARM::fixup_arm_thumb_blx: |
164 | switch (Modifier) { |
165 | case MCSymbolRefExpr::VK_TLSCALL: |
166 | return ELF::R_ARM_THM_TLS_CALL; |
167 | default: |
168 | return ELF::R_ARM_THM_CALL; |
169 | } |
170 | case ARM::fixup_arm_ldst_pcrel_12: |
171 | return ELF::R_ARM_LDR_PC_G0; |
172 | case ARM::fixup_arm_pcrel_10_unscaled: |
173 | return ELF::R_ARM_LDRS_PC_G0; |
174 | case ARM::fixup_t2_ldst_pcrel_12: |
175 | return ELF::R_ARM_THM_PC12; |
176 | case ARM::fixup_arm_adr_pcrel_12: |
177 | return ELF::R_ARM_ALU_PC_G0; |
178 | case ARM::fixup_thumb_adr_pcrel_10: |
179 | return ELF::R_ARM_THM_PC8; |
180 | case ARM::fixup_t2_adr_pcrel_12: |
181 | return ELF::R_ARM_THM_ALU_PREL_11_0; |
182 | case ARM::fixup_bf_target: |
183 | return ELF::R_ARM_THM_BF16; |
184 | case ARM::fixup_bfc_target: |
185 | return ELF::R_ARM_THM_BF12; |
186 | case ARM::fixup_bfl_target: |
187 | return ELF::R_ARM_THM_BF18; |
188 | } |
189 | } |
190 | switch (Kind) { |
191 | default: |
192 | Ctx.reportError(L: Fixup.getLoc(), Msg: "unsupported relocation type" ); |
193 | return ELF::R_ARM_NONE; |
194 | case FK_Data_1: |
195 | switch (Modifier) { |
196 | default: |
197 | Ctx.reportError(L: Fixup.getLoc(), |
198 | Msg: "invalid fixup for 1-byte data relocation" ); |
199 | return ELF::R_ARM_NONE; |
200 | case MCSymbolRefExpr::VK_None: |
201 | return ELF::R_ARM_ABS8; |
202 | } |
203 | case FK_Data_2: |
204 | switch (Modifier) { |
205 | default: |
206 | Ctx.reportError(L: Fixup.getLoc(), |
207 | Msg: "invalid fixup for 2-byte data relocation" ); |
208 | return ELF::R_ARM_NONE; |
209 | case MCSymbolRefExpr::VK_None: |
210 | return ELF::R_ARM_ABS16; |
211 | } |
212 | case FK_Data_4: |
213 | switch (Modifier) { |
214 | default: |
215 | Ctx.reportError(L: Fixup.getLoc(), |
216 | Msg: "invalid fixup for 4-byte data relocation" ); |
217 | return ELF::R_ARM_NONE; |
218 | case MCSymbolRefExpr::VK_ARM_NONE: |
219 | return ELF::R_ARM_NONE; |
220 | case MCSymbolRefExpr::VK_GOT: |
221 | return ELF::R_ARM_GOT_BREL; |
222 | case MCSymbolRefExpr::VK_TLSGD: |
223 | return ELF::R_ARM_TLS_GD32; |
224 | case MCSymbolRefExpr::VK_TPOFF: |
225 | return ELF::R_ARM_TLS_LE32; |
226 | case MCSymbolRefExpr::VK_GOTTPOFF: |
227 | return ELF::R_ARM_TLS_IE32; |
228 | case MCSymbolRefExpr::VK_None: |
229 | return ELF::R_ARM_ABS32; |
230 | case MCSymbolRefExpr::VK_GOTOFF: |
231 | return ELF::R_ARM_GOTOFF32; |
232 | case MCSymbolRefExpr::VK_ARM_GOT_PREL: |
233 | return ELF::R_ARM_GOT_PREL; |
234 | case MCSymbolRefExpr::VK_ARM_TARGET1: |
235 | return ELF::R_ARM_TARGET1; |
236 | case MCSymbolRefExpr::VK_ARM_TARGET2: |
237 | return ELF::R_ARM_TARGET2; |
238 | case MCSymbolRefExpr::VK_ARM_PREL31: |
239 | return ELF::R_ARM_PREL31; |
240 | case MCSymbolRefExpr::VK_ARM_SBREL: |
241 | return ELF::R_ARM_SBREL32; |
242 | case MCSymbolRefExpr::VK_ARM_TLSLDO: |
243 | return ELF::R_ARM_TLS_LDO32; |
244 | case MCSymbolRefExpr::VK_TLSCALL: |
245 | return ELF::R_ARM_TLS_CALL; |
246 | case MCSymbolRefExpr::VK_TLSDESC: |
247 | return ELF::R_ARM_TLS_GOTDESC; |
248 | case MCSymbolRefExpr::VK_TLSLDM: |
249 | return ELF::R_ARM_TLS_LDM32; |
250 | case MCSymbolRefExpr::VK_ARM_TLSDESCSEQ: |
251 | return ELF::R_ARM_TLS_DESCSEQ; |
252 | case MCSymbolRefExpr::VK_FUNCDESC: |
253 | return CheckFDPIC(ELF::R_ARM_FUNCDESC); |
254 | case MCSymbolRefExpr::VK_GOTFUNCDESC: |
255 | return CheckFDPIC(ELF::R_ARM_GOTFUNCDESC); |
256 | case MCSymbolRefExpr::VK_GOTOFFFUNCDESC: |
257 | return CheckFDPIC(ELF::R_ARM_GOTOFFFUNCDESC); |
258 | case MCSymbolRefExpr::VK_TLSGD_FDPIC: |
259 | return CheckFDPIC(ELF::R_ARM_TLS_GD32_FDPIC); |
260 | case MCSymbolRefExpr::VK_TLSLDM_FDPIC: |
261 | return CheckFDPIC(ELF::R_ARM_TLS_LDM32_FDPIC); |
262 | case MCSymbolRefExpr::VK_GOTTPOFF_FDPIC: |
263 | return CheckFDPIC(ELF::R_ARM_TLS_IE32_FDPIC); |
264 | } |
265 | case ARM::fixup_arm_condbranch: |
266 | case ARM::fixup_arm_uncondbranch: |
267 | return ELF::R_ARM_JUMP24; |
268 | case ARM::fixup_arm_movt_hi16: |
269 | switch (Modifier) { |
270 | default: |
271 | Ctx.reportError(L: Fixup.getLoc(), Msg: "invalid fixup for ARM MOVT instruction" ); |
272 | return ELF::R_ARM_NONE; |
273 | case MCSymbolRefExpr::VK_None: |
274 | return ELF::R_ARM_MOVT_ABS; |
275 | case MCSymbolRefExpr::VK_ARM_SBREL: |
276 | return ELF::R_ARM_MOVT_BREL; |
277 | } |
278 | case ARM::fixup_arm_movw_lo16: |
279 | switch (Modifier) { |
280 | default: |
281 | Ctx.reportError(L: Fixup.getLoc(), Msg: "invalid fixup for ARM MOVW instruction" ); |
282 | return ELF::R_ARM_NONE; |
283 | case MCSymbolRefExpr::VK_None: |
284 | return ELF::R_ARM_MOVW_ABS_NC; |
285 | case MCSymbolRefExpr::VK_ARM_SBREL: |
286 | return ELF::R_ARM_MOVW_BREL_NC; |
287 | } |
288 | case ARM::fixup_t2_movt_hi16: |
289 | switch (Modifier) { |
290 | default: |
291 | Ctx.reportError(L: Fixup.getLoc(), |
292 | Msg: "invalid fixup for Thumb MOVT instruction" ); |
293 | return ELF::R_ARM_NONE; |
294 | case MCSymbolRefExpr::VK_None: |
295 | return ELF::R_ARM_THM_MOVT_ABS; |
296 | case MCSymbolRefExpr::VK_ARM_SBREL: |
297 | return ELF::R_ARM_THM_MOVT_BREL; |
298 | } |
299 | case ARM::fixup_t2_movw_lo16: |
300 | switch (Modifier) { |
301 | default: |
302 | Ctx.reportError(L: Fixup.getLoc(), |
303 | Msg: "invalid fixup for Thumb MOVW instruction" ); |
304 | return ELF::R_ARM_NONE; |
305 | case MCSymbolRefExpr::VK_None: |
306 | return ELF::R_ARM_THM_MOVW_ABS_NC; |
307 | case MCSymbolRefExpr::VK_ARM_SBREL: |
308 | return ELF::R_ARM_THM_MOVW_BREL_NC; |
309 | } |
310 | |
311 | case ARM::fixup_arm_thumb_upper_8_15: |
312 | return ELF::R_ARM_THM_ALU_ABS_G3; |
313 | case ARM::fixup_arm_thumb_upper_0_7: |
314 | return ELF::R_ARM_THM_ALU_ABS_G2_NC; |
315 | case ARM::fixup_arm_thumb_lower_8_15: |
316 | return ELF::R_ARM_THM_ALU_ABS_G1_NC; |
317 | case ARM::fixup_arm_thumb_lower_0_7: |
318 | return ELF::R_ARM_THM_ALU_ABS_G0_NC; |
319 | } |
320 | } |
321 | |
322 | void ARMELFObjectWriter::addTargetSectionFlags(MCContext &Ctx, |
323 | MCSectionELF &Sec) { |
324 | // The mix of execute-only and non-execute-only at link time is |
325 | // non-execute-only. To avoid the empty implicitly created .text |
326 | // section from making the whole .text section non-execute-only, we |
327 | // mark it execute-only if it is empty and there is at least one |
328 | // execute-only section in the object. |
329 | MCSectionELF *TextSection = |
330 | static_cast<MCSectionELF *>(Ctx.getObjectFileInfo()->getTextSection()); |
331 | bool IsExecOnly = Sec.getFlags() & ELF::SHF_ARM_PURECODE; |
332 | if (IsExecOnly && !TextSection->hasInstructions()) { |
333 | for (auto &F : *TextSection) |
334 | if (auto *DF = dyn_cast<MCDataFragment>(Val: &F)) |
335 | if (!DF->getContents().empty()) |
336 | return; |
337 | TextSection->setFlags(TextSection->getFlags() | ELF::SHF_ARM_PURECODE); |
338 | } |
339 | } |
340 | |
341 | std::unique_ptr<MCObjectTargetWriter> |
342 | llvm::createARMELFObjectWriter(uint8_t OSABI) { |
343 | return std::make_unique<ARMELFObjectWriter>(args&: OSABI); |
344 | } |
345 | |