xref: /llvm-project/bolt/lib/Core/Relocation.cpp (revision e11d49cbf5a210ea312f891d9dff6b4bf6433d57)
12f09f445SMaksim Panchenko //===- bolt/Core/Relocation.cpp - Object file relocations -----------------===//
2a34c753fSRafael Auler //
3a34c753fSRafael Auler // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4a34c753fSRafael Auler // See https://llvm.org/LICENSE.txt for license information.
5a34c753fSRafael Auler // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a34c753fSRafael Auler //
7a34c753fSRafael Auler //===----------------------------------------------------------------------===//
8a34c753fSRafael Auler //
92f09f445SMaksim Panchenko // This file implements the Relocation class.
102f09f445SMaksim Panchenko //
11a34c753fSRafael Auler //===----------------------------------------------------------------------===//
12a34c753fSRafael Auler 
13a34c753fSRafael Auler #include "bolt/Core/Relocation.h"
14a34c753fSRafael Auler #include "llvm/MC/MCContext.h"
1557f7c7d9Sserge-sans-paille #include "llvm/MC/MCExpr.h"
16a34c753fSRafael Auler #include "llvm/MC/MCStreamer.h"
1757f7c7d9Sserge-sans-paille #include "llvm/MC/MCSymbol.h"
18eb9f4eb6SAmir Ayupov #include "llvm/Object/ELF.h"
19a34c753fSRafael Auler 
20a34c753fSRafael Auler using namespace llvm;
21a34c753fSRafael Auler using namespace bolt;
22a34c753fSRafael Auler 
23c7d6d622SJob Noorman namespace ELFReserved {
24c7d6d622SJob Noorman enum {
25c7d6d622SJob Noorman   R_RISCV_TPREL_I = 49,
26c7d6d622SJob Noorman   R_RISCV_TPREL_S = 50,
27c7d6d622SJob Noorman };
28c7d6d622SJob Noorman } // namespace ELFReserved
29c7d6d622SJob Noorman 
30a34c753fSRafael Auler Triple::ArchType Relocation::Arch;
31a34c753fSRafael Auler 
32be2f67c4SAmir Ayupov static bool isSupportedX86(uint64_t Type) {
33a34c753fSRafael Auler   switch (Type) {
34a34c753fSRafael Auler   default:
35a34c753fSRafael Auler     return false;
36a34c753fSRafael Auler   case ELF::R_X86_64_8:
37a34c753fSRafael Auler   case ELF::R_X86_64_16:
38a34c753fSRafael Auler   case ELF::R_X86_64_32:
39a34c753fSRafael Auler   case ELF::R_X86_64_32S:
40a34c753fSRafael Auler   case ELF::R_X86_64_64:
41a34c753fSRafael Auler   case ELF::R_X86_64_PC8:
42a34c753fSRafael Auler   case ELF::R_X86_64_PC32:
43a34c753fSRafael Auler   case ELF::R_X86_64_PC64:
44a34c753fSRafael Auler   case ELF::R_X86_64_PLT32:
45853e126cSRafael Auler   case ELF::R_X86_64_GOTPC64:
46a34c753fSRafael Auler   case ELF::R_X86_64_GOTPCREL:
47a34c753fSRafael Auler   case ELF::R_X86_64_GOTTPOFF:
48a34c753fSRafael Auler   case ELF::R_X86_64_TPOFF32:
49a34c753fSRafael Auler   case ELF::R_X86_64_GOTPCRELX:
50a34c753fSRafael Auler   case ELF::R_X86_64_REX_GOTPCRELX:
51a34c753fSRafael Auler     return true;
52a34c753fSRafael Auler   }
53a34c753fSRafael Auler }
54a34c753fSRafael Auler 
55be2f67c4SAmir Ayupov static bool isSupportedAArch64(uint64_t Type) {
56a34c753fSRafael Auler   switch (Type) {
57a34c753fSRafael Auler   default:
58a34c753fSRafael Auler     return false;
59a34c753fSRafael Auler   case ELF::R_AARCH64_CALL26:
60a34c753fSRafael Auler   case ELF::R_AARCH64_JUMP26:
61a34c753fSRafael Auler   case ELF::R_AARCH64_TSTBR14:
62a34c753fSRafael Auler   case ELF::R_AARCH64_CONDBR19:
63a34c753fSRafael Auler   case ELF::R_AARCH64_ADR_PREL_LO21:
64a34c753fSRafael Auler   case ELF::R_AARCH64_ADR_PREL_PG_HI21:
65a34c753fSRafael Auler   case ELF::R_AARCH64_ADR_PREL_PG_HI21_NC:
66a34c753fSRafael Auler   case ELF::R_AARCH64_LDST64_ABS_LO12_NC:
67a34c753fSRafael Auler   case ELF::R_AARCH64_ADD_ABS_LO12_NC:
68a34c753fSRafael Auler   case ELF::R_AARCH64_LDST128_ABS_LO12_NC:
69a34c753fSRafael Auler   case ELF::R_AARCH64_LDST32_ABS_LO12_NC:
70a34c753fSRafael Auler   case ELF::R_AARCH64_LDST16_ABS_LO12_NC:
71a34c753fSRafael Auler   case ELF::R_AARCH64_LDST8_ABS_LO12_NC:
72a34c753fSRafael Auler   case ELF::R_AARCH64_ADR_GOT_PAGE:
73a34c753fSRafael Auler   case ELF::R_AARCH64_TLSDESC_ADR_PREL21:
74a34c753fSRafael Auler   case ELF::R_AARCH64_TLSDESC_ADR_PAGE21:
75a34c753fSRafael Auler   case ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
76a34c753fSRafael Auler   case ELF::R_AARCH64_TLSLE_ADD_TPREL_HI12:
77a34c753fSRafael Auler   case ELF::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
78*e11d49cbSAlexey Moksyakov   case ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0:
79*e11d49cbSAlexey Moksyakov   case ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0_NC:
80a34c753fSRafael Auler   case ELF::R_AARCH64_LD64_GOT_LO12_NC:
81a34c753fSRafael Auler   case ELF::R_AARCH64_TLSDESC_LD64_LO12:
82a34c753fSRafael Auler   case ELF::R_AARCH64_TLSDESC_ADD_LO12:
83a34c753fSRafael Auler   case ELF::R_AARCH64_TLSDESC_CALL:
84a34c753fSRafael Auler   case ELF::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
8548e894a5SAlexey Moksyakov   case ELF::R_AARCH64_PREL16:
86a34c753fSRafael Auler   case ELF::R_AARCH64_PREL32:
8748e894a5SAlexey Moksyakov   case ELF::R_AARCH64_PREL64:
88172deb75SVladislav Khmelevsky   case ELF::R_AARCH64_ABS16:
89172deb75SVladislav Khmelevsky   case ELF::R_AARCH64_ABS32:
90a34c753fSRafael Auler   case ELF::R_AARCH64_ABS64:
91a34c753fSRafael Auler   case ELF::R_AARCH64_MOVW_UABS_G0:
92a34c753fSRafael Auler   case ELF::R_AARCH64_MOVW_UABS_G0_NC:
93a34c753fSRafael Auler   case ELF::R_AARCH64_MOVW_UABS_G1:
94a34c753fSRafael Auler   case ELF::R_AARCH64_MOVW_UABS_G1_NC:
95a34c753fSRafael Auler   case ELF::R_AARCH64_MOVW_UABS_G2:
96a34c753fSRafael Auler   case ELF::R_AARCH64_MOVW_UABS_G2_NC:
97a34c753fSRafael Auler   case ELF::R_AARCH64_MOVW_UABS_G3:
98a34c753fSRafael Auler     return true;
99a34c753fSRafael Auler   }
100a34c753fSRafael Auler }
101a34c753fSRafael Auler 
102f8730293SJob Noorman static bool isSupportedRISCV(uint64_t Type) {
103f8730293SJob Noorman   switch (Type) {
104f8730293SJob Noorman   default:
105f8730293SJob Noorman     return false;
106f8730293SJob Noorman   case ELF::R_RISCV_JAL:
107f8730293SJob Noorman   case ELF::R_RISCV_CALL:
108f8730293SJob Noorman   case ELF::R_RISCV_CALL_PLT:
109f8730293SJob Noorman   case ELF::R_RISCV_BRANCH:
110f8730293SJob Noorman   case ELF::R_RISCV_RELAX:
111f8730293SJob Noorman   case ELF::R_RISCV_GOT_HI20:
112f8730293SJob Noorman   case ELF::R_RISCV_PCREL_HI20:
113f8730293SJob Noorman   case ELF::R_RISCV_PCREL_LO12_I:
1141b78742eSJob Noorman   case ELF::R_RISCV_PCREL_LO12_S:
115f8730293SJob Noorman   case ELF::R_RISCV_RVC_JUMP:
116f8730293SJob Noorman   case ELF::R_RISCV_RVC_BRANCH:
117b410d24aSJob Noorman   case ELF::R_RISCV_ADD32:
118b410d24aSJob Noorman   case ELF::R_RISCV_SUB32:
1199555736aSJob Noorman   case ELF::R_RISCV_HI20:
1209555736aSJob Noorman   case ELF::R_RISCV_LO12_I:
1219555736aSJob Noorman   case ELF::R_RISCV_LO12_S:
122cd7f1714SJob Noorman   case ELF::R_RISCV_64:
123c7d6d622SJob Noorman   case ELF::R_RISCV_TLS_GOT_HI20:
124c7d6d622SJob Noorman   case ELF::R_RISCV_TPREL_HI20:
125c7d6d622SJob Noorman   case ELF::R_RISCV_TPREL_ADD:
126c7d6d622SJob Noorman   case ELF::R_RISCV_TPREL_LO12_I:
127c7d6d622SJob Noorman   case ELF::R_RISCV_TPREL_LO12_S:
128c7d6d622SJob Noorman   case ELFReserved::R_RISCV_TPREL_I:
129c7d6d622SJob Noorman   case ELFReserved::R_RISCV_TPREL_S:
130f8730293SJob Noorman     return true;
131f8730293SJob Noorman   }
132f8730293SJob Noorman }
133f8730293SJob Noorman 
134be2f67c4SAmir Ayupov static size_t getSizeForTypeX86(uint64_t Type) {
135a34c753fSRafael Auler   switch (Type) {
136a34c753fSRafael Auler   default:
137eb9f4eb6SAmir Ayupov     errs() << object::getELFRelocationTypeName(ELF::EM_X86_64, Type) << '\n';
138a34c753fSRafael Auler     llvm_unreachable("unsupported relocation type");
139a34c753fSRafael Auler   case ELF::R_X86_64_8:
140a34c753fSRafael Auler   case ELF::R_X86_64_PC8:
141a34c753fSRafael Auler     return 1;
142a34c753fSRafael Auler   case ELF::R_X86_64_16:
143a34c753fSRafael Auler     return 2;
144a34c753fSRafael Auler   case ELF::R_X86_64_PLT32:
145a34c753fSRafael Auler   case ELF::R_X86_64_PC32:
146a34c753fSRafael Auler   case ELF::R_X86_64_32S:
147a34c753fSRafael Auler   case ELF::R_X86_64_32:
148a34c753fSRafael Auler   case ELF::R_X86_64_GOTPCREL:
149a34c753fSRafael Auler   case ELF::R_X86_64_GOTTPOFF:
150a34c753fSRafael Auler   case ELF::R_X86_64_TPOFF32:
151a34c753fSRafael Auler   case ELF::R_X86_64_GOTPCRELX:
152a34c753fSRafael Auler   case ELF::R_X86_64_REX_GOTPCRELX:
153a34c753fSRafael Auler     return 4;
154a34c753fSRafael Auler   case ELF::R_X86_64_PC64:
155a34c753fSRafael Auler   case ELF::R_X86_64_64:
156853e126cSRafael Auler   case ELF::R_X86_64_GOTPC64:
157a34c753fSRafael Auler     return 8;
158a34c753fSRafael Auler   }
159a34c753fSRafael Auler }
160a34c753fSRafael Auler 
161be2f67c4SAmir Ayupov static size_t getSizeForTypeAArch64(uint64_t Type) {
162a34c753fSRafael Auler   switch (Type) {
163a34c753fSRafael Auler   default:
164eb9f4eb6SAmir Ayupov     errs() << object::getELFRelocationTypeName(ELF::EM_AARCH64, Type) << '\n';
165a34c753fSRafael Auler     llvm_unreachable("unsupported relocation type");
166172deb75SVladislav Khmelevsky   case ELF::R_AARCH64_ABS16:
16748e894a5SAlexey Moksyakov   case ELF::R_AARCH64_PREL16:
168172deb75SVladislav Khmelevsky     return 2;
169a34c753fSRafael Auler   case ELF::R_AARCH64_CALL26:
170a34c753fSRafael Auler   case ELF::R_AARCH64_JUMP26:
171a34c753fSRafael Auler   case ELF::R_AARCH64_TSTBR14:
172a34c753fSRafael Auler   case ELF::R_AARCH64_CONDBR19:
173a34c753fSRafael Auler   case ELF::R_AARCH64_ADR_PREL_LO21:
174a34c753fSRafael Auler   case ELF::R_AARCH64_ADR_PREL_PG_HI21:
175a34c753fSRafael Auler   case ELF::R_AARCH64_ADR_PREL_PG_HI21_NC:
176a34c753fSRafael Auler   case ELF::R_AARCH64_LDST64_ABS_LO12_NC:
177a34c753fSRafael Auler   case ELF::R_AARCH64_ADD_ABS_LO12_NC:
178a34c753fSRafael Auler   case ELF::R_AARCH64_LDST128_ABS_LO12_NC:
179a34c753fSRafael Auler   case ELF::R_AARCH64_LDST32_ABS_LO12_NC:
180a34c753fSRafael Auler   case ELF::R_AARCH64_LDST16_ABS_LO12_NC:
181a34c753fSRafael Auler   case ELF::R_AARCH64_LDST8_ABS_LO12_NC:
182a34c753fSRafael Auler   case ELF::R_AARCH64_ADR_GOT_PAGE:
183a34c753fSRafael Auler   case ELF::R_AARCH64_TLSDESC_ADR_PREL21:
184a34c753fSRafael Auler   case ELF::R_AARCH64_TLSDESC_ADR_PAGE21:
185a34c753fSRafael Auler   case ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
186a34c753fSRafael Auler   case ELF::R_AARCH64_TLSLE_ADD_TPREL_HI12:
187a34c753fSRafael Auler   case ELF::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
188*e11d49cbSAlexey Moksyakov   case ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0:
189*e11d49cbSAlexey Moksyakov   case ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0_NC:
190a34c753fSRafael Auler   case ELF::R_AARCH64_LD64_GOT_LO12_NC:
191a34c753fSRafael Auler   case ELF::R_AARCH64_TLSDESC_LD64_LO12:
192a34c753fSRafael Auler   case ELF::R_AARCH64_TLSDESC_ADD_LO12:
193a34c753fSRafael Auler   case ELF::R_AARCH64_TLSDESC_CALL:
194a34c753fSRafael Auler   case ELF::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
195a34c753fSRafael Auler   case ELF::R_AARCH64_PREL32:
196a34c753fSRafael Auler   case ELF::R_AARCH64_MOVW_UABS_G0:
197a34c753fSRafael Auler   case ELF::R_AARCH64_MOVW_UABS_G0_NC:
198a34c753fSRafael Auler   case ELF::R_AARCH64_MOVW_UABS_G1:
199a34c753fSRafael Auler   case ELF::R_AARCH64_MOVW_UABS_G1_NC:
200a34c753fSRafael Auler   case ELF::R_AARCH64_MOVW_UABS_G2:
201a34c753fSRafael Auler   case ELF::R_AARCH64_MOVW_UABS_G2_NC:
202a34c753fSRafael Auler   case ELF::R_AARCH64_MOVW_UABS_G3:
203172deb75SVladislav Khmelevsky   case ELF::R_AARCH64_ABS32:
204a34c753fSRafael Auler     return 4;
205a34c753fSRafael Auler   case ELF::R_AARCH64_ABS64:
20648e894a5SAlexey Moksyakov   case ELF::R_AARCH64_PREL64:
207a34c753fSRafael Auler     return 8;
208a34c753fSRafael Auler   }
209a34c753fSRafael Auler }
210a34c753fSRafael Auler 
211f8730293SJob Noorman static size_t getSizeForTypeRISCV(uint64_t Type) {
212f8730293SJob Noorman   switch (Type) {
213f8730293SJob Noorman   default:
214f8730293SJob Noorman     errs() << object::getELFRelocationTypeName(ELF::EM_RISCV, Type) << '\n';
215f8730293SJob Noorman     llvm_unreachable("unsupported relocation type");
216f8730293SJob Noorman   case ELF::R_RISCV_RVC_JUMP:
217f8730293SJob Noorman   case ELF::R_RISCV_RVC_BRANCH:
218f8730293SJob Noorman     return 2;
219f8730293SJob Noorman   case ELF::R_RISCV_JAL:
220f8730293SJob Noorman   case ELF::R_RISCV_BRANCH:
221f8730293SJob Noorman   case ELF::R_RISCV_PCREL_HI20:
222f8730293SJob Noorman   case ELF::R_RISCV_PCREL_LO12_I:
2231b78742eSJob Noorman   case ELF::R_RISCV_PCREL_LO12_S:
224f8730293SJob Noorman   case ELF::R_RISCV_32_PCREL:
225f8730293SJob Noorman   case ELF::R_RISCV_CALL:
226f8730293SJob Noorman   case ELF::R_RISCV_CALL_PLT:
227b410d24aSJob Noorman   case ELF::R_RISCV_ADD32:
228b410d24aSJob Noorman   case ELF::R_RISCV_SUB32:
2299555736aSJob Noorman   case ELF::R_RISCV_HI20:
2309555736aSJob Noorman   case ELF::R_RISCV_LO12_I:
2319555736aSJob Noorman   case ELF::R_RISCV_LO12_S:
232f8730293SJob Noorman     return 4;
233cd7f1714SJob Noorman   case ELF::R_RISCV_64:
234f8730293SJob Noorman   case ELF::R_RISCV_GOT_HI20:
235c7d6d622SJob Noorman   case ELF::R_RISCV_TLS_GOT_HI20:
236f8730293SJob Noorman     // See extractValueRISCV for why this is necessary.
237f8730293SJob Noorman     return 8;
238f8730293SJob Noorman   }
239f8730293SJob Noorman }
240f8730293SJob Noorman 
241be2f67c4SAmir Ayupov static bool skipRelocationTypeX86(uint64_t Type) {
242be2f67c4SAmir Ayupov   return Type == ELF::R_X86_64_NONE;
243be2f67c4SAmir Ayupov }
2446e26ffa0SVladislav Khmelevsky 
245be2f67c4SAmir Ayupov static bool skipRelocationTypeAArch64(uint64_t Type) {
2466e26ffa0SVladislav Khmelevsky   return Type == ELF::R_AARCH64_NONE || Type == ELF::R_AARCH64_LD_PREL_LO19;
2476e26ffa0SVladislav Khmelevsky }
2486e26ffa0SVladislav Khmelevsky 
249f8730293SJob Noorman static bool skipRelocationTypeRISCV(uint64_t Type) {
250f8730293SJob Noorman   switch (Type) {
251f8730293SJob Noorman   default:
252f8730293SJob Noorman     return false;
253f8730293SJob Noorman   case ELF::R_RISCV_NONE:
254f8730293SJob Noorman   case ELF::R_RISCV_RELAX:
255f8730293SJob Noorman     return true;
256f8730293SJob Noorman   }
257f8730293SJob Noorman }
258f8730293SJob Noorman 
259be2f67c4SAmir Ayupov static bool skipRelocationProcessX86(uint64_t &Type, uint64_t Contents) {
260a34c753fSRafael Auler   return false;
261a34c753fSRafael Auler }
262a34c753fSRafael Auler 
263be2f67c4SAmir Ayupov static bool skipRelocationProcessAArch64(uint64_t &Type, uint64_t Contents) {
264a34c753fSRafael Auler   auto IsMov = [](uint64_t Contents) -> bool {
265a34c753fSRafael Auler     // The bits 28-23 are 0b100101
2662f98c5feSVladislav Khmelevsky     return (Contents & 0x1f800000) == 0x12800000;
267a34c753fSRafael Auler   };
268a34c753fSRafael Auler 
269a34c753fSRafael Auler   auto IsB = [](uint64_t Contents) -> bool {
270a34c753fSRafael Auler     // The bits 31-26 are 0b000101
2712f98c5feSVladislav Khmelevsky     return (Contents & 0xfc000000) == 0x14000000;
2722f98c5feSVladislav Khmelevsky   };
2732f98c5feSVladislav Khmelevsky 
2742f98c5feSVladislav Khmelevsky   auto IsAdr = [](uint64_t Contents) -> bool {
2752f98c5feSVladislav Khmelevsky     // The bits 31-24 are 0b0xx10000
2762f98c5feSVladislav Khmelevsky     return (Contents & 0x9f000000) == 0x10000000;
277a34c753fSRafael Auler   };
278a34c753fSRafael Auler 
27917ed8f29SVladislav Khmelevsky   auto IsAddImm = [](uint64_t Contents) -> bool {
28017ed8f29SVladislav Khmelevsky     // The bits 30-23 are 0b00100010
28117ed8f29SVladislav Khmelevsky     return (Contents & 0x7F800000) == 0x11000000;
28217ed8f29SVladislav Khmelevsky   };
28317ed8f29SVladislav Khmelevsky 
28440c2e0faSMaksim Panchenko   auto IsNop = [](uint64_t Contents) -> bool { return Contents == 0xd503201f; };
285a34c753fSRafael Auler 
286a34c753fSRafael Auler   // The linker might eliminate the instruction and replace it with NOP, ignore
287a34c753fSRafael Auler   if (IsNop(Contents))
288a34c753fSRafael Auler     return true;
289a34c753fSRafael Auler 
29017ed8f29SVladislav Khmelevsky   // The linker might relax ADRP+LDR instruction sequence for loading symbol
29117ed8f29SVladislav Khmelevsky   // address from GOT table to ADRP+ADD sequence that would point to the
29217ed8f29SVladislav Khmelevsky   // binary-local symbol. Change relocation type in order to process it right.
29317ed8f29SVladislav Khmelevsky   if (Type == ELF::R_AARCH64_LD64_GOT_LO12_NC && IsAddImm(Contents)) {
29417ed8f29SVladislav Khmelevsky     Type = ELF::R_AARCH64_ADD_ABS_LO12_NC;
29517ed8f29SVladislav Khmelevsky     return false;
29617ed8f29SVladislav Khmelevsky   }
29717ed8f29SVladislav Khmelevsky 
298a34c753fSRafael Auler   // The linker might perform TLS relocations relaxations, such as
299a34c753fSRafael Auler   // changed TLS access model (e.g. changed global dynamic model
300a34c753fSRafael Auler   // to initial exec), thus changing the instructions. The static
301a34c753fSRafael Auler   // relocations might be invalid at this point and we might no
3021a2f8336Sspaette   // need to process these relocations anymore.
303a34c753fSRafael Auler   // More information could be found by searching
304a34c753fSRafael Auler   // elfNN_aarch64_tls_relax in bfd
305a34c753fSRafael Auler   switch (Type) {
306a34c753fSRafael Auler   default:
307a34c753fSRafael Auler     break;
308a34c753fSRafael Auler   case ELF::R_AARCH64_TLSDESC_LD64_LO12:
309a34c753fSRafael Auler   case ELF::R_AARCH64_TLSDESC_ADR_PAGE21:
310a34c753fSRafael Auler   case ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
311a34c753fSRafael Auler   case ELF::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: {
312a34c753fSRafael Auler     if (IsMov(Contents))
313a34c753fSRafael Auler       return true;
314a34c753fSRafael Auler   }
315a34c753fSRafael Auler   }
316a34c753fSRafael Auler 
3172f98c5feSVladislav Khmelevsky   // The linker might replace load/store instruction with jump and
318a34c753fSRafael Auler   // veneer due to errata 843419
319a34c753fSRafael Auler   // https://documentation-service.arm.com/static/5fa29fddb209f547eebd361d
320a34c753fSRafael Auler   // Thus load/store relocations for these instructions must be ignored
321a34c753fSRafael Auler   // NOTE: We only process GOT and TLS relocations this way since the
322a34c753fSRafael Auler   // addend used in load/store instructions won't change after bolt
323a34c753fSRafael Auler   // (it is important since the instruction in veneer won't have relocation)
324a34c753fSRafael Auler   switch (Type) {
325a34c753fSRafael Auler   default:
326a34c753fSRafael Auler     break;
327a34c753fSRafael Auler   case ELF::R_AARCH64_LD64_GOT_LO12_NC:
328a34c753fSRafael Auler   case ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
329a34c753fSRafael Auler   case ELF::R_AARCH64_TLSDESC_LD64_LO12: {
330a34c753fSRafael Auler     if (IsB(Contents))
331a34c753fSRafael Auler       return true;
332a34c753fSRafael Auler   }
333a34c753fSRafael Auler   }
334a34c753fSRafael Auler 
3352f98c5feSVladislav Khmelevsky   // The linker might relax ADRP+ADD or ADRP+LDR sequences to the ADR+NOP
3362f98c5feSVladislav Khmelevsky   switch (Type) {
3372f98c5feSVladislav Khmelevsky   default:
3382f98c5feSVladislav Khmelevsky     break;
3392f98c5feSVladislav Khmelevsky   case ELF::R_AARCH64_ADR_PREL_PG_HI21:
3402f98c5feSVladislav Khmelevsky   case ELF::R_AARCH64_ADD_ABS_LO12_NC:
3412f98c5feSVladislav Khmelevsky   case ELF::R_AARCH64_ADR_GOT_PAGE:
3422f98c5feSVladislav Khmelevsky   case ELF::R_AARCH64_LD64_GOT_LO12_NC:
3432f98c5feSVladislav Khmelevsky     if (IsAdr(Contents))
3442f98c5feSVladislav Khmelevsky       return true;
3452f98c5feSVladislav Khmelevsky   }
3462f98c5feSVladislav Khmelevsky 
347a34c753fSRafael Auler   return false;
348a34c753fSRafael Auler }
349a34c753fSRafael Auler 
350f8730293SJob Noorman static bool skipRelocationProcessRISCV(uint64_t &Type, uint64_t Contents) {
351f8730293SJob Noorman   return false;
352f8730293SJob Noorman }
353f8730293SJob Noorman 
35477811752SRafael Auler static uint64_t encodeValueX86(uint64_t Type, uint64_t Value, uint64_t PC) {
3554a4045f7SElvina Yakubova   switch (Type) {
3564a4045f7SElvina Yakubova   default:
35777811752SRafael Auler     llvm_unreachable("unsupported relocation");
35877811752SRafael Auler   case ELF::R_X86_64_64:
3594a4045f7SElvina Yakubova   case ELF::R_X86_64_32:
3604a4045f7SElvina Yakubova     break;
3614a4045f7SElvina Yakubova   case ELF::R_X86_64_PC32:
3624a4045f7SElvina Yakubova     Value -= PC;
3634a4045f7SElvina Yakubova     break;
3644a4045f7SElvina Yakubova   }
3654a4045f7SElvina Yakubova   return Value;
3664a4045f7SElvina Yakubova }
3674a4045f7SElvina Yakubova 
36877811752SRafael Auler static uint64_t encodeValueAArch64(uint64_t Type, uint64_t Value, uint64_t PC) {
3694a4045f7SElvina Yakubova   switch (Type) {
3704a4045f7SElvina Yakubova   default:
37177811752SRafael Auler     llvm_unreachable("unsupported relocation");
37296b5e092SJob Noorman   case ELF::R_AARCH64_ABS16:
3734a4045f7SElvina Yakubova   case ELF::R_AARCH64_ABS32:
37496b5e092SJob Noorman   case ELF::R_AARCH64_ABS64:
3754a4045f7SElvina Yakubova     break;
37648e894a5SAlexey Moksyakov   case ELF::R_AARCH64_PREL16:
3774a4045f7SElvina Yakubova   case ELF::R_AARCH64_PREL32:
37848e894a5SAlexey Moksyakov   case ELF::R_AARCH64_PREL64:
3794a4045f7SElvina Yakubova     Value -= PC;
3804a4045f7SElvina Yakubova     break;
38162020a3aSzhoujiapeng   case ELF::R_AARCH64_CALL26:
38262020a3aSzhoujiapeng     Value -= PC;
38362020a3aSzhoujiapeng     assert(isInt<28>(Value) && "only PC +/- 128MB is allowed for direct call");
38462020a3aSzhoujiapeng     // Immediate goes in bits 25:0 of BL.
38562020a3aSzhoujiapeng     // OP 1001_01 goes in bits 31:26 of BL.
3867b4b09a5SSinan Lin     Value = ((Value >> 2) & 0x3ffffff) | 0x94000000ULL;
38762020a3aSzhoujiapeng     break;
38871c2a132Ssinan   case ELF::R_AARCH64_JUMP26:
38971c2a132Ssinan     Value -= PC;
39071c2a132Ssinan     assert(isInt<28>(Value) &&
39171c2a132Ssinan            "only PC +/- 128MB is allowed for direct branch");
39271c2a132Ssinan     // Immediate goes in bits 25:0 of B.
39371c2a132Ssinan     // OP 0001_01 goes in bits 31:26 of B.
39471c2a132Ssinan     Value = ((Value >> 2) & 0x3ffffff) | 0x14000000ULL;
39571c2a132Ssinan     break;
3964a4045f7SElvina Yakubova   }
3974a4045f7SElvina Yakubova   return Value;
3984a4045f7SElvina Yakubova }
3994a4045f7SElvina Yakubova 
400cd7f1714SJob Noorman static uint64_t encodeValueRISCV(uint64_t Type, uint64_t Value, uint64_t PC) {
401cd7f1714SJob Noorman   switch (Type) {
402cd7f1714SJob Noorman   default:
403cd7f1714SJob Noorman     llvm_unreachable("unsupported relocation");
404cd7f1714SJob Noorman   case ELF::R_RISCV_64:
405cd7f1714SJob Noorman     break;
406cd7f1714SJob Noorman   }
407cd7f1714SJob Noorman   return Value;
408cd7f1714SJob Noorman }
409cd7f1714SJob Noorman 
410be2f67c4SAmir Ayupov static uint64_t extractValueX86(uint64_t Type, uint64_t Contents, uint64_t PC) {
411a34c753fSRafael Auler   if (Type == ELF::R_X86_64_32S)
4124101aa13SMaksim Panchenko     return SignExtend64<32>(Contents);
4134101aa13SMaksim Panchenko   if (Relocation::isPCRelative(Type))
4144101aa13SMaksim Panchenko     return SignExtend64(Contents, 8 * Relocation::getSizeForType(Type));
415a34c753fSRafael Auler   return Contents;
416a34c753fSRafael Auler }
417a34c753fSRafael Auler 
418be2f67c4SAmir Ayupov static uint64_t extractValueAArch64(uint64_t Type, uint64_t Contents,
419be2f67c4SAmir Ayupov                                     uint64_t PC) {
420a34c753fSRafael Auler   switch (Type) {
421a34c753fSRafael Auler   default:
422eb9f4eb6SAmir Ayupov     errs() << object::getELFRelocationTypeName(ELF::EM_AARCH64, Type) << '\n';
423a34c753fSRafael Auler     llvm_unreachable("unsupported relocation type");
424172deb75SVladislav Khmelevsky   case ELF::R_AARCH64_ABS16:
425172deb75SVladislav Khmelevsky   case ELF::R_AARCH64_ABS32:
426a34c753fSRafael Auler   case ELF::R_AARCH64_ABS64:
427a34c753fSRafael Auler     return Contents;
42848e894a5SAlexey Moksyakov   case ELF::R_AARCH64_PREL16:
42948e894a5SAlexey Moksyakov     return static_cast<int64_t>(PC) + SignExtend64<16>(Contents & 0xffff);
430a34c753fSRafael Auler   case ELF::R_AARCH64_PREL32:
431a34c753fSRafael Auler     return static_cast<int64_t>(PC) + SignExtend64<32>(Contents & 0xffffffff);
43248e894a5SAlexey Moksyakov   case ELF::R_AARCH64_PREL64:
43348e894a5SAlexey Moksyakov     return static_cast<int64_t>(PC) + Contents;
434a34c753fSRafael Auler   case ELF::R_AARCH64_TLSDESC_CALL:
435a34c753fSRafael Auler   case ELF::R_AARCH64_JUMP26:
436a34c753fSRafael Auler   case ELF::R_AARCH64_CALL26:
437a34c753fSRafael Auler     // Immediate goes in bits 25:0 of B and BL.
438a34c753fSRafael Auler     Contents &= ~0xfffffffffc000000ULL;
439a34c753fSRafael Auler     return static_cast<int64_t>(PC) + SignExtend64<28>(Contents << 2);
440a34c753fSRafael Auler   case ELF::R_AARCH64_TSTBR14:
441a34c753fSRafael Auler     // Immediate:15:2 goes in bits 18:5 of TBZ, TBNZ
442a34c753fSRafael Auler     Contents &= ~0xfffffffffff8001fULL;
443a34c753fSRafael Auler     return static_cast<int64_t>(PC) + SignExtend64<16>(Contents >> 3);
444a34c753fSRafael Auler   case ELF::R_AARCH64_CONDBR19:
445a34c753fSRafael Auler     // Immediate:20:2 goes in bits 23:5 of Bcc, CBZ, CBNZ
446a34c753fSRafael Auler     Contents &= ~0xffffffffff00001fULL;
447a34c753fSRafael Auler     return static_cast<int64_t>(PC) + SignExtend64<21>(Contents >> 3);
448a34c753fSRafael Auler   case ELF::R_AARCH64_ADR_GOT_PAGE:
449a34c753fSRafael Auler   case ELF::R_AARCH64_TLSDESC_ADR_PREL21:
450a34c753fSRafael Auler   case ELF::R_AARCH64_TLSDESC_ADR_PAGE21:
451a34c753fSRafael Auler   case ELF::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
452a34c753fSRafael Auler   case ELF::R_AARCH64_ADR_PREL_LO21:
453a34c753fSRafael Auler   case ELF::R_AARCH64_ADR_PREL_PG_HI21:
454a34c753fSRafael Auler   case ELF::R_AARCH64_ADR_PREL_PG_HI21_NC: {
455a34c753fSRafael Auler     // Bits 32:12 of Symbol address goes in bits 30:29 + 23:5 of ADRP
456a34c753fSRafael Auler     // and ADR instructions
457a34c753fSRafael Auler     bool IsAdr = !!(((Contents >> 31) & 0x1) == 0);
458a34c753fSRafael Auler     Contents &= ~0xffffffff9f00001fUll;
459a34c753fSRafael Auler     uint64_t LowBits = (Contents >> 29) & 0x3;
460a34c753fSRafael Auler     uint64_t HighBits = (Contents >> 5) & 0x7ffff;
461a34c753fSRafael Auler     Contents = LowBits | (HighBits << 2);
462a34c753fSRafael Auler     if (IsAdr)
463a34c753fSRafael Auler       return static_cast<int64_t>(PC) + SignExtend64<21>(Contents);
464a34c753fSRafael Auler 
465a34c753fSRafael Auler     // ADRP instruction
466a34c753fSRafael Auler     Contents = static_cast<int64_t>(PC) + SignExtend64<33>(Contents << 12);
467a34c753fSRafael Auler     Contents &= ~0xfffUll;
468a34c753fSRafael Auler     return Contents;
469a34c753fSRafael Auler   }
470a34c753fSRafael Auler   case ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
471a34c753fSRafael Auler   case ELF::R_AARCH64_TLSDESC_LD64_LO12:
472a34c753fSRafael Auler   case ELF::R_AARCH64_LD64_GOT_LO12_NC:
473a34c753fSRafael Auler   case ELF::R_AARCH64_LDST64_ABS_LO12_NC: {
474a34c753fSRafael Auler     // Immediate goes in bits 21:10 of LD/ST instruction, taken
475a34c753fSRafael Auler     // from bits 11:3 of Symbol address
476a34c753fSRafael Auler     Contents &= ~0xffffffffffc003ffU;
477a34c753fSRafael Auler     return Contents >> (10 - 3);
478a34c753fSRafael Auler   }
479a34c753fSRafael Auler   case ELF::R_AARCH64_TLSLE_ADD_TPREL_HI12:
480a34c753fSRafael Auler   case ELF::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
481a34c753fSRafael Auler   case ELF::R_AARCH64_TLSDESC_ADD_LO12:
482a34c753fSRafael Auler   case ELF::R_AARCH64_ADD_ABS_LO12_NC: {
483a34c753fSRafael Auler     // Immediate goes in bits 21:10 of ADD instruction
484a34c753fSRafael Auler     Contents &= ~0xffffffffffc003ffU;
485a34c753fSRafael Auler     return Contents >> (10 - 0);
486a34c753fSRafael Auler   }
487a34c753fSRafael Auler   case ELF::R_AARCH64_LDST128_ABS_LO12_NC: {
488a34c753fSRafael Auler     // Immediate goes in bits 21:10 of ADD instruction, taken
489a34c753fSRafael Auler     // from bits 11:4 of Symbol address
490a34c753fSRafael Auler     Contents &= ~0xffffffffffc003ffU;
491a34c753fSRafael Auler     return Contents >> (10 - 4);
492a34c753fSRafael Auler   }
493a34c753fSRafael Auler   case ELF::R_AARCH64_LDST32_ABS_LO12_NC: {
494a34c753fSRafael Auler     // Immediate goes in bits 21:10 of ADD instruction, taken
495a34c753fSRafael Auler     // from bits 11:2 of Symbol address
496a34c753fSRafael Auler     Contents &= ~0xffffffffffc003ffU;
497a34c753fSRafael Auler     return Contents >> (10 - 2);
498a34c753fSRafael Auler   }
499a34c753fSRafael Auler   case ELF::R_AARCH64_LDST16_ABS_LO12_NC: {
500a34c753fSRafael Auler     // Immediate goes in bits 21:10 of ADD instruction, taken
501a34c753fSRafael Auler     // from bits 11:1 of Symbol address
502a34c753fSRafael Auler     Contents &= ~0xffffffffffc003ffU;
503a34c753fSRafael Auler     return Contents >> (10 - 1);
504a34c753fSRafael Auler   }
505a34c753fSRafael Auler   case ELF::R_AARCH64_LDST8_ABS_LO12_NC: {
506a34c753fSRafael Auler     // Immediate goes in bits 21:10 of ADD instruction, taken
507a34c753fSRafael Auler     // from bits 11:0 of Symbol address
508a34c753fSRafael Auler     Contents &= ~0xffffffffffc003ffU;
509a34c753fSRafael Auler     return Contents >> (10 - 0);
510a34c753fSRafael Auler   }
511a34c753fSRafael Auler   case ELF::R_AARCH64_MOVW_UABS_G3:
512a34c753fSRafael Auler   case ELF::R_AARCH64_MOVW_UABS_G2_NC:
513a34c753fSRafael Auler   case ELF::R_AARCH64_MOVW_UABS_G2:
514a34c753fSRafael Auler   case ELF::R_AARCH64_MOVW_UABS_G1_NC:
515a34c753fSRafael Auler   case ELF::R_AARCH64_MOVW_UABS_G1:
516a34c753fSRafael Auler   case ELF::R_AARCH64_MOVW_UABS_G0_NC:
517a34c753fSRafael Auler   case ELF::R_AARCH64_MOVW_UABS_G0:
5181a2f8336Sspaette     // The shift goes in bits 22:21 of MOV* instructions
519a34c753fSRafael Auler     uint8_t Shift = (Contents >> 21) & 0x3;
520a34c753fSRafael Auler     // Immediate goes in bits 20:5
521a34c753fSRafael Auler     Contents = (Contents >> 5) & 0xffff;
522a34c753fSRafael Auler     return Contents << (16 * Shift);
523a34c753fSRafael Auler   }
524a34c753fSRafael Auler }
525a34c753fSRafael Auler 
526f8730293SJob Noorman static uint64_t extractUImmRISCV(uint32_t Contents) {
527f8730293SJob Noorman   return SignExtend64<32>(Contents & 0xfffff000);
528f8730293SJob Noorman }
529f8730293SJob Noorman 
530f8730293SJob Noorman static uint64_t extractIImmRISCV(uint32_t Contents) {
531f8730293SJob Noorman   return SignExtend64<12>(Contents >> 20);
532f8730293SJob Noorman }
533f8730293SJob Noorman 
5341b78742eSJob Noorman static uint64_t extractSImmRISCV(uint32_t Contents) {
5351b78742eSJob Noorman   return SignExtend64<12>(((Contents >> 7) & 0x1f) | ((Contents >> 25) << 5));
5361b78742eSJob Noorman }
5371b78742eSJob Noorman 
538f8730293SJob Noorman static uint64_t extractJImmRISCV(uint32_t Contents) {
539f8730293SJob Noorman   return SignExtend64<21>(
540f8730293SJob Noorman       (((Contents >> 21) & 0x3ff) << 1) | (((Contents >> 20) & 0x1) << 11) |
541f8730293SJob Noorman       (((Contents >> 12) & 0xff) << 12) | (((Contents >> 31) & 0x1) << 20));
542f8730293SJob Noorman }
543f8730293SJob Noorman 
544f8730293SJob Noorman static uint64_t extractBImmRISCV(uint32_t Contents) {
545f8730293SJob Noorman   return SignExtend64<13>(
546f8730293SJob Noorman       (((Contents >> 8) & 0xf) << 1) | (((Contents >> 25) & 0x3f) << 5) |
547f8730293SJob Noorman       (((Contents >> 7) & 0x1) << 11) | (((Contents >> 31) & 0x1) << 12));
548f8730293SJob Noorman }
549f8730293SJob Noorman 
550f8730293SJob Noorman static uint64_t extractValueRISCV(uint64_t Type, uint64_t Contents,
551f8730293SJob Noorman                                   uint64_t PC) {
552f8730293SJob Noorman   switch (Type) {
553f8730293SJob Noorman   default:
554f8730293SJob Noorman     errs() << object::getELFRelocationTypeName(ELF::EM_RISCV, Type) << '\n';
555f8730293SJob Noorman     llvm_unreachable("unsupported relocation type");
556f8730293SJob Noorman   case ELF::R_RISCV_JAL:
557f8730293SJob Noorman     return extractJImmRISCV(Contents);
558f8730293SJob Noorman   case ELF::R_RISCV_CALL:
559f8730293SJob Noorman   case ELF::R_RISCV_CALL_PLT:
560f8730293SJob Noorman     return extractUImmRISCV(Contents);
561f8730293SJob Noorman   case ELF::R_RISCV_BRANCH:
562f8730293SJob Noorman     return extractBImmRISCV(Contents);
563f8730293SJob Noorman   case ELF::R_RISCV_GOT_HI20:
564c7d6d622SJob Noorman   case ELF::R_RISCV_TLS_GOT_HI20:
565f8730293SJob Noorman     // We need to know the exact address of the GOT entry so we extract the
566f8730293SJob Noorman     // value from both the AUIPC and L[D|W]. We cannot rely on the symbol in the
567f8730293SJob Noorman     // relocation for this since it simply refers to the object that is stored
568f8730293SJob Noorman     // in the GOT entry, not to the entry itself.
569f8730293SJob Noorman     return extractUImmRISCV(Contents & 0xffffffff) +
570f8730293SJob Noorman            extractIImmRISCV(Contents >> 32);
571f8730293SJob Noorman   case ELF::R_RISCV_PCREL_HI20:
5729555736aSJob Noorman   case ELF::R_RISCV_HI20:
573f8730293SJob Noorman     return extractUImmRISCV(Contents);
574f8730293SJob Noorman   case ELF::R_RISCV_PCREL_LO12_I:
5759555736aSJob Noorman   case ELF::R_RISCV_LO12_I:
576f8730293SJob Noorman     return extractIImmRISCV(Contents);
5771b78742eSJob Noorman   case ELF::R_RISCV_PCREL_LO12_S:
5789555736aSJob Noorman   case ELF::R_RISCV_LO12_S:
5791b78742eSJob Noorman     return extractSImmRISCV(Contents);
580f8730293SJob Noorman   case ELF::R_RISCV_RVC_JUMP:
581f8730293SJob Noorman     return SignExtend64<11>(Contents >> 2);
582f8730293SJob Noorman   case ELF::R_RISCV_RVC_BRANCH:
583f8730293SJob Noorman     return SignExtend64<8>(((Contents >> 2) & 0x1f) | ((Contents >> 5) & 0xe0));
584b410d24aSJob Noorman   case ELF::R_RISCV_ADD32:
585b410d24aSJob Noorman   case ELF::R_RISCV_SUB32:
586cd7f1714SJob Noorman   case ELF::R_RISCV_64:
587b410d24aSJob Noorman     return Contents;
588f8730293SJob Noorman   }
589f8730293SJob Noorman }
590f8730293SJob Noorman 
591be2f67c4SAmir Ayupov static bool isGOTX86(uint64_t Type) {
592a34c753fSRafael Auler   switch (Type) {
593a34c753fSRafael Auler   default:
594a34c753fSRafael Auler     return false;
595a34c753fSRafael Auler   case ELF::R_X86_64_GOT32:
596a34c753fSRafael Auler   case ELF::R_X86_64_GOTPCREL:
597a34c753fSRafael Auler   case ELF::R_X86_64_GOTTPOFF:
598a34c753fSRafael Auler   case ELF::R_X86_64_GOTOFF64:
599a34c753fSRafael Auler   case ELF::R_X86_64_GOTPC32:
600a34c753fSRafael Auler   case ELF::R_X86_64_GOT64:
601a34c753fSRafael Auler   case ELF::R_X86_64_GOTPCREL64:
602a34c753fSRafael Auler   case ELF::R_X86_64_GOTPC64:
603a34c753fSRafael Auler   case ELF::R_X86_64_GOTPLT64:
604a34c753fSRafael Auler   case ELF::R_X86_64_GOTPC32_TLSDESC:
605a34c753fSRafael Auler   case ELF::R_X86_64_GOTPCRELX:
606a34c753fSRafael Auler   case ELF::R_X86_64_REX_GOTPCRELX:
607a34c753fSRafael Auler     return true;
608a34c753fSRafael Auler   }
609a34c753fSRafael Auler }
610a34c753fSRafael Auler 
611be2f67c4SAmir Ayupov static bool isGOTAArch64(uint64_t Type) {
612a34c753fSRafael Auler   switch (Type) {
613a34c753fSRafael Auler   default:
614a34c753fSRafael Auler     return false;
615a34c753fSRafael Auler   case ELF::R_AARCH64_ADR_GOT_PAGE:
616a34c753fSRafael Auler   case ELF::R_AARCH64_LD64_GOT_LO12_NC:
617a34c753fSRafael Auler   case ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
618a34c753fSRafael Auler   case ELF::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
619a34c753fSRafael Auler   case ELF::R_AARCH64_TLSDESC_ADR_PREL21:
620a34c753fSRafael Auler   case ELF::R_AARCH64_TLSDESC_ADR_PAGE21:
621a34c753fSRafael Auler   case ELF::R_AARCH64_TLSDESC_LD64_LO12:
622a34c753fSRafael Auler   case ELF::R_AARCH64_TLSDESC_ADD_LO12:
623a34c753fSRafael Auler   case ELF::R_AARCH64_TLSDESC_CALL:
624a34c753fSRafael Auler     return true;
625a34c753fSRafael Auler   }
626a34c753fSRafael Auler }
627a34c753fSRafael Auler 
628f8730293SJob Noorman static bool isGOTRISCV(uint64_t Type) {
629f8730293SJob Noorman   switch (Type) {
630f8730293SJob Noorman   default:
631f8730293SJob Noorman     return false;
632f8730293SJob Noorman   case ELF::R_RISCV_GOT_HI20:
633c7d6d622SJob Noorman   case ELF::R_RISCV_TLS_GOT_HI20:
634f8730293SJob Noorman     return true;
635f8730293SJob Noorman   }
636f8730293SJob Noorman }
637f8730293SJob Noorman 
638be2f67c4SAmir Ayupov static bool isTLSX86(uint64_t Type) {
639a34c753fSRafael Auler   switch (Type) {
640a34c753fSRafael Auler   default:
641a34c753fSRafael Auler     return false;
642a34c753fSRafael Auler   case ELF::R_X86_64_TPOFF32:
643a34c753fSRafael Auler   case ELF::R_X86_64_TPOFF64:
644a34c753fSRafael Auler   case ELF::R_X86_64_GOTTPOFF:
645a34c753fSRafael Auler     return true;
646a34c753fSRafael Auler   }
647a34c753fSRafael Auler }
648a34c753fSRafael Auler 
649be2f67c4SAmir Ayupov static bool isTLSAArch64(uint64_t Type) {
650a34c753fSRafael Auler   switch (Type) {
651a34c753fSRafael Auler   default:
652a34c753fSRafael Auler     return false;
653a34c753fSRafael Auler   case ELF::R_AARCH64_TLSDESC_ADR_PREL21:
654a34c753fSRafael Auler   case ELF::R_AARCH64_TLSDESC_ADR_PAGE21:
655a34c753fSRafael Auler   case ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
656a34c753fSRafael Auler   case ELF::R_AARCH64_TLSLE_ADD_TPREL_HI12:
657a34c753fSRafael Auler   case ELF::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
658*e11d49cbSAlexey Moksyakov   case ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0:
659*e11d49cbSAlexey Moksyakov   case ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0_NC:
660a34c753fSRafael Auler   case ELF::R_AARCH64_TLSDESC_LD64_LO12:
661a34c753fSRafael Auler   case ELF::R_AARCH64_TLSDESC_ADD_LO12:
662a34c753fSRafael Auler   case ELF::R_AARCH64_TLSDESC_CALL:
663a34c753fSRafael Auler   case ELF::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
664a34c753fSRafael Auler     return true;
665a34c753fSRafael Auler   }
666a34c753fSRafael Auler }
667a34c753fSRafael Auler 
668f8730293SJob Noorman static bool isTLSRISCV(uint64_t Type) {
669f8730293SJob Noorman   switch (Type) {
670f8730293SJob Noorman   default:
671f8730293SJob Noorman     return false;
672c7d6d622SJob Noorman   case ELF::R_RISCV_TLS_GOT_HI20:
673c7d6d622SJob Noorman   case ELF::R_RISCV_TPREL_HI20:
674c7d6d622SJob Noorman   case ELF::R_RISCV_TPREL_ADD:
675c7d6d622SJob Noorman   case ELF::R_RISCV_TPREL_LO12_I:
676c7d6d622SJob Noorman   case ELF::R_RISCV_TPREL_LO12_S:
677c7d6d622SJob Noorman   case ELFReserved::R_RISCV_TPREL_I:
678c7d6d622SJob Noorman   case ELFReserved::R_RISCV_TPREL_S:
679c7d6d622SJob Noorman     return true;
680f8730293SJob Noorman   }
681f8730293SJob Noorman }
682f8730293SJob Noorman 
683be2f67c4SAmir Ayupov static bool isPCRelativeX86(uint64_t Type) {
684a34c753fSRafael Auler   switch (Type) {
685a34c753fSRafael Auler   default:
686a34c753fSRafael Auler     llvm_unreachable("Unknown relocation type");
687a34c753fSRafael Auler   case ELF::R_X86_64_64:
688a34c753fSRafael Auler   case ELF::R_X86_64_32:
689a34c753fSRafael Auler   case ELF::R_X86_64_32S:
690a34c753fSRafael Auler   case ELF::R_X86_64_16:
691a34c753fSRafael Auler   case ELF::R_X86_64_8:
692a34c753fSRafael Auler   case ELF::R_X86_64_TPOFF32:
693a34c753fSRafael Auler     return false;
694a34c753fSRafael Auler   case ELF::R_X86_64_PC8:
695a34c753fSRafael Auler   case ELF::R_X86_64_PC32:
696a34c753fSRafael Auler   case ELF::R_X86_64_PC64:
697a34c753fSRafael Auler   case ELF::R_X86_64_GOTPCREL:
698a34c753fSRafael Auler   case ELF::R_X86_64_PLT32:
6994101aa13SMaksim Panchenko   case ELF::R_X86_64_GOTOFF64:
7004101aa13SMaksim Panchenko   case ELF::R_X86_64_GOTPC32:
701853e126cSRafael Auler   case ELF::R_X86_64_GOTPC64:
702a34c753fSRafael Auler   case ELF::R_X86_64_GOTTPOFF:
703a34c753fSRafael Auler   case ELF::R_X86_64_GOTPCRELX:
704a34c753fSRafael Auler   case ELF::R_X86_64_REX_GOTPCRELX:
705a34c753fSRafael Auler     return true;
706a34c753fSRafael Auler   }
707a34c753fSRafael Auler }
708a34c753fSRafael Auler 
709be2f67c4SAmir Ayupov static bool isPCRelativeAArch64(uint64_t Type) {
710a34c753fSRafael Auler   switch (Type) {
711a34c753fSRafael Auler   default:
712a34c753fSRafael Auler     llvm_unreachable("Unknown relocation type");
713172deb75SVladislav Khmelevsky   case ELF::R_AARCH64_ABS16:
714172deb75SVladislav Khmelevsky   case ELF::R_AARCH64_ABS32:
715a34c753fSRafael Auler   case ELF::R_AARCH64_ABS64:
716a34c753fSRafael Auler   case ELF::R_AARCH64_LDST64_ABS_LO12_NC:
717a34c753fSRafael Auler   case ELF::R_AARCH64_ADD_ABS_LO12_NC:
718a34c753fSRafael Auler   case ELF::R_AARCH64_LDST128_ABS_LO12_NC:
719a34c753fSRafael Auler   case ELF::R_AARCH64_LDST32_ABS_LO12_NC:
720a34c753fSRafael Auler   case ELF::R_AARCH64_LDST16_ABS_LO12_NC:
721a34c753fSRafael Auler   case ELF::R_AARCH64_LDST8_ABS_LO12_NC:
722a34c753fSRafael Auler   case ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
723a34c753fSRafael Auler   case ELF::R_AARCH64_TLSLE_ADD_TPREL_HI12:
724a34c753fSRafael Auler   case ELF::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
725*e11d49cbSAlexey Moksyakov   case ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0:
726*e11d49cbSAlexey Moksyakov   case ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0_NC:
727a34c753fSRafael Auler   case ELF::R_AARCH64_LD64_GOT_LO12_NC:
728a34c753fSRafael Auler   case ELF::R_AARCH64_TLSDESC_LD64_LO12:
729a34c753fSRafael Auler   case ELF::R_AARCH64_TLSDESC_ADD_LO12:
730a34c753fSRafael Auler   case ELF::R_AARCH64_MOVW_UABS_G0:
731a34c753fSRafael Auler   case ELF::R_AARCH64_MOVW_UABS_G0_NC:
732a34c753fSRafael Auler   case ELF::R_AARCH64_MOVW_UABS_G1:
733a34c753fSRafael Auler   case ELF::R_AARCH64_MOVW_UABS_G1_NC:
734a34c753fSRafael Auler   case ELF::R_AARCH64_MOVW_UABS_G2:
735a34c753fSRafael Auler   case ELF::R_AARCH64_MOVW_UABS_G2_NC:
736a34c753fSRafael Auler   case ELF::R_AARCH64_MOVW_UABS_G3:
737a34c753fSRafael Auler     return false;
738a34c753fSRafael Auler   case ELF::R_AARCH64_TLSDESC_CALL:
739a34c753fSRafael Auler   case ELF::R_AARCH64_CALL26:
740a34c753fSRafael Auler   case ELF::R_AARCH64_JUMP26:
741a34c753fSRafael Auler   case ELF::R_AARCH64_TSTBR14:
742a34c753fSRafael Auler   case ELF::R_AARCH64_CONDBR19:
743a34c753fSRafael Auler   case ELF::R_AARCH64_ADR_PREL_LO21:
744a34c753fSRafael Auler   case ELF::R_AARCH64_ADR_PREL_PG_HI21:
745a34c753fSRafael Auler   case ELF::R_AARCH64_ADR_PREL_PG_HI21_NC:
746a34c753fSRafael Auler   case ELF::R_AARCH64_ADR_GOT_PAGE:
747a34c753fSRafael Auler   case ELF::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
748a34c753fSRafael Auler   case ELF::R_AARCH64_TLSDESC_ADR_PREL21:
749a34c753fSRafael Auler   case ELF::R_AARCH64_TLSDESC_ADR_PAGE21:
75048e894a5SAlexey Moksyakov   case ELF::R_AARCH64_PREL16:
751a34c753fSRafael Auler   case ELF::R_AARCH64_PREL32:
75248e894a5SAlexey Moksyakov   case ELF::R_AARCH64_PREL64:
753a34c753fSRafael Auler     return true;
754a34c753fSRafael Auler   }
755a34c753fSRafael Auler }
756a34c753fSRafael Auler 
757f8730293SJob Noorman static bool isPCRelativeRISCV(uint64_t Type) {
758f8730293SJob Noorman   switch (Type) {
759f8730293SJob Noorman   default:
760f8730293SJob Noorman     llvm_unreachable("Unknown relocation type");
761b410d24aSJob Noorman   case ELF::R_RISCV_ADD32:
762b410d24aSJob Noorman   case ELF::R_RISCV_SUB32:
7639555736aSJob Noorman   case ELF::R_RISCV_HI20:
7649555736aSJob Noorman   case ELF::R_RISCV_LO12_I:
7659555736aSJob Noorman   case ELF::R_RISCV_LO12_S:
766cd7f1714SJob Noorman   case ELF::R_RISCV_64:
767b410d24aSJob Noorman     return false;
768f8730293SJob Noorman   case ELF::R_RISCV_JAL:
769f8730293SJob Noorman   case ELF::R_RISCV_CALL:
770f8730293SJob Noorman   case ELF::R_RISCV_CALL_PLT:
771f8730293SJob Noorman   case ELF::R_RISCV_BRANCH:
772f8730293SJob Noorman   case ELF::R_RISCV_GOT_HI20:
773f8730293SJob Noorman   case ELF::R_RISCV_PCREL_HI20:
774f8730293SJob Noorman   case ELF::R_RISCV_PCREL_LO12_I:
7751b78742eSJob Noorman   case ELF::R_RISCV_PCREL_LO12_S:
776f8730293SJob Noorman   case ELF::R_RISCV_RVC_JUMP:
777f8730293SJob Noorman   case ELF::R_RISCV_RVC_BRANCH:
778f8730293SJob Noorman   case ELF::R_RISCV_32_PCREL:
779c7d6d622SJob Noorman   case ELF::R_RISCV_TLS_GOT_HI20:
780f8730293SJob Noorman     return true;
781f8730293SJob Noorman   }
782f8730293SJob Noorman }
783f8730293SJob Noorman 
784a34c753fSRafael Auler bool Relocation::isSupported(uint64_t Type) {
7854308c742SNathan Sidwell   switch (Arch) {
7864308c742SNathan Sidwell   default:
7874308c742SNathan Sidwell     return false;
7884308c742SNathan Sidwell   case Triple::aarch64:
789a34c753fSRafael Auler     return isSupportedAArch64(Type);
7904308c742SNathan Sidwell   case Triple::riscv64:
791f8730293SJob Noorman     return isSupportedRISCV(Type);
7924308c742SNathan Sidwell   case Triple::x86_64:
793a34c753fSRafael Auler     return isSupportedX86(Type);
794a34c753fSRafael Auler   }
7954308c742SNathan Sidwell }
796a34c753fSRafael Auler 
797a34c753fSRafael Auler size_t Relocation::getSizeForType(uint64_t Type) {
7984308c742SNathan Sidwell   switch (Arch) {
7994308c742SNathan Sidwell   default:
8004308c742SNathan Sidwell     llvm_unreachable("Unsupported architecture");
8014308c742SNathan Sidwell   case Triple::aarch64:
802a34c753fSRafael Auler     return getSizeForTypeAArch64(Type);
8034308c742SNathan Sidwell   case Triple::riscv64:
804f8730293SJob Noorman     return getSizeForTypeRISCV(Type);
8054308c742SNathan Sidwell   case Triple::x86_64:
806a34c753fSRafael Auler     return getSizeForTypeX86(Type);
807a34c753fSRafael Auler   }
8084308c742SNathan Sidwell }
809a34c753fSRafael Auler 
8106e26ffa0SVladislav Khmelevsky bool Relocation::skipRelocationType(uint64_t Type) {
8114308c742SNathan Sidwell   switch (Arch) {
8124308c742SNathan Sidwell   default:
8134308c742SNathan Sidwell     llvm_unreachable("Unsupported architecture");
8144308c742SNathan Sidwell   case Triple::aarch64:
8156e26ffa0SVladislav Khmelevsky     return skipRelocationTypeAArch64(Type);
8164308c742SNathan Sidwell   case Triple::riscv64:
817f8730293SJob Noorman     return skipRelocationTypeRISCV(Type);
8184308c742SNathan Sidwell   case Triple::x86_64:
8196e26ffa0SVladislav Khmelevsky     return skipRelocationTypeX86(Type);
8206e26ffa0SVladislav Khmelevsky   }
8214308c742SNathan Sidwell }
8226e26ffa0SVladislav Khmelevsky 
82317ed8f29SVladislav Khmelevsky bool Relocation::skipRelocationProcess(uint64_t &Type, uint64_t Contents) {
8244308c742SNathan Sidwell   switch (Arch) {
8254308c742SNathan Sidwell   default:
8264308c742SNathan Sidwell     llvm_unreachable("Unsupported architecture");
8274308c742SNathan Sidwell   case Triple::aarch64:
828a34c753fSRafael Auler     return skipRelocationProcessAArch64(Type, Contents);
8294308c742SNathan Sidwell   case Triple::riscv64:
8304308c742SNathan Sidwell     return skipRelocationProcessRISCV(Type, Contents);
8314308c742SNathan Sidwell   case Triple::x86_64:
832a34c753fSRafael Auler     return skipRelocationProcessX86(Type, Contents);
833a34c753fSRafael Auler   }
8344308c742SNathan Sidwell }
835a34c753fSRafael Auler 
83677811752SRafael Auler uint64_t Relocation::encodeValue(uint64_t Type, uint64_t Value, uint64_t PC) {
8374308c742SNathan Sidwell   switch (Arch) {
8384308c742SNathan Sidwell   default:
8394308c742SNathan Sidwell     llvm_unreachable("Unsupported architecture");
8404308c742SNathan Sidwell   case Triple::aarch64:
84177811752SRafael Auler     return encodeValueAArch64(Type, Value, PC);
8424308c742SNathan Sidwell   case Triple::riscv64:
843cd7f1714SJob Noorman     return encodeValueRISCV(Type, Value, PC);
8444308c742SNathan Sidwell   case Triple::x86_64:
84577811752SRafael Auler     return encodeValueX86(Type, Value, PC);
8464a4045f7SElvina Yakubova   }
8474308c742SNathan Sidwell }
8484a4045f7SElvina Yakubova 
849a34c753fSRafael Auler uint64_t Relocation::extractValue(uint64_t Type, uint64_t Contents,
850a34c753fSRafael Auler                                   uint64_t PC) {
8514308c742SNathan Sidwell   switch (Arch) {
8524308c742SNathan Sidwell   default:
8534308c742SNathan Sidwell     llvm_unreachable("Unsupported architecture");
8544308c742SNathan Sidwell   case Triple::aarch64:
855a34c753fSRafael Auler     return extractValueAArch64(Type, Contents, PC);
8564308c742SNathan Sidwell   case Triple::riscv64:
857f8730293SJob Noorman     return extractValueRISCV(Type, Contents, PC);
8584308c742SNathan Sidwell   case Triple::x86_64:
859a34c753fSRafael Auler     return extractValueX86(Type, Contents, PC);
860a34c753fSRafael Auler   }
8614308c742SNathan Sidwell }
862a34c753fSRafael Auler 
863a34c753fSRafael Auler bool Relocation::isGOT(uint64_t Type) {
8644308c742SNathan Sidwell   switch (Arch) {
8654308c742SNathan Sidwell   default:
8664308c742SNathan Sidwell     llvm_unreachable("Unsupported architecture");
8674308c742SNathan Sidwell   case Triple::aarch64:
868a34c753fSRafael Auler     return isGOTAArch64(Type);
8694308c742SNathan Sidwell   case Triple::riscv64:
870f8730293SJob Noorman     return isGOTRISCV(Type);
8714308c742SNathan Sidwell   case Triple::x86_64:
872a34c753fSRafael Auler     return isGOTX86(Type);
873a34c753fSRafael Auler   }
8744308c742SNathan Sidwell }
875a34c753fSRafael Auler 
87618176426SMaksim Panchenko bool Relocation::isX86GOTPCRELX(uint64_t Type) {
87718176426SMaksim Panchenko   if (Arch != Triple::x86_64)
87818176426SMaksim Panchenko     return false;
87918176426SMaksim Panchenko   return Type == ELF::R_X86_64_GOTPCRELX || Type == ELF::R_X86_64_REX_GOTPCRELX;
88018176426SMaksim Panchenko }
88118176426SMaksim Panchenko 
882853e126cSRafael Auler bool Relocation::isX86GOTPC64(uint64_t Type) {
883853e126cSRafael Auler   if (Arch != Triple::x86_64)
884853e126cSRafael Auler     return false;
885853e126cSRafael Auler   return Type == ELF::R_X86_64_GOTPC64;
886853e126cSRafael Auler }
887853e126cSRafael Auler 
888228970f6Sspupyrev bool Relocation::isNone(uint64_t Type) { return Type == getNone(); }
889a34c753fSRafael Auler 
890a34c753fSRafael Auler bool Relocation::isRelative(uint64_t Type) {
8914308c742SNathan Sidwell   switch (Arch) {
8924308c742SNathan Sidwell   default:
8934308c742SNathan Sidwell     llvm_unreachable("Unsupported architecture");
8944308c742SNathan Sidwell   case Triple::aarch64:
895a34c753fSRafael Auler     return Type == ELF::R_AARCH64_RELATIVE;
8964308c742SNathan Sidwell   case Triple::riscv64:
897f8730293SJob Noorman     return Type == ELF::R_RISCV_RELATIVE;
8984308c742SNathan Sidwell   case Triple::x86_64:
899a34c753fSRafael Auler     return Type == ELF::R_X86_64_RELATIVE;
900a34c753fSRafael Auler   }
9014308c742SNathan Sidwell }
902a34c753fSRafael Auler 
903a34c753fSRafael Auler bool Relocation::isIRelative(uint64_t Type) {
9044308c742SNathan Sidwell   switch (Arch) {
9054308c742SNathan Sidwell   default:
9064308c742SNathan Sidwell     llvm_unreachable("Unsupported architecture");
9074308c742SNathan Sidwell   case Triple::aarch64:
908a34c753fSRafael Auler     return Type == ELF::R_AARCH64_IRELATIVE;
9094308c742SNathan Sidwell   case Triple::riscv64:
910f8730293SJob Noorman     llvm_unreachable("not implemented");
9114308c742SNathan Sidwell   case Triple::x86_64:
912a34c753fSRafael Auler     return Type == ELF::R_X86_64_IRELATIVE;
913a34c753fSRafael Auler   }
9144308c742SNathan Sidwell }
915a34c753fSRafael Auler 
916a34c753fSRafael Auler bool Relocation::isTLS(uint64_t Type) {
9174308c742SNathan Sidwell   switch (Arch) {
9184308c742SNathan Sidwell   default:
9194308c742SNathan Sidwell     llvm_unreachable("Unsupported architecture");
9204308c742SNathan Sidwell   case Triple::aarch64:
921a34c753fSRafael Auler     return isTLSAArch64(Type);
9224308c742SNathan Sidwell   case Triple::riscv64:
923f8730293SJob Noorman     return isTLSRISCV(Type);
9244308c742SNathan Sidwell   case Triple::x86_64:
925a34c753fSRafael Auler     return isTLSX86(Type);
926a34c753fSRafael Auler   }
9274308c742SNathan Sidwell }
928a34c753fSRafael Auler 
929ff5e2babSJob Noorman bool Relocation::isInstructionReference(uint64_t Type) {
930ff5e2babSJob Noorman   if (Arch != Triple::riscv64)
931ff5e2babSJob Noorman     return false;
932ff5e2babSJob Noorman 
933ff5e2babSJob Noorman   switch (Type) {
934ff5e2babSJob Noorman   default:
935ff5e2babSJob Noorman     return false;
936ff5e2babSJob Noorman   case ELF::R_RISCV_PCREL_LO12_I:
937ff5e2babSJob Noorman   case ELF::R_RISCV_PCREL_LO12_S:
938ff5e2babSJob Noorman     return true;
939ff5e2babSJob Noorman   }
940ff5e2babSJob Noorman }
941ff5e2babSJob Noorman 
942228970f6Sspupyrev uint64_t Relocation::getNone() {
9434308c742SNathan Sidwell   switch (Arch) {
9444308c742SNathan Sidwell   default:
9454308c742SNathan Sidwell     llvm_unreachable("Unsupported architecture");
9464308c742SNathan Sidwell   case Triple::aarch64:
947228970f6Sspupyrev     return ELF::R_AARCH64_NONE;
9484308c742SNathan Sidwell   case Triple::riscv64:
949f8730293SJob Noorman     return ELF::R_RISCV_NONE;
9504308c742SNathan Sidwell   case Triple::x86_64:
951228970f6Sspupyrev     return ELF::R_X86_64_NONE;
952a34c753fSRafael Auler   }
9534308c742SNathan Sidwell }
954a34c753fSRafael Auler 
955a34c753fSRafael Auler uint64_t Relocation::getPC32() {
9564308c742SNathan Sidwell   switch (Arch) {
9574308c742SNathan Sidwell   default:
9584308c742SNathan Sidwell     llvm_unreachable("Unsupported architecture");
9594308c742SNathan Sidwell   case Triple::aarch64:
960a34c753fSRafael Auler     return ELF::R_AARCH64_PREL32;
9614308c742SNathan Sidwell   case Triple::riscv64:
962f8730293SJob Noorman     return ELF::R_RISCV_32_PCREL;
9634308c742SNathan Sidwell   case Triple::x86_64:
964a34c753fSRafael Auler     return ELF::R_X86_64_PC32;
965a34c753fSRafael Auler   }
9664308c742SNathan Sidwell }
967a34c753fSRafael Auler 
968a34c753fSRafael Auler uint64_t Relocation::getPC64() {
9694308c742SNathan Sidwell   switch (Arch) {
9704308c742SNathan Sidwell   default:
9714308c742SNathan Sidwell     llvm_unreachable("Unsupported architecture");
9724308c742SNathan Sidwell   case Triple::aarch64:
973a34c753fSRafael Auler     return ELF::R_AARCH64_PREL64;
9744308c742SNathan Sidwell   case Triple::riscv64:
975f8730293SJob Noorman     llvm_unreachable("not implemented");
9764308c742SNathan Sidwell   case Triple::x86_64:
977a34c753fSRafael Auler     return ELF::R_X86_64_PC64;
978a34c753fSRafael Auler   }
9794308c742SNathan Sidwell }
980a34c753fSRafael Auler 
981228970f6Sspupyrev bool Relocation::isPCRelative(uint64_t Type) {
9824308c742SNathan Sidwell   switch (Arch) {
9834308c742SNathan Sidwell   default:
9844308c742SNathan Sidwell     llvm_unreachable("Unsupported architecture");
9854308c742SNathan Sidwell   case Triple::aarch64:
986228970f6Sspupyrev     return isPCRelativeAArch64(Type);
9874308c742SNathan Sidwell   case Triple::riscv64:
988f8730293SJob Noorman     return isPCRelativeRISCV(Type);
9894308c742SNathan Sidwell   case Triple::x86_64:
990228970f6Sspupyrev     return isPCRelativeX86(Type);
991228970f6Sspupyrev   }
9924308c742SNathan Sidwell }
993228970f6Sspupyrev 
994b0d1f87bSVladislav Khmelevsky uint64_t Relocation::getAbs64() {
9954308c742SNathan Sidwell   switch (Arch) {
9964308c742SNathan Sidwell   default:
9974308c742SNathan Sidwell     llvm_unreachable("Unsupported architecture");
9984308c742SNathan Sidwell   case Triple::aarch64:
999b0d1f87bSVladislav Khmelevsky     return ELF::R_AARCH64_ABS64;
10004308c742SNathan Sidwell   case Triple::riscv64:
1001cd7f1714SJob Noorman     return ELF::R_RISCV_64;
10024308c742SNathan Sidwell   case Triple::x86_64:
1003b0d1f87bSVladislav Khmelevsky     return ELF::R_X86_64_64;
1004b0d1f87bSVladislav Khmelevsky   }
10054308c742SNathan Sidwell }
1006b0d1f87bSVladislav Khmelevsky 
1007f9bf9f92SVladislav Khmelevsky uint64_t Relocation::getRelative() {
10084308c742SNathan Sidwell   switch (Arch) {
10094308c742SNathan Sidwell   default:
10104308c742SNathan Sidwell     llvm_unreachable("Unsupported architecture");
10114308c742SNathan Sidwell   case Triple::aarch64:
1012f9bf9f92SVladislav Khmelevsky     return ELF::R_AARCH64_RELATIVE;
10134308c742SNathan Sidwell   case Triple::riscv64:
10144308c742SNathan Sidwell     llvm_unreachable("not implemented");
10154308c742SNathan Sidwell   case Triple::x86_64:
1016f9bf9f92SVladislav Khmelevsky     return ELF::R_X86_64_RELATIVE;
1017f9bf9f92SVladislav Khmelevsky   }
10184308c742SNathan Sidwell }
1019f9bf9f92SVladislav Khmelevsky 
1020a34c753fSRafael Auler size_t Relocation::emit(MCStreamer *Streamer) const {
1021a34c753fSRafael Auler   const size_t Size = getSizeForType(Type);
1022b4bb6211SJob Noorman   const auto *Value = createExpr(Streamer);
1023b4bb6211SJob Noorman   Streamer->emitValue(Value, Size);
1024b4bb6211SJob Noorman   return Size;
1025a34c753fSRafael Auler }
1026b4bb6211SJob Noorman 
1027b4bb6211SJob Noorman const MCExpr *Relocation::createExpr(MCStreamer *Streamer) const {
1028b4bb6211SJob Noorman   MCContext &Ctx = Streamer->getContext();
1029b4bb6211SJob Noorman   const MCExpr *Value = nullptr;
1030b4bb6211SJob Noorman 
1031b4bb6211SJob Noorman   if (Symbol && Addend) {
1032b4bb6211SJob Noorman     Value = MCBinaryExpr::createAdd(MCSymbolRefExpr::create(Symbol, Ctx),
1033b4bb6211SJob Noorman                                     MCConstantExpr::create(Addend, Ctx), Ctx);
1034b4bb6211SJob Noorman   } else if (Symbol) {
1035b4bb6211SJob Noorman     Value = MCSymbolRefExpr::create(Symbol, Ctx);
1036a34c753fSRafael Auler   } else {
1037a34c753fSRafael Auler     Value = MCConstantExpr::create(Addend, Ctx);
1038a34c753fSRafael Auler   }
1039b4bb6211SJob Noorman 
1040b4bb6211SJob Noorman   if (isPCRelative(Type)) {
1041b4bb6211SJob Noorman     MCSymbol *TempLabel = Ctx.createNamedTempSymbol();
1042b4bb6211SJob Noorman     Streamer->emitLabel(TempLabel);
104340c2e0faSMaksim Panchenko     Value = MCBinaryExpr::createSub(
104440c2e0faSMaksim Panchenko         Value, MCSymbolRefExpr::create(TempLabel, Ctx), Ctx);
1045a34c753fSRafael Auler   }
1046a34c753fSRafael Auler 
1047b4bb6211SJob Noorman   return Value;
1048a34c753fSRafael Auler }
1049a34c753fSRafael Auler 
1050b4bb6211SJob Noorman const MCExpr *Relocation::createExpr(MCStreamer *Streamer,
1051b4bb6211SJob Noorman                                      const MCExpr *RetainedValue) const {
1052b4bb6211SJob Noorman   const auto *Value = createExpr(Streamer);
1053b4bb6211SJob Noorman 
1054b4bb6211SJob Noorman   if (RetainedValue) {
1055b4bb6211SJob Noorman     Value = MCBinaryExpr::create(getComposeOpcodeFor(Type), RetainedValue,
1056b4bb6211SJob Noorman                                  Value, Streamer->getContext());
1057b4bb6211SJob Noorman   }
1058b4bb6211SJob Noorman 
1059b4bb6211SJob Noorman   return Value;
1060b4bb6211SJob Noorman }
1061b4bb6211SJob Noorman 
1062b4bb6211SJob Noorman MCBinaryExpr::Opcode Relocation::getComposeOpcodeFor(uint64_t Type) {
1063b410d24aSJob Noorman   assert(Arch == Triple::riscv64 && "only implemented for RISC-V");
1064b410d24aSJob Noorman 
1065b410d24aSJob Noorman   switch (Type) {
1066b410d24aSJob Noorman   default:
1067b4bb6211SJob Noorman     llvm_unreachable("not implemented");
1068b410d24aSJob Noorman   case ELF::R_RISCV_ADD32:
1069b410d24aSJob Noorman     return MCBinaryExpr::Add;
1070b410d24aSJob Noorman   case ELF::R_RISCV_SUB32:
1071b410d24aSJob Noorman     return MCBinaryExpr::Sub;
1072b410d24aSJob Noorman   }
1073a34c753fSRafael Auler }
1074a34c753fSRafael Auler 
1075a34c753fSRafael Auler void Relocation::print(raw_ostream &OS) const {
10764308c742SNathan Sidwell   switch (Arch) {
10774308c742SNathan Sidwell   default:
10784308c742SNathan Sidwell     OS << "RType:" << Twine::utohexstr(Type);
10794308c742SNathan Sidwell     break;
10804308c742SNathan Sidwell 
10814308c742SNathan Sidwell   case Triple::aarch64:
108267e733d3SNathan Sidwell     static const char *const AArch64RelocNames[] = {
108367e733d3SNathan Sidwell #define ELF_RELOC(name, value) #name,
108467e733d3SNathan Sidwell #include "llvm/BinaryFormat/ELFRelocs/AArch64.def"
108567e733d3SNathan Sidwell #undef ELF_RELOC
108667e733d3SNathan Sidwell     };
108767e733d3SNathan Sidwell     assert(Type < ArrayRef(AArch64RelocNames).size());
1088a34c753fSRafael Auler     OS << AArch64RelocNames[Type];
10894308c742SNathan Sidwell     break;
10904308c742SNathan Sidwell 
10914308c742SNathan Sidwell   case Triple::riscv64:
1092f8730293SJob Noorman     // RISC-V relocations are not sequentially numbered so we cannot use an
1093f8730293SJob Noorman     // array
1094f8730293SJob Noorman     switch (Type) {
1095f8730293SJob Noorman     default:
1096f8730293SJob Noorman       llvm_unreachable("illegal RISC-V relocation");
1097f8730293SJob Noorman #define ELF_RELOC(name, value)                                                 \
1098f8730293SJob Noorman   case value:                                                                  \
1099f8730293SJob Noorman     OS << #name;                                                               \
1100f8730293SJob Noorman     break;
1101f8730293SJob Noorman #include "llvm/BinaryFormat/ELFRelocs/RISCV.def"
110267e733d3SNathan Sidwell #undef ELF_RELOC
1103f8730293SJob Noorman     }
11044308c742SNathan Sidwell     break;
11054308c742SNathan Sidwell 
11064308c742SNathan Sidwell   case Triple::x86_64:
110767e733d3SNathan Sidwell     static const char *const X86RelocNames[] = {
110867e733d3SNathan Sidwell #define ELF_RELOC(name, value) #name,
110967e733d3SNathan Sidwell #include "llvm/BinaryFormat/ELFRelocs/x86_64.def"
111067e733d3SNathan Sidwell #undef ELF_RELOC
111167e733d3SNathan Sidwell     };
111267e733d3SNathan Sidwell     assert(Type < ArrayRef(X86RelocNames).size());
1113a34c753fSRafael Auler     OS << X86RelocNames[Type];
11144308c742SNathan Sidwell     break;
11154308c742SNathan Sidwell   }
1116a34c753fSRafael Auler   OS << ", 0x" << Twine::utohexstr(Offset);
1117a34c753fSRafael Auler   if (Symbol) {
1118a34c753fSRafael Auler     OS << ", " << Symbol->getName();
1119a34c753fSRafael Auler   }
1120a34c753fSRafael Auler   if (int64_t(Addend) < 0)
1121a34c753fSRafael Auler     OS << ", -0x" << Twine::utohexstr(-int64_t(Addend));
1122a34c753fSRafael Auler   else
1123a34c753fSRafael Auler     OS << ", 0x" << Twine::utohexstr(Addend);
1124a34c753fSRafael Auler   OS << ", 0x" << Twine::utohexstr(Value);
1125a34c753fSRafael Auler }
1126