llvm.org GIT mirror llvm / 3523e86
RuntimeDyldELF/AArch64: Implement basic GOT support This patch implements two GOT relocations: R_AARCH64_ADR_GOT_PAGE and R_AARCH64_LD64_GOT_LO12_NC Differential revision: https://reviews.llvm.org/D28571 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@294191 91177308-0d34-0410-b5e6-96231b3b80d8 Eugene Leviant 3 years ago
5 changed file(s) with 222 addition(s) and 73 deletion(s). Raw diff Collapse all Expand all
483483 }
484484 }
485485
486 // Compute Global Offset Table size. If it is not zero we
487 // also update alignment, which is equal to a size of a
488 // single GOT entry.
489 if (unsigned GotSize = computeGOTSize(Obj)) {
490 RWSectionSizes.push_back(GotSize);
491 RWDataAlign = std::max(RWDataAlign, getGOTEntrySize());
492 }
493
486494 // Compute the size of all common symbols
487495 uint64_t CommonSize = 0;
488496 uint32_t CommonAlign = 1;
515523 RWDataSize = computeAllocationSizeForSections(RWSectionSizes, RWDataAlign);
516524
517525 return Error::success();
526 }
527
528 // compute GOT size
529 unsigned RuntimeDyldImpl::computeGOTSize(const ObjectFile &Obj) {
530 size_t GotEntrySize = getGOTEntrySize();
531 if (!GotEntrySize)
532 return 0;
533
534 size_t GotSize = 0;
535 for (section_iterator SI = Obj.section_begin(), SE = Obj.section_end();
536 SI != SE; ++SI) {
537
538 for (const RelocationRef &Reloc : SI->relocations())
539 if (relocationNeedsGot(Reloc))
540 GotSize += GotEntrySize;
541 }
542
543 return GotSize;
518544 }
519545
520546 // compute stub buffer size for the given section
960960 return true;
961961 }
962962
963 void RuntimeDyldELF::resolveAArch64Branch(unsigned SectionID,
964 const RelocationValueRef &Value,
965 relocation_iterator RelI,
966 StubMap &Stubs) {
967
968 DEBUG(dbgs() << "\t\tThis is an AArch64 branch relocation.");
969 SectionEntry &Section = Sections[SectionID];
970
971 uint64_t Offset = RelI->getOffset();
972 unsigned RelType = RelI->getType();
973 // Look for an existing stub.
974 StubMap::const_iterator i = Stubs.find(Value);
975 if (i != Stubs.end()) {
976 resolveRelocation(Section, Offset,
977 (uint64_t)Section.getAddressWithOffset(i->second),
978 RelType, 0);
979 DEBUG(dbgs() << " Stub function found\n");
980 } else if (!resolveAArch64ShortBranch(SectionID, RelI, Value)) {
981 // Create a new stub function.
982 DEBUG(dbgs() << " Create a new stub function\n");
983 Stubs[Value] = Section.getStubOffset();
984 uint8_t *StubTargetAddr = createStubFunction(
985 Section.getAddressWithOffset(Section.getStubOffset()));
986
987 RelocationEntry REmovz_g3(SectionID, StubTargetAddr - Section.getAddress(),
988 ELF::R_AARCH64_MOVW_UABS_G3, Value.Addend);
989 RelocationEntry REmovk_g2(SectionID,
990 StubTargetAddr - Section.getAddress() + 4,
991 ELF::R_AARCH64_MOVW_UABS_G2_NC, Value.Addend);
992 RelocationEntry REmovk_g1(SectionID,
993 StubTargetAddr - Section.getAddress() + 8,
994 ELF::R_AARCH64_MOVW_UABS_G1_NC, Value.Addend);
995 RelocationEntry REmovk_g0(SectionID,
996 StubTargetAddr - Section.getAddress() + 12,
997 ELF::R_AARCH64_MOVW_UABS_G0_NC, Value.Addend);
998
999 if (Value.SymbolName) {
1000 addRelocationForSymbol(REmovz_g3, Value.SymbolName);
1001 addRelocationForSymbol(REmovk_g2, Value.SymbolName);
1002 addRelocationForSymbol(REmovk_g1, Value.SymbolName);
1003 addRelocationForSymbol(REmovk_g0, Value.SymbolName);
1004 } else {
1005 addRelocationForSection(REmovz_g3, Value.SectionID);
1006 addRelocationForSection(REmovk_g2, Value.SectionID);
1007 addRelocationForSection(REmovk_g1, Value.SectionID);
1008 addRelocationForSection(REmovk_g0, Value.SectionID);
1009 }
1010 resolveRelocation(Section, Offset,
1011 reinterpret_cast(Section.getAddressWithOffset(
1012 Section.getStubOffset())),
1013 RelType, 0);
1014 Section.advanceStubOffset(getMaxStubSize());
1015 }
1016 }
1017
9631018 Expected
9641019 RuntimeDyldELF::processRelocationRef(
9651020 unsigned SectionID, relocation_iterator RelI, const ObjectFile &O,
10541109
10551110 DEBUG(dbgs() << "\t\tSectionID: " << SectionID << " Offset: " << Offset
10561111 << "\n");
1057 if ((Arch == Triple::aarch64 || Arch == Triple::aarch64_be) &&
1058 (RelType == ELF::R_AARCH64_CALL26 || RelType == ELF::R_AARCH64_JUMP26)) {
1059 // This is an AArch64 branch relocation, need to use a stub function.
1060 DEBUG(dbgs() << "\t\tThis is an AArch64 branch relocation.");
1061 SectionEntry &Section = Sections[SectionID];
1062
1063 // Look for an existing stub.
1064 StubMap::const_iterator i = Stubs.find(Value);
1065 if (i != Stubs.end()) {
1066 resolveRelocation(Section, Offset,
1067 (uint64_t)Section.getAddressWithOffset(i->second),
1068 RelType, 0);
1069 DEBUG(dbgs() << " Stub function found\n");
1070 } else if (!resolveAArch64ShortBranch(SectionID, RelI, Value)) {
1071 // Create a new stub function.
1072 DEBUG(dbgs() << " Create a new stub function\n");
1073 Stubs[Value] = Section.getStubOffset();
1074 uint8_t *StubTargetAddr = createStubFunction(
1075 Section.getAddressWithOffset(Section.getStubOffset()));
1076
1077 RelocationEntry REmovz_g3(SectionID,
1078 StubTargetAddr - Section.getAddress(),
1079 ELF::R_AARCH64_MOVW_UABS_G3, Value.Addend);
1080 RelocationEntry REmovk_g2(SectionID, StubTargetAddr -
1081 Section.getAddress() + 4,
1082 ELF::R_AARCH64_MOVW_UABS_G2_NC, Value.Addend);
1083 RelocationEntry REmovk_g1(SectionID, StubTargetAddr -
1084 Section.getAddress() + 8,
1085 ELF::R_AARCH64_MOVW_UABS_G1_NC, Value.Addend);
1086 RelocationEntry REmovk_g0(SectionID, StubTargetAddr -
1087 Section.getAddress() + 12,
1088 ELF::R_AARCH64_MOVW_UABS_G0_NC, Value.Addend);
1089
1090 if (Value.SymbolName) {
1091 addRelocationForSymbol(REmovz_g3, Value.SymbolName);
1092 addRelocationForSymbol(REmovk_g2, Value.SymbolName);
1093 addRelocationForSymbol(REmovk_g1, Value.SymbolName);
1094 addRelocationForSymbol(REmovk_g0, Value.SymbolName);
1095 } else {
1096 addRelocationForSection(REmovz_g3, Value.SectionID);
1097 addRelocationForSection(REmovk_g2, Value.SectionID);
1098 addRelocationForSection(REmovk_g1, Value.SectionID);
1099 addRelocationForSection(REmovk_g0, Value.SectionID);
1100 }
1101 resolveRelocation(Section, Offset,
1102 reinterpret_cast(Section.getAddressWithOffset(
1103 Section.getStubOffset())),
1104 RelType, 0);
1105 Section.advanceStubOffset(getMaxStubSize());
1112 if ((Arch == Triple::aarch64 || Arch == Triple::aarch64_be)) {
1113 if (RelType == ELF::R_AARCH64_CALL26 || RelType == ELF::R_AARCH64_JUMP26) {
1114 resolveAArch64Branch(SectionID, Value, RelI, Stubs);
1115 } else if (RelType == ELF::R_AARCH64_ADR_GOT_PAGE) {
1116 // Craete new GOT entry or find existing one. If GOT entry is
1117 // to be created, then we also emit ABS64 relocation for it.
1118 uint64_t GOTOffset = findOrAllocGOTEntry(Value, ELF::R_AARCH64_ABS64);
1119 resolveGOTOffsetRelocation(SectionID, Offset, GOTOffset + Addend,
1120 ELF::R_AARCH64_ADR_PREL_PG_HI21);
1121
1122 } else if (RelType == ELF::R_AARCH64_LD64_GOT_LO12_NC) {
1123 uint64_t GOTOffset = findOrAllocGOTEntry(Value, ELF::R_AARCH64_ABS64);
1124 resolveGOTOffsetRelocation(SectionID, Offset, GOTOffset + Addend,
1125 ELF::R_AARCH64_LDST64_ABS_LO12_NC);
1126 } else {
1127 processSimpleRelocation(SectionID, Offset, RelType, Value);
11061128 }
11071129 } else if (Arch == Triple::arm) {
11081130 if (RelType == ELF::R_ARM_PC24 || RelType == ELF::R_ARM_CALL ||
12511273 if (i != GOTSymbolOffsets.end())
12521274 RE.SymOffset = i->second;
12531275 else {
1254 RE.SymOffset = allocateGOTEntries(SectionID, 1);
1276 RE.SymOffset = allocateGOTEntries(1);
12551277 GOTSymbolOffsets[TargetName] = RE.SymOffset;
12561278 }
12571279 }
15081530 Section.advanceStubOffset(getMaxStubSize());
15091531
15101532 // Allocate a GOT Entry
1511 uint64_t GOTOffset = allocateGOTEntries(SectionID, 1);
1533 uint64_t GOTOffset = allocateGOTEntries(1);
15121534
15131535 // The load of the GOT address has an addend of -4
1514 resolveGOTOffsetRelocation(SectionID, StubOffset + 2, GOTOffset - 4);
1536 resolveGOTOffsetRelocation(SectionID, StubOffset + 2, GOTOffset - 4,
1537 ELF::R_X86_64_PC32);
15151538
15161539 // Fill in the value of the symbol we're targeting into the GOT
15171540 addRelocationForSymbol(
1518 computeGOTOffsetRE(SectionID, GOTOffset, 0, ELF::R_X86_64_64),
1541 computeGOTOffsetRE(GOTOffset, 0, ELF::R_X86_64_64),
15191542 Value.SymbolName);
15201543 }
15211544
15301553 } else if (RelType == ELF::R_X86_64_GOTPCREL ||
15311554 RelType == ELF::R_X86_64_GOTPCRELX ||
15321555 RelType == ELF::R_X86_64_REX_GOTPCRELX) {
1533 uint64_t GOTOffset = allocateGOTEntries(SectionID, 1);
1534 resolveGOTOffsetRelocation(SectionID, Offset, GOTOffset + Addend);
1556 uint64_t GOTOffset = allocateGOTEntries(1);
1557 resolveGOTOffsetRelocation(SectionID, Offset, GOTOffset + Addend,
1558 ELF::R_X86_64_PC32);
15351559
15361560 // Fill in the value of the symbol we're targeting into the GOT
1537 RelocationEntry RE = computeGOTOffsetRE(SectionID, GOTOffset, Value.Offset, ELF::R_X86_64_64);
1561 RelocationEntry RE =
1562 computeGOTOffsetRE(GOTOffset, Value.Offset, ELF::R_X86_64_64);
15381563 if (Value.SymbolName)
15391564 addRelocationForSymbol(RE, Value.SymbolName);
15401565 else
15921617 return Result;
15931618 }
15941619
1595 uint64_t RuntimeDyldELF::allocateGOTEntries(unsigned SectionID, unsigned no)
1596 {
1597 (void)SectionID; // The GOT Section is the same for all section in the object file
1620 uint64_t RuntimeDyldELF::allocateGOTEntries(unsigned no) {
15981621 if (GOTSectionID == 0) {
15991622 GOTSectionID = Sections.size();
16001623 // Reserve a section id. We'll allocate the section later
16061629 return StartOffset;
16071630 }
16081631
1609 void RuntimeDyldELF::resolveGOTOffsetRelocation(unsigned SectionID, uint64_t Offset, uint64_t GOTOffset)
1610 {
1632 uint64_t RuntimeDyldELF::findOrAllocGOTEntry(const RelocationValueRef &Value,
1633 unsigned GOTRelType) {
1634 auto E = GOTOffsetMap.insert({Value, 0});
1635 if (E.second) {
1636 uint64_t GOTOffset = allocateGOTEntries(1);
1637
1638 // Create relocation for newly created GOT entry
1639 RelocationEntry RE =
1640 computeGOTOffsetRE(GOTOffset, Value.Offset, GOTRelType);
1641 if (Value.SymbolName)
1642 addRelocationForSymbol(RE, Value.SymbolName);
1643 else
1644 addRelocationForSection(RE, Value.SectionID);
1645
1646 E.first->second = GOTOffset;
1647 }
1648
1649 return E.first->second;
1650 }
1651
1652 void RuntimeDyldELF::resolveGOTOffsetRelocation(unsigned SectionID,
1653 uint64_t Offset,
1654 uint64_t GOTOffset,
1655 uint32_t Type) {
16111656 // Fill in the relative address of the GOT Entry into the stub
1612 RelocationEntry GOTRE(SectionID, Offset, ELF::R_X86_64_PC32, GOTOffset);
1657 RelocationEntry GOTRE(SectionID, Offset, Type, GOTOffset);
16131658 addRelocationForSection(GOTRE, GOTSectionID);
16141659 }
16151660
1616 RelocationEntry RuntimeDyldELF::computeGOTOffsetRE(unsigned SectionID, uint64_t GOTOffset, uint64_t SymbolOffset,
1617 uint32_t Type)
1618 {
1619 (void)SectionID; // The GOT Section is the same for all section in the object file
1661 RelocationEntry RuntimeDyldELF::computeGOTOffsetRE(uint64_t GOTOffset,
1662 uint64_t SymbolOffset,
1663 uint32_t Type) {
16201664 return RelocationEntry(GOTSectionID, GOTOffset, Type, SymbolOffset);
16211665 }
16221666
16821726 return Obj.isELF();
16831727 }
16841728
1729 bool RuntimeDyldELF::relocationNeedsGot(const RelocationRef &R) const {
1730 unsigned RelTy = R.getType();
1731 if (Arch == Triple::aarch64 || Arch == Triple::aarch64_be)
1732 return RelTy == ELF::R_AARCH64_ADR_GOT_PAGE ||
1733 RelTy == ELF::R_AARCH64_LD64_GOT_LO12_NC;
1734
1735 if (Arch == Triple::x86_64)
1736 return RelTy == ELF::R_X86_64_GOTPCREL ||
1737 RelTy == ELF::R_X86_64_GOTPCRELX ||
1738 RelTy == ELF::R_X86_64_REX_GOTPCRELX;
1739 return false;
1740 }
1741
16851742 bool RuntimeDyldELF::relocationNeedsStub(const RelocationRef &R) const {
16861743 if (Arch != Triple::x86_64)
16871744 return true; // Conservative answer
4141
4242 bool resolveAArch64ShortBranch(unsigned SectionID, relocation_iterator RelI,
4343 const RelocationValueRef &Value);
44
45 void resolveAArch64Branch(unsigned SectionID, const RelocationValueRef &Value,
46 relocation_iterator RelI, StubMap &Stubs);
4447
4548 void resolveARMRelocation(const SectionEntry &Section, uint64_t Offset,
4649 uint32_t Value, uint32_t Type, int32_t Addend);
8790 ObjSectionToIDMap &LocalSections,
8891 RelocationValueRef &Rel);
8992 protected:
90 size_t getGOTEntrySize();
93 size_t getGOTEntrySize() override;
9194
9295 private:
9396 SectionEntry &getSection(unsigned SectionID) { return Sections[SectionID]; }
9497
9598 // Allocate no GOT entries for use in the given section.
96 uint64_t allocateGOTEntries(unsigned SectionID, unsigned no);
99 uint64_t allocateGOTEntries(unsigned no);
100
101 // Find GOT entry corresponding to relocation or create new one.
102 uint64_t findOrAllocGOTEntry(const RelocationValueRef &Value,
103 unsigned GOTRelType);
97104
98105 // Resolve the relvative address of GOTOffset in Section ID and place
99106 // it at the given Offset
100107 void resolveGOTOffsetRelocation(unsigned SectionID, uint64_t Offset,
101 uint64_t GOTOffset);
108 uint64_t GOTOffset, uint32_t Type);
102109
103110 // For a GOT entry referenced from SectionID, compute a relocation entry
104111 // that will place the final resolved value in the GOT slot
105 RelocationEntry computeGOTOffsetRE(unsigned SectionID,
106 uint64_t GOTOffset,
107 uint64_t SymbolOffset,
112 RelocationEntry computeGOTOffsetRE(uint64_t GOTOffset, uint64_t SymbolOffset,
108113 unsigned Type);
109114
110115 // Compute the address in memory where we can find the placeholder
145150 SmallVector UnregisteredEHFrameSections;
146151 SmallVector RegisteredEHFrameSections;
147152
153 // Map between GOT relocation value and corresponding GOT offset
154 std::map GOTOffsetMap;
155
156 bool relocationNeedsGot(const RelocationRef &R) const override;
148157 bool relocationNeedsStub(const RelocationRef &R) const override;
149158
150159 public:
212212 }
213213 };
214214
215 /// @brief Symbol info for RuntimeDyld.
215 /// @brief Symbol info for RuntimeDyld.
216216 class SymbolTableEntry {
217217 public:
218218 SymbolTableEntry()
425425 uint64_t &RODataSize, uint32_t &RODataAlign,
426426 uint64_t &RWDataSize, uint32_t &RWDataAlign);
427427
428 // \brief Compute GOT size
429 unsigned computeGOTSize(const ObjectFile &Obj);
430
428431 // \brief Compute the stub buffer size required for a section
429432 unsigned computeSectionStubBufSize(const ObjectFile &Obj,
430433 const SectionRef &Section);
431434
432435 // \brief Implementation of the generic part of the loadObject algorithm.
433436 Expected loadObjectImpl(const object::ObjectFile &Obj);
437
438 // \brief Return size of Global Offset Table (GOT) entry
439 virtual size_t getGOTEntrySize() { return 0; }
440
441 // \brief Return true if the relocation R may require allocating a GOT entry.
442 virtual bool relocationNeedsGot(const RelocationRef &R) const {
443 return false;
444 }
434445
435446 // \brief Return true if the relocation R may require allocating a stub.
436447 virtual bool relocationNeedsStub(const RelocationRef &R) const {
0 # RUN: llvm-mc -triple=arm64-none-linux-gnu -filetype=obj -o %T/pic-reloc.o %s
1 # RUN: llvm-rtdyld -triple=arm64-none-linux-gnu -verify -check=%s %T/pic-reloc.o \
2 # RUN: -map-section pic-reloc.o,.got=0x20000 -dummy-extern f=0x1234 -dummy-extern g=0x5678
3
4 _s:
5 nop
6 _a1:
7 adrp x8, :got:f
8 _a2:
9 adrp x9, :got:g
10 _a3:
11 adrp x10, :got:_s
12 _l1:
13 ldr x8, [x8, :got_lo12:f]
14 _l2:
15 ldr x9, [x9, :got_lo12:g]
16 _l3:
17 ldr x10, [x10, :got_lo12:_s]
18
19
20 ## We'll end up having two sections .text and .got,
21 ## each is located on the start of a memory page
22
23 ## Test that .got section has three entries pointing to f, g and _s
24 # *{8}section_addr(pic-reloc.o, .got) = f
25 # *{8}(section_addr(pic-reloc.o, .got) + 8) = g
26 # *{8}(section_addr(pic-reloc.o, .got) + 16) = _s
27
28 ## Test that first adrp instruction really takes address of
29 ## the .got section (_s label is on the start of a page)
30 # rtdyld-check: _s + (((*{4}_a1)[30:29] + ((*{4}_a1)[23:5] << 2)) << 12) = section_addr(pic-reloc.o, .got)
31
32 ## Test that second adrp takes address of .got
33 # rtdyld-check: _s + (((*{4}_a2)[30:29] + ((*{4}_a2)[23:5] << 2)) << 12) = section_addr(pic-reloc.o, .got)
34
35 ## Test that third adrp takes address of .got
36 # rtdyld-check: _s + (((*{4}_a3)[30:29] + ((*{4}_a3)[23:5] << 2)) << 12) = section_addr(pic-reloc.o, .got)
37
38 ## Test that first ldr immediate value is 0 >> 3 = 0 (1st .got entry)
39 # rtdyld-check: (*{4}_l1)[21:10] = 0
40
41 ## Test that second ldr immediate value is 8 >> 3 = 1 (2nd .got entry)
42 # rtdyld-check: (*{4}_l2)[21:10] = 1
43
44 ## Test that third ldr immediate value is 16 >> 3 = 2 (3rd .got entry, addend is 0)
45 # rtdyld-check: (*{4}_l3)[21:10] = 2