xref: /openbsd-src/gnu/llvm/lld/MachO/Arch/ARM64_32.cpp (revision dfe94b169149f14cc1aee2cf6dad58a8d9a1860c)
11cf9926bSpatrick //===- ARM64_32.cpp
21cf9926bSpatrick //----------------------------------------------------------===//
31cf9926bSpatrick //
41cf9926bSpatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
51cf9926bSpatrick // See https://llvm.org/LICENSE.txt for license information.
61cf9926bSpatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
71cf9926bSpatrick //
81cf9926bSpatrick //===----------------------------------------------------------------------===//
91cf9926bSpatrick 
101cf9926bSpatrick #include "Arch/ARM64Common.h"
111cf9926bSpatrick #include "InputFiles.h"
121cf9926bSpatrick #include "Symbols.h"
131cf9926bSpatrick #include "SyntheticSections.h"
141cf9926bSpatrick #include "Target.h"
151cf9926bSpatrick 
161cf9926bSpatrick #include "lld/Common/ErrorHandler.h"
171cf9926bSpatrick #include "llvm/ADT/SmallVector.h"
181cf9926bSpatrick #include "llvm/ADT/StringRef.h"
191cf9926bSpatrick #include "llvm/BinaryFormat/MachO.h"
201cf9926bSpatrick #include "llvm/Support/Endian.h"
211cf9926bSpatrick #include "llvm/Support/MathExtras.h"
221cf9926bSpatrick 
231cf9926bSpatrick using namespace llvm::MachO;
241cf9926bSpatrick using namespace llvm::support::endian;
251cf9926bSpatrick using namespace lld;
261cf9926bSpatrick using namespace lld::macho;
271cf9926bSpatrick 
281cf9926bSpatrick namespace {
291cf9926bSpatrick 
301cf9926bSpatrick struct ARM64_32 : ARM64Common {
311cf9926bSpatrick   ARM64_32();
32*dfe94b16Srobert   void writeStub(uint8_t *buf, const Symbol &, uint64_t) const override;
331cf9926bSpatrick   void writeStubHelperHeader(uint8_t *buf) const override;
34*dfe94b16Srobert   void writeStubHelperEntry(uint8_t *buf, const Symbol &,
351cf9926bSpatrick                             uint64_t entryAddr) const override;
36*dfe94b16Srobert   void writeObjCMsgSendStub(uint8_t *buf, Symbol *sym, uint64_t stubsAddr,
37*dfe94b16Srobert                             uint64_t stubOffset, uint64_t selrefsVA,
38*dfe94b16Srobert                             uint64_t selectorIndex, uint64_t gotAddr,
39*dfe94b16Srobert                             uint64_t msgSendIndex) const override;
401cf9926bSpatrick };
411cf9926bSpatrick 
421cf9926bSpatrick } // namespace
431cf9926bSpatrick 
441cf9926bSpatrick // These are very similar to ARM64's relocation attributes, except that we don't
451cf9926bSpatrick // have the BYTE8 flag set.
46*dfe94b16Srobert static constexpr std::array<RelocAttrs, 11> relocAttrsArray{{
471cf9926bSpatrick #define B(x) RelocAttrBits::x
481cf9926bSpatrick     {"UNSIGNED", B(UNSIGNED) | B(ABSOLUTE) | B(EXTERN) | B(LOCAL) | B(BYTE4)},
491cf9926bSpatrick     {"SUBTRACTOR", B(SUBTRAHEND) | B(EXTERN) | B(BYTE4)},
501cf9926bSpatrick     {"BRANCH26", B(PCREL) | B(EXTERN) | B(BRANCH) | B(BYTE4)},
511cf9926bSpatrick     {"PAGE21", B(PCREL) | B(EXTERN) | B(BYTE4)},
521cf9926bSpatrick     {"PAGEOFF12", B(ABSOLUTE) | B(EXTERN) | B(BYTE4)},
531cf9926bSpatrick     {"GOT_LOAD_PAGE21", B(PCREL) | B(EXTERN) | B(GOT) | B(BYTE4)},
541cf9926bSpatrick     {"GOT_LOAD_PAGEOFF12",
551cf9926bSpatrick      B(ABSOLUTE) | B(EXTERN) | B(GOT) | B(LOAD) | B(BYTE4)},
561cf9926bSpatrick     {"POINTER_TO_GOT", B(PCREL) | B(EXTERN) | B(GOT) | B(POINTER) | B(BYTE4)},
571cf9926bSpatrick     {"TLVP_LOAD_PAGE21", B(PCREL) | B(EXTERN) | B(TLV) | B(BYTE4)},
581cf9926bSpatrick     {"TLVP_LOAD_PAGEOFF12",
591cf9926bSpatrick      B(ABSOLUTE) | B(EXTERN) | B(TLV) | B(LOAD) | B(BYTE4)},
601cf9926bSpatrick     {"ADDEND", B(ADDEND)},
611cf9926bSpatrick #undef B
621cf9926bSpatrick }};
631cf9926bSpatrick 
641cf9926bSpatrick // The stub code is fairly similar to ARM64's, except that we load pointers into
651cf9926bSpatrick // 32-bit 'w' registers, instead of the 64-bit 'x' ones.
661cf9926bSpatrick 
671cf9926bSpatrick static constexpr uint32_t stubCode[] = {
681cf9926bSpatrick     0x90000010, // 00: adrp  x16, __la_symbol_ptr@page
691cf9926bSpatrick     0xb9400210, // 04: ldr   w16, [x16, __la_symbol_ptr@pageoff]
701cf9926bSpatrick     0xd61f0200, // 08: br    x16
711cf9926bSpatrick };
721cf9926bSpatrick 
writeStub(uint8_t * buf8,const Symbol & sym,uint64_t pointerVA) const73*dfe94b16Srobert void ARM64_32::writeStub(uint8_t *buf8, const Symbol &sym,
74*dfe94b16Srobert                          uint64_t pointerVA) const {
75*dfe94b16Srobert   ::writeStub(buf8, stubCode, sym, pointerVA);
761cf9926bSpatrick }
771cf9926bSpatrick 
781cf9926bSpatrick static constexpr uint32_t stubHelperHeaderCode[] = {
791cf9926bSpatrick     0x90000011, // 00: adrp  x17, _dyld_private@page
801cf9926bSpatrick     0x91000231, // 04: add   x17, x17, _dyld_private@pageoff
811cf9926bSpatrick     0xa9bf47f0, // 08: stp   x16/x17, [sp, #-16]!
821cf9926bSpatrick     0x90000010, // 0c: adrp  x16, dyld_stub_binder@page
831cf9926bSpatrick     0xb9400210, // 10: ldr   w16, [x16, dyld_stub_binder@pageoff]
841cf9926bSpatrick     0xd61f0200, // 14: br    x16
851cf9926bSpatrick };
861cf9926bSpatrick 
writeStubHelperHeader(uint8_t * buf8) const871cf9926bSpatrick void ARM64_32::writeStubHelperHeader(uint8_t *buf8) const {
881cf9926bSpatrick   ::writeStubHelperHeader<ILP32>(buf8, stubHelperHeaderCode);
891cf9926bSpatrick }
901cf9926bSpatrick 
911cf9926bSpatrick static constexpr uint32_t stubHelperEntryCode[] = {
921cf9926bSpatrick     0x18000050, // 00: ldr  w16, l0
931cf9926bSpatrick     0x14000000, // 04: b    stubHelperHeader
941cf9926bSpatrick     0x00000000, // 08: l0: .long 0
951cf9926bSpatrick };
961cf9926bSpatrick 
writeStubHelperEntry(uint8_t * buf8,const Symbol & sym,uint64_t entryVA) const97*dfe94b16Srobert void ARM64_32::writeStubHelperEntry(uint8_t *buf8, const Symbol &sym,
981cf9926bSpatrick                                     uint64_t entryVA) const {
991cf9926bSpatrick   ::writeStubHelperEntry(buf8, stubHelperEntryCode, sym, entryVA);
1001cf9926bSpatrick }
1011cf9926bSpatrick 
writeObjCMsgSendStub(uint8_t * buf,Symbol * sym,uint64_t stubsAddr,uint64_t stubOffset,uint64_t selrefsVA,uint64_t selectorIndex,uint64_t gotAddr,uint64_t msgSendIndex) const102*dfe94b16Srobert void ARM64_32::writeObjCMsgSendStub(uint8_t *buf, Symbol *sym,
103*dfe94b16Srobert                                     uint64_t stubsAddr, uint64_t stubOffset,
104*dfe94b16Srobert                                     uint64_t selrefsVA, uint64_t selectorIndex,
105*dfe94b16Srobert                                     uint64_t gotAddr,
106*dfe94b16Srobert                                     uint64_t msgSendIndex) const {
107*dfe94b16Srobert   fatal("TODO: implement this");
108*dfe94b16Srobert }
109*dfe94b16Srobert 
ARM64_32()1101cf9926bSpatrick ARM64_32::ARM64_32() : ARM64Common(ILP32()) {
1111cf9926bSpatrick   cpuType = CPU_TYPE_ARM64_32;
1121cf9926bSpatrick   cpuSubtype = CPU_SUBTYPE_ARM64_V8;
1131cf9926bSpatrick 
114*dfe94b16Srobert   modeDwarfEncoding = 0x04000000;              // UNWIND_ARM_MODE_DWARF
115*dfe94b16Srobert   subtractorRelocType = GENERIC_RELOC_INVALID; // FIXME
116*dfe94b16Srobert   unsignedRelocType = GENERIC_RELOC_INVALID;   // FIXME
117*dfe94b16Srobert 
1181cf9926bSpatrick   stubSize = sizeof(stubCode);
1191cf9926bSpatrick   stubHelperHeaderSize = sizeof(stubHelperHeaderCode);
1201cf9926bSpatrick   stubHelperEntrySize = sizeof(stubHelperEntryCode);
121*dfe94b16Srobert 
122*dfe94b16Srobert   relocAttrs = {relocAttrsArray.data(), relocAttrsArray.size()};
1231cf9926bSpatrick }
1241cf9926bSpatrick 
createARM64_32TargetInfo()1251cf9926bSpatrick TargetInfo *macho::createARM64_32TargetInfo() {
1261cf9926bSpatrick   static ARM64_32 t;
1271cf9926bSpatrick   return &t;
1281cf9926bSpatrick }
129