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