1 //===- AArch64Relocator.cpp ----------------------------------------------===//
2 //
3 // The MCLinker Project
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "mcld/LinkerConfig.h"
11 #include "mcld/IRBuilder.h"
12 #include "mcld/Support/MsgHandling.h"
13 #include "mcld/LD/LDSymbol.h"
14 #include "mcld/LD/ELFFileFormat.h"
15 #include "mcld/Object/ObjectBuilder.h"
16
17 #include "AArch64Relocator.h"
18 #include "AArch64RelocationFunctions.h"
19 #include "AArch64RelocationHelpers.h"
20
21 #include <llvm/ADT/Twine.h>
22 #include <llvm/Support/DataTypes.h>
23 #include <llvm/Support/ELF.h>
24 #include <llvm/Support/Host.h>
25
26 namespace mcld {
27
28 //===----------------------------------------------------------------------===//
29 // Relocation Functions and Tables
30 //===----------------------------------------------------------------------===//
31 DECL_AARCH64_APPLY_RELOC_FUNCS
32
33 /// the prototype of applying function
34 typedef Relocator::Result (*ApplyFunctionType)(Relocation& pReloc,
35 AArch64Relocator& pParent);
36
37 // the table entry of applying functions
38 class ApplyFunctionEntry {
39 public:
ApplyFunctionEntry()40 ApplyFunctionEntry() {}
ApplyFunctionEntry(ApplyFunctionType pFunc,const char * pName,size_t pSize=0)41 ApplyFunctionEntry(ApplyFunctionType pFunc,
42 const char* pName,
43 size_t pSize = 0)
44 : func(pFunc), name(pName), size(pSize) {}
45 ApplyFunctionType func;
46 const char* name;
47 size_t size;
48 };
49 typedef std::map<Relocator::Type, ApplyFunctionEntry> ApplyFunctionMap;
50
51 static const ApplyFunctionMap::value_type ApplyFunctionList[] = {
52 DECL_AARCH64_APPLY_RELOC_FUNC_PTRS(ApplyFunctionMap::value_type,
53 ApplyFunctionEntry)};
54
55 // declare the table of applying functions
56 static ApplyFunctionMap ApplyFunctions(ApplyFunctionList,
57 ApplyFunctionList +
58 sizeof(ApplyFunctionList) /
59 sizeof(ApplyFunctionList[0]));
60
61 //===----------------------------------------------------------------------===//
62 // AArch64Relocator
63 //===----------------------------------------------------------------------===//
AArch64Relocator(AArch64GNULDBackend & pParent,const LinkerConfig & pConfig)64 AArch64Relocator::AArch64Relocator(AArch64GNULDBackend& pParent,
65 const LinkerConfig& pConfig)
66 : Relocator(pConfig), m_Target(pParent) {
67 }
68
~AArch64Relocator()69 AArch64Relocator::~AArch64Relocator() {
70 }
71
applyRelocation(Relocation & pRelocation)72 Relocator::Result AArch64Relocator::applyRelocation(Relocation& pRelocation) {
73 Relocation::Type type = pRelocation.type();
74 // valid types are 0x0, 0x100-1032, and R_AARCH64_REWRITE_INSN
75 if ((type < 0x100 || type > 1032) &&
76 (type != 0x0) &&
77 (type != R_AARCH64_REWRITE_INSN)) {
78 return Relocator::Unknown;
79 }
80 assert(ApplyFunctions.find(type) != ApplyFunctions.end());
81 return ApplyFunctions[type].func(pRelocation, *this);
82 }
83
getName(Relocator::Type pType) const84 const char* AArch64Relocator::getName(Relocator::Type pType) const {
85 assert(ApplyFunctions.find(pType) != ApplyFunctions.end());
86 return ApplyFunctions[pType].name;
87 }
88
getSize(Relocation::Type pType) const89 Relocator::Size AArch64Relocator::getSize(Relocation::Type pType) const {
90 return ApplyFunctions[pType].size;
91 }
92
addCopyReloc(ResolveInfo & pSym)93 void AArch64Relocator::addCopyReloc(ResolveInfo& pSym) {
94 Relocation& rel_entry = *getTarget().getRelaDyn().create();
95 rel_entry.setType(llvm::ELF::R_AARCH64_COPY);
96 assert(pSym.outSymbol()->hasFragRef());
97 rel_entry.targetRef().assign(*pSym.outSymbol()->fragRef());
98 rel_entry.setSymInfo(&pSym);
99 }
100
101 /// defineSymbolForCopyReloc
102 /// For a symbol needing copy relocation, define a copy symbol in the BSS
103 /// section and all other reference to this symbol should refer to this
104 /// copy.
105 /// This is executed at scan relocation stage.
defineSymbolforCopyReloc(IRBuilder & pBuilder,const ResolveInfo & pSym)106 LDSymbol& AArch64Relocator::defineSymbolforCopyReloc(IRBuilder& pBuilder,
107 const ResolveInfo& pSym) {
108 // get or create corresponding BSS LDSection
109 LDSection* bss_sect_hdr = NULL;
110 ELFFileFormat* file_format = getTarget().getOutputFormat();
111 if (ResolveInfo::ThreadLocal == pSym.type())
112 bss_sect_hdr = &file_format->getTBSS();
113 else
114 bss_sect_hdr = &file_format->getBSS();
115
116 // get or create corresponding BSS SectionData
117 SectionData* bss_data = NULL;
118 if (bss_sect_hdr->hasSectionData())
119 bss_data = bss_sect_hdr->getSectionData();
120 else
121 bss_data = IRBuilder::CreateSectionData(*bss_sect_hdr);
122
123 // Determine the alignment by the symbol value
124 // FIXME: here we use the largest alignment
125 uint32_t addralign = config().targets().bitclass() / 8;
126
127 // allocate space in BSS for the copy symbol
128 Fragment* frag = new FillFragment(0x0, 1, pSym.size());
129 uint64_t size = ObjectBuilder::AppendFragment(*frag, *bss_data, addralign);
130 bss_sect_hdr->setSize(bss_sect_hdr->size() + size);
131
132 // change symbol binding to Global if it's a weak symbol
133 ResolveInfo::Binding binding = (ResolveInfo::Binding)pSym.binding();
134 if (binding == ResolveInfo::Weak)
135 binding = ResolveInfo::Global;
136
137 // Define the copy symbol in the bss section and resolve it
138 LDSymbol* cpy_sym = pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>(
139 pSym.name(),
140 (ResolveInfo::Type)pSym.type(),
141 ResolveInfo::Define,
142 binding,
143 pSym.size(), // size
144 0x0, // value
145 FragmentRef::Create(*frag, 0x0),
146 (ResolveInfo::Visibility)pSym.other());
147
148 return *cpy_sym;
149 }
150
scanLocalReloc(Relocation & pReloc,const LDSection & pSection)151 void AArch64Relocator::scanLocalReloc(Relocation& pReloc,
152 const LDSection& pSection) {
153 // rsym - The relocation target symbol
154 ResolveInfo* rsym = pReloc.symInfo();
155 switch (pReloc.type()) {
156 case llvm::ELF::R_AARCH64_ABS64:
157 // If buiding PIC object (shared library or PIC executable),
158 // a dynamic relocations with RELATIVE type to this location is needed.
159 // Reserve an entry in .rel.dyn
160 if (config().isCodeIndep()) {
161 // set Rel bit
162 rsym->setReserved(rsym->reserved() | ReserveRel);
163 getTarget().checkAndSetHasTextRel(*pSection.getLink());
164 // set up the dyn rel directly
165 Relocation& reloc = helper_DynRela_init(rsym,
166 *pReloc.targetRef().frag(),
167 pReloc.targetRef().offset(),
168 llvm::ELF::R_AARCH64_RELATIVE,
169 *this);
170 getRelRelMap().record(pReloc, reloc);
171 }
172 return;
173
174 case llvm::ELF::R_AARCH64_ABS32:
175 case llvm::ELF::R_AARCH64_ABS16:
176 // If buiding PIC object (shared library or PIC executable),
177 // a dynamic relocations with RELATIVE type to this location is needed.
178 // Reserve an entry in .rel.dyn
179 if (config().isCodeIndep()) {
180 // set up the dyn rel directly
181 Relocation& reloc = helper_DynRela_init(rsym,
182 *pReloc.targetRef().frag(),
183 pReloc.targetRef().offset(),
184 pReloc.type(),
185 *this);
186 getRelRelMap().record(pReloc, reloc);
187 // set Rel bit
188 rsym->setReserved(rsym->reserved() | ReserveRel);
189 getTarget().checkAndSetHasTextRel(*pSection.getLink());
190 }
191 return;
192
193 case llvm::ELF::R_AARCH64_ADR_GOT_PAGE:
194 case llvm::ELF::R_AARCH64_LD64_GOT_LO12_NC: {
195 // Symbol needs GOT entry, reserve entry in .got
196 // return if we already create GOT for this symbol
197 if (rsym->reserved() & ReserveGOT)
198 return;
199 // If building PIC object, a dynamic relocation with
200 // type RELATIVE is needed to relocate this GOT entry.
201 if (config().isCodeIndep())
202 helper_GOT_init(pReloc, true, *this);
203 else
204 helper_GOT_init(pReloc, false, *this);
205 // set GOT bit
206 rsym->setReserved(rsym->reserved() | ReserveGOT);
207 return;
208 }
209
210 default:
211 break;
212 }
213 }
214
scanGlobalReloc(Relocation & pReloc,IRBuilder & pBuilder,const LDSection & pSection)215 void AArch64Relocator::scanGlobalReloc(Relocation& pReloc,
216 IRBuilder& pBuilder,
217 const LDSection& pSection) {
218 // rsym - The relocation target symbol
219 ResolveInfo* rsym = pReloc.symInfo();
220 switch (pReloc.type()) {
221 case llvm::ELF::R_AARCH64_ABS64:
222 case llvm::ELF::R_AARCH64_ABS32:
223 case llvm::ELF::R_AARCH64_ABS16:
224 // Absolute relocation type, symbol may needs PLT entry or
225 // dynamic relocation entry
226 if (getTarget().symbolNeedsPLT(*rsym)) {
227 // create plt for this symbol if it does not have one
228 if (!(rsym->reserved() & ReservePLT)) {
229 // Symbol needs PLT entry, we need a PLT entry
230 // and the corresponding GOT and dynamic relocation entry
231 // in .got and .rel.plt.
232 helper_PLT_init(pReloc, *this);
233 // set PLT bit
234 rsym->setReserved(rsym->reserved() | ReservePLT);
235 }
236 }
237
238 if (getTarget()
239 .symbolNeedsDynRel(
240 *rsym, (rsym->reserved() & ReservePLT), true)) {
241 // symbol needs dynamic relocation entry, set up the dynrel entry
242 if (getTarget().symbolNeedsCopyReloc(pReloc, *rsym)) {
243 LDSymbol& cpy_sym = defineSymbolforCopyReloc(pBuilder, *rsym);
244 addCopyReloc(*cpy_sym.resolveInfo());
245 } else {
246 // set Rel bit and the dyn rel
247 rsym->setReserved(rsym->reserved() | ReserveRel);
248 getTarget().checkAndSetHasTextRel(*pSection.getLink());
249 if (llvm::ELF::R_AARCH64_ABS64 == pReloc.type() &&
250 helper_use_relative_reloc(*rsym, *this)) {
251 Relocation& reloc =
252 helper_DynRela_init(rsym,
253 *pReloc.targetRef().frag(),
254 pReloc.targetRef().offset(),
255 llvm::ELF::R_AARCH64_RELATIVE,
256 *this);
257 getRelRelMap().record(pReloc, reloc);
258 } else {
259 Relocation& reloc = helper_DynRela_init(rsym,
260 *pReloc.targetRef().frag(),
261 pReloc.targetRef().offset(),
262 pReloc.type(),
263 *this);
264 getRelRelMap().record(pReloc, reloc);
265 }
266 }
267 }
268 return;
269
270 case llvm::ELF::R_AARCH64_PREL64:
271 case llvm::ELF::R_AARCH64_PREL32:
272 case llvm::ELF::R_AARCH64_PREL16:
273 if (getTarget().symbolNeedsPLT(*rsym) &&
274 LinkerConfig::DynObj != config().codeGenType()) {
275 // create plt for this symbol if it does not have one
276 if (!(rsym->reserved() & ReservePLT)) {
277 // Symbol needs PLT entry, we need a PLT entry
278 // and the corresponding GOT and dynamic relocation entry
279 // in .got and .rel.plt.
280 helper_PLT_init(pReloc, *this);
281 // set PLT bit
282 rsym->setReserved(rsym->reserved() | ReservePLT);
283 }
284 }
285
286 // Only PC relative relocation against dynamic symbol needs a
287 // dynamic relocation. Only dynamic copy relocation is allowed
288 // and PC relative relocation will be resolved to the local copy.
289 // All other dynamic relocations may lead to run-time relocation
290 // overflow.
291 if (getTarget().isDynamicSymbol(*rsym) &&
292 getTarget()
293 .symbolNeedsDynRel(
294 *rsym, (rsym->reserved() & ReservePLT), false) &&
295 getTarget().symbolNeedsCopyReloc(pReloc, *rsym)) {
296 LDSymbol& cpy_sym = defineSymbolforCopyReloc(pBuilder, *rsym);
297 addCopyReloc(*cpy_sym.resolveInfo());
298 }
299 return;
300
301 case llvm::ELF::R_AARCH64_CONDBR19:
302 case llvm::ELF::R_AARCH64_JUMP26:
303 case llvm::ELF::R_AARCH64_CALL26: {
304 // return if we already create plt for this symbol
305 if (rsym->reserved() & ReservePLT)
306 return;
307
308 // if the symbol's value can be decided at link time, then no need plt
309 if (getTarget().symbolFinalValueIsKnown(*rsym))
310 return;
311
312 // if symbol is defined in the ouput file and it's not
313 // preemptible, no need plt
314 if (rsym->isDefine() && !rsym->isDyn() &&
315 !getTarget().isSymbolPreemptible(*rsym)) {
316 return;
317 }
318
319 // Symbol needs PLT entry, we need to reserve a PLT entry
320 // and the corresponding GOT and dynamic relocation entry
321 // in .got and .rel.plt.
322 helper_PLT_init(pReloc, *this);
323 // set PLT bit
324 rsym->setReserved(rsym->reserved() | ReservePLT);
325 return;
326 }
327
328 case llvm::ELF::R_AARCH64_ADR_PREL_LO21:
329 case llvm::ELF::R_AARCH64_ADR_PREL_PG_HI21:
330 case llvm::ELF::R_AARCH64_ADR_PREL_PG_HI21_NC:
331 if (getTarget()
332 .symbolNeedsDynRel(
333 *rsym, (rsym->reserved() & ReservePLT), false)) {
334 if (getTarget().symbolNeedsCopyReloc(pReloc, *rsym)) {
335 LDSymbol& cpy_sym = defineSymbolforCopyReloc(pBuilder, *rsym);
336 addCopyReloc(*cpy_sym.resolveInfo());
337 }
338 }
339 if (getTarget().symbolNeedsPLT(*rsym)) {
340 // create plt for this symbol if it does not have one
341 if (!(rsym->reserved() & ReservePLT)) {
342 // Symbol needs PLT entry, we need a PLT entry
343 // and the corresponding GOT and dynamic relocation entry
344 // in .got and .rel.plt.
345 helper_PLT_init(pReloc, *this);
346 // set PLT bit
347 rsym->setReserved(rsym->reserved() | ReservePLT);
348 }
349 }
350 return;
351
352 case llvm::ELF::R_AARCH64_ADR_GOT_PAGE:
353 case llvm::ELF::R_AARCH64_LD64_GOT_LO12_NC: {
354 // Symbol needs GOT entry, reserve entry in .got
355 // return if we already create GOT for this symbol
356 if (rsym->reserved() & ReserveGOT)
357 return;
358 // if the symbol cannot be fully resolved at link time, then we need a
359 // dynamic relocation
360 if (!getTarget().symbolFinalValueIsKnown(*rsym))
361 helper_GOT_init(pReloc, true, *this);
362 else
363 helper_GOT_init(pReloc, false, *this);
364 // set GOT bit
365 rsym->setReserved(rsym->reserved() | ReserveGOT);
366 return;
367 }
368
369 default:
370 break;
371 }
372 }
373
scanRelocation(Relocation & pReloc,IRBuilder & pBuilder,Module & pModule,LDSection & pSection,Input & pInput)374 void AArch64Relocator::scanRelocation(Relocation& pReloc,
375 IRBuilder& pBuilder,
376 Module& pModule,
377 LDSection& pSection,
378 Input& pInput) {
379 ResolveInfo* rsym = pReloc.symInfo();
380 assert(rsym != NULL &&
381 "ResolveInfo of relocation not set while scanRelocation");
382
383 assert(pSection.getLink() != NULL);
384 if ((pSection.getLink()->flag() & llvm::ELF::SHF_ALLOC) == 0)
385 return;
386
387 // Scan relocation type to determine if an GOT/PLT/Dynamic Relocation
388 // entries should be created.
389 // FIXME: Below judgements concern nothing about TLS related relocation
390
391 // rsym is local
392 if (rsym->isLocal())
393 scanLocalReloc(pReloc, pSection);
394 // rsym is external
395 else
396 scanGlobalReloc(pReloc, pBuilder, pSection);
397
398 // check if we shoule issue undefined reference for the relocation target
399 // symbol
400 if (rsym->isUndef() && !rsym->isDyn() && !rsym->isWeak() && !rsym->isNull())
401 issueUndefRef(pReloc, pSection, pInput);
402 }
403
404 bool
mayHaveFunctionPointerAccess(const Relocation & pReloc) const405 AArch64Relocator::mayHaveFunctionPointerAccess(const Relocation& pReloc) const {
406 switch (pReloc.type()) {
407 case llvm::ELF::R_AARCH64_ADR_PREL_PG_HI21:
408 case llvm::ELF::R_AARCH64_ADR_PREL_PG_HI21_NC:
409 case llvm::ELF::R_AARCH64_ADD_ABS_LO12_NC:
410 case llvm::ELF::R_AARCH64_ADR_GOT_PAGE:
411 case llvm::ELF::R_AARCH64_LD64_GOT_LO12_NC: {
412 return true;
413 }
414 default: {
415 if (pReloc.symInfo()->isLocal()) {
416 // Do not fold any local symbols if building a shared object.
417 return (config().codeGenType() == LinkerConfig::DynObj);
418 } else {
419 // Do not fold any none global defualt symbols if building a shared
420 // object.
421 return ((config().codeGenType() == LinkerConfig::DynObj) &&
422 (pReloc.symInfo()->visibility() != ResolveInfo::Default));
423 }
424 }
425 }
426 return false;
427 }
428
getDebugStringOffset(Relocation & pReloc) const429 uint32_t AArch64Relocator::getDebugStringOffset(Relocation& pReloc) const {
430 if (pReloc.type() != llvm::ELF::R_AARCH64_ABS32)
431 error(diag::unsupport_reloc_for_debug_string)
432 << getName(pReloc.type()) << "mclinker@googlegroups.com";
433
434 if (pReloc.symInfo()->type() == ResolveInfo::Section)
435 return pReloc.target() + pReloc.addend();
436 else
437 return pReloc.symInfo()->outSymbol()->fragRef()->offset() +
438 pReloc.target() + pReloc.addend();
439 }
440
applyDebugStringOffset(Relocation & pReloc,uint32_t pOffset)441 void AArch64Relocator::applyDebugStringOffset(Relocation& pReloc,
442 uint32_t pOffset) {
443 pReloc.target() = pOffset;
444 }
445
446 //===----------------------------------------------------------------------===//
447 // Each relocation function implementation
448 //===----------------------------------------------------------------------===//
449
450 // R_AARCH64_NONE
none(Relocation & pReloc,AArch64Relocator & pParent)451 Relocator::Result none(Relocation& pReloc, AArch64Relocator& pParent) {
452 return Relocator::OK;
453 }
454
unsupported(Relocation & pReloc,AArch64Relocator & pParent)455 Relocator::Result unsupported(Relocation& pReloc, AArch64Relocator& pParent) {
456 return Relocator::Unsupported;
457 }
458
459 // R_AARCH64_ABS64: S + A
460 // R_AARCH64_ABS32: S + A
461 // R_AARCH64_ABS16: S + A
abs(Relocation & pReloc,AArch64Relocator & pParent)462 Relocator::Result abs(Relocation& pReloc, AArch64Relocator& pParent) {
463 ResolveInfo* rsym = pReloc.symInfo();
464 Relocator::DWord A = pReloc.target() + pReloc.addend();
465 Relocator::DWord S = pReloc.symValue();
466 Relocation* dyn_rel = pParent.getRelRelMap().lookUp(pReloc);
467 bool has_dyn_rel = (dyn_rel != NULL);
468
469 LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection();
470 // If the flag of target section is not ALLOC, we will not scan this
471 // relocation but perform static relocation. (e.g., applying .debug section)
472 if (0x0 == (llvm::ELF::SHF_ALLOC & target_sect.flag())) {
473 pReloc.target() = S + A;
474 return Relocator::OK;
475 }
476 // A local symbol may need RELATIVE Type dynamic relocation
477 if (rsym->isLocal() && has_dyn_rel) {
478 dyn_rel->setAddend(S + A);
479 }
480
481 // An external symbol may need PLT and dynamic relocation
482 if (!rsym->isLocal()) {
483 if (rsym->reserved() & AArch64Relocator::ReservePLT) {
484 S = helper_get_PLT_address(*rsym, pParent);
485 }
486 // If we generate a dynamic relocation (except R_AARCH64_64_RELATIVE)
487 // for a place, we should not perform static relocation on it
488 // in order to keep the addend store in the place correct.
489 if (has_dyn_rel) {
490 if (llvm::ELF::R_AARCH64_ABS64 == pReloc.type() &&
491 llvm::ELF::R_AARCH64_RELATIVE == dyn_rel->type()) {
492 dyn_rel->setAddend(S + A);
493 } else {
494 dyn_rel->setAddend(A);
495 return Relocator::OK;
496 }
497 }
498 }
499
500 // perform static relocation
501 pReloc.target() = S + A;
502 return Relocator::OK;
503 }
504
505 // R_AARCH64_PREL64: S + A - P
506 // R_AARCH64_PREL32: S + A - P
507 // R_AARCH64_PREL16: S + A - P
rel(Relocation & pReloc,AArch64Relocator & pParent)508 Relocator::Result rel(Relocation& pReloc, AArch64Relocator& pParent) {
509 ResolveInfo* rsym = pReloc.symInfo();
510 Relocator::Address S = pReloc.symValue();
511 Relocator::DWord A = pReloc.addend();
512 Relocator::DWord P = pReloc.place();
513
514 if (llvm::ELF::R_AARCH64_PREL64 != pReloc.type())
515 A += pReloc.target() & get_mask(pParent.getSize(pReloc.type()));
516 else
517 A += pReloc.target();
518
519 LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection();
520 // If the flag of target section is not ALLOC, we will not scan this
521 // relocation but perform static relocation. (e.g., applying .debug section)
522 if (0x0 != (llvm::ELF::SHF_ALLOC & target_sect.flag())) {
523 // if plt entry exists, the S value is the plt entry address
524 if (!rsym->isLocal()) {
525 if (rsym->reserved() & AArch64Relocator::ReservePLT) {
526 S = helper_get_PLT_address(*rsym, pParent);
527 }
528 }
529 }
530
531 Relocator::DWord X = S + A - P;
532 pReloc.target() = X;
533
534 if (llvm::ELF::R_AARCH64_PREL64 != pReloc.type() &&
535 helper_check_signed_overflow(X, pParent.getSize(pReloc.type())))
536 return Relocator::Overflow;
537 return Relocator::OK;
538 }
539
540 // R_AARCH64_ADD_ABS_LO12_NC: S + A
add_abs_lo12(Relocation & pReloc,AArch64Relocator & pParent)541 Relocator::Result add_abs_lo12(Relocation& pReloc, AArch64Relocator& pParent) {
542 Relocator::Address value = 0x0;
543 Relocator::Address S = pReloc.symValue();
544 Relocator::DWord A = pReloc.addend();
545
546 value = helper_get_page_offset(S + A);
547 pReloc.target() = helper_reencode_add_imm(pReloc.target(), value);
548
549 return Relocator::OK;
550 }
551
552 // R_AARCH64_ADR_PREL_LO21: S + A - P
adr_prel_lo21(Relocation & pReloc,AArch64Relocator & pParent)553 Relocator::Result adr_prel_lo21(Relocation& pReloc, AArch64Relocator& pParent) {
554 ResolveInfo* rsym = pReloc.symInfo();
555 Relocator::Address S = pReloc.symValue();
556 // if plt entry exists, the S value is the plt entry address
557 if (rsym->reserved() & AArch64Relocator::ReservePLT) {
558 S = helper_get_PLT_address(*rsym, pParent);
559 }
560 Relocator::DWord A = pReloc.addend();
561 Relocator::DWord P = pReloc.place();
562 Relocator::DWord X = S + A - P;
563
564 pReloc.target() = helper_reencode_adr_imm(pReloc.target(), X);
565
566 return Relocator::OK;
567 }
568
569 // R_AARCH64_ADR_PREL_PG_HI21: ((PG(S + A) - PG(P)) >> 12)
570 // R_AARCH64_ADR_PREL_PG_HI21_NC: ((PG(S + A) - PG(P)) >> 12)
adr_prel_pg_hi21(Relocation & pReloc,AArch64Relocator & pParent)571 Relocator::Result adr_prel_pg_hi21(Relocation& pReloc,
572 AArch64Relocator& pParent) {
573 ResolveInfo* rsym = pReloc.symInfo();
574 Relocator::Address S = pReloc.symValue();
575 // if plt entry exists, the S value is the plt entry address
576 if (rsym->reserved() & AArch64Relocator::ReservePLT) {
577 S = helper_get_PLT_address(*rsym, pParent);
578 }
579 Relocator::DWord A = pReloc.addend();
580 Relocator::DWord P = pReloc.place();
581 Relocator::DWord X =
582 helper_get_page_address(S + A) - helper_get_page_address(P);
583
584 pReloc.target() = helper_reencode_adr_imm(pReloc.target(), (X >> 12));
585
586 return Relocator::OK;
587 }
588
589 // R_AARCH64_CALL26: S + A - P
590 // R_AARCH64_JUMP26: S + A - P
call(Relocation & pReloc,AArch64Relocator & pParent)591 Relocator::Result call(Relocation& pReloc, AArch64Relocator& pParent) {
592 // If target is undefined weak symbol, we only need to jump to the
593 // next instruction unless it has PLT entry. Rewrite instruction
594 // to NOP.
595 if (pReloc.symInfo()->isWeak() && pReloc.symInfo()->isUndef() &&
596 !pReloc.symInfo()->isDyn() &&
597 !(pReloc.symInfo()->reserved() & AArch64Relocator::ReservePLT)) {
598 // change target to NOP
599 pReloc.target() = 0xd503201f;
600 return Relocator::OK;
601 }
602
603 Relocator::Address S = pReloc.symValue();
604 Relocator::DWord A = pReloc.addend();
605 Relocator::Address P = pReloc.place();
606
607 // S depends on PLT exists or not
608 if (pReloc.symInfo()->reserved() & AArch64Relocator::ReservePLT)
609 S = helper_get_PLT_address(*pReloc.symInfo(), pParent);
610
611 Relocator::DWord X = S + A - P;
612 // TODO: check overflow..
613
614 pReloc.target() = helper_reencode_branch_offset_26(pReloc.target(), X >> 2);
615
616 return Relocator::OK;
617 }
618
619 // R_AARCH64_CONDBR19: S + A - P
condbr(Relocation & pReloc,AArch64Relocator & pParent)620 Relocator::Result condbr(Relocation& pReloc, AArch64Relocator& pParent) {
621 // If target is undefined weak symbol, we only need to jump to the
622 // next instruction unless it has PLT entry. Rewrite instruction
623 // to NOP.
624 if (pReloc.symInfo()->isWeak() && pReloc.symInfo()->isUndef() &&
625 !pReloc.symInfo()->isDyn() &&
626 !(pReloc.symInfo()->reserved() & AArch64Relocator::ReservePLT)) {
627 // change target to NOP
628 pReloc.target() = 0xd503201f;
629 return Relocator::OK;
630 }
631
632 Relocator::Address S = pReloc.symValue();
633 Relocator::DWord A = pReloc.addend();
634 Relocator::Address P = pReloc.place();
635
636 // S depends on PLT exists or not
637 if (pReloc.symInfo()->reserved() & AArch64Relocator::ReservePLT)
638 S = helper_get_PLT_address(*pReloc.symInfo(), pParent);
639
640 Relocator::DWord X = S + A - P;
641 // TODO: check overflow..
642
643 pReloc.target() = helper_reencode_cond_branch_ofs_19(pReloc.target(), X >> 2);
644
645 return Relocator::OK;
646 }
647
648 // R_AARCH64_ADR_GOT_PAGE: Page(G(GDAT(S+A))) - Page(P)
adr_got_page(Relocation & pReloc,AArch64Relocator & pParent)649 Relocator::Result adr_got_page(Relocation& pReloc, AArch64Relocator& pParent) {
650 if (!(pReloc.symInfo()->reserved() & AArch64Relocator::ReserveGOT)) {
651 return Relocator::BadReloc;
652 }
653
654 Relocator::Address GOT_S = helper_get_GOT_address(*pReloc.symInfo(), pParent);
655 Relocator::DWord A = pReloc.addend();
656 Relocator::Address P = pReloc.place();
657 Relocator::DWord X =
658 helper_get_page_address(GOT_S + A) - helper_get_page_address(P);
659
660 pReloc.target() = helper_reencode_adr_imm(pReloc.target(), (X >> 12));
661
662 // setup got entry value if needed
663 AArch64GOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*pReloc.symInfo());
664 if (got_entry != NULL && AArch64Relocator::SymVal == got_entry->getValue())
665 got_entry->setValue(pReloc.symValue());
666 // setup relocation addend if needed
667 Relocation* dyn_rela = pParent.getRelRelMap().lookUp(pReloc);
668 if ((dyn_rela != NULL) && (AArch64Relocator::SymVal == dyn_rela->addend())) {
669 dyn_rela->setAddend(pReloc.symValue());
670 }
671 return Relocator::OK;
672 }
673
674 // R_AARCH64_LD64_GOT_LO12_NC: G(GDAT(S+A))
ld64_got_lo12(Relocation & pReloc,AArch64Relocator & pParent)675 Relocator::Result ld64_got_lo12(Relocation& pReloc, AArch64Relocator& pParent) {
676 if (!(pReloc.symInfo()->reserved() & AArch64Relocator::ReserveGOT)) {
677 return Relocator::BadReloc;
678 }
679
680 Relocator::Address GOT_S = helper_get_GOT_address(*pReloc.symInfo(), pParent);
681 Relocator::DWord A = pReloc.addend();
682 Relocator::DWord X = helper_get_page_offset(GOT_S + A);
683
684 pReloc.target() = helper_reencode_ldst_pos_imm(pReloc.target(), (X >> 3));
685
686 // setup got entry value if needed
687 AArch64GOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*pReloc.symInfo());
688 if (got_entry != NULL && AArch64Relocator::SymVal == got_entry->getValue())
689 got_entry->setValue(pReloc.symValue());
690
691 // setup relocation addend if needed
692 Relocation* dyn_rela = pParent.getRelRelMap().lookUp(pReloc);
693 if ((dyn_rela != NULL) && (AArch64Relocator::SymVal == dyn_rela->addend())) {
694 dyn_rela->setAddend(pReloc.symValue());
695 }
696
697 return Relocator::OK;
698 }
699
700 // R_AARCH64_LDST8_ABS_LO12_NC: S + A
701 // R_AARCH64_LDST16_ABS_LO12_NC: S + A
702 // R_AARCH64_LDST32_ABS_LO12_NC: S + A
703 // R_AARCH64_LDST64_ABS_LO12_NC: S + A
704 // R_AARCH64_LDST128_ABS_LO12_NC: S + A
ldst_abs_lo12(Relocation & pReloc,AArch64Relocator & pParent)705 Relocator::Result ldst_abs_lo12(Relocation& pReloc, AArch64Relocator& pParent) {
706 Relocator::Address S = pReloc.symValue();
707 Relocator::DWord A = pReloc.addend();
708 Relocator::DWord X = helper_get_page_offset(S + A);
709
710 switch (pReloc.type()) {
711 case llvm::ELF::R_AARCH64_LDST8_ABS_LO12_NC:
712 pReloc.target() = helper_reencode_ldst_pos_imm(pReloc.target(), X);
713 break;
714 case llvm::ELF::R_AARCH64_LDST16_ABS_LO12_NC:
715 pReloc.target() = helper_reencode_ldst_pos_imm(pReloc.target(), (X >> 1));
716 break;
717 case llvm::ELF::R_AARCH64_LDST32_ABS_LO12_NC:
718 pReloc.target() = helper_reencode_ldst_pos_imm(pReloc.target(), (X >> 2));
719 break;
720 case llvm::ELF::R_AARCH64_LDST64_ABS_LO12_NC:
721 pReloc.target() = helper_reencode_ldst_pos_imm(pReloc.target(), (X >> 3));
722 break;
723 case llvm::ELF::R_AARCH64_LDST128_ABS_LO12_NC:
724 pReloc.target() = helper_reencode_ldst_pos_imm(pReloc.target(), (X >> 4));
725 break;
726 default:
727 break;
728 }
729 return Relocator::OK;
730 }
731
732 } // namespace mcld
733