brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.8 KiB · 04da702 Raw
237 lines · cpp
1//===- ARM64.cpp ----------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "Arch/ARM64Common.h"10#include "InputFiles.h"11#include "Symbols.h"12#include "SyntheticSections.h"13#include "Target.h"14 15#include "lld/Common/ErrorHandler.h"16#include "mach-o/compact_unwind_encoding.h"17#include "llvm/BinaryFormat/MachO.h"18 19using namespace llvm;20using namespace llvm::MachO;21using namespace lld;22using namespace lld::macho;23 24namespace {25 26struct ARM64 : ARM64Common {27  ARM64();28  void writeStub(uint8_t *buf, const Symbol &, uint64_t) const override;29  void writeStubHelperHeader(uint8_t *buf) const override;30  void writeStubHelperEntry(uint8_t *buf, const Symbol &,31                            uint64_t entryAddr) const override;32 33  void writeObjCMsgSendStub(uint8_t *buf, Symbol *sym, uint64_t stubsAddr,34                            uint64_t &stubOffset, uint64_t selrefVA,35                            Symbol *objcMsgSend) const override;36  void populateThunk(InputSection *thunk, Symbol *funcSym) override;37 38  void initICFSafeThunkBody(InputSection *thunk,39                            Symbol *targetSym) const override;40  Symbol *getThunkBranchTarget(InputSection *thunk) const override;41  uint32_t getICFSafeThunkSize() const override;42};43 44} // namespace45 46// Random notes on reloc types:47// ADDEND always pairs with BRANCH26, PAGE21, or PAGEOFF1248// POINTER_TO_GOT: ld64 supports a 4-byte pc-relative form as well as an 8-byte49// absolute version of this relocation. The semantics of the absolute relocation50// are weird -- it results in the value of the GOT slot being written, instead51// of the address. Let's not support it unless we find a real-world use case.52static constexpr std::array<RelocAttrs, 11> relocAttrsArray{{53#define B(x) RelocAttrBits::x54    {"UNSIGNED",55     B(UNSIGNED) | B(ABSOLUTE) | B(EXTERN) | B(LOCAL) | B(BYTE4) | B(BYTE8)},56    {"SUBTRACTOR", B(SUBTRAHEND) | B(EXTERN) | B(BYTE4) | B(BYTE8)},57    {"BRANCH26", B(PCREL) | B(EXTERN) | B(BRANCH) | B(BYTE4)},58    {"PAGE21", B(PCREL) | B(EXTERN) | B(BYTE4)},59    {"PAGEOFF12", B(ABSOLUTE) | B(EXTERN) | B(BYTE4)},60    {"GOT_LOAD_PAGE21", B(PCREL) | B(EXTERN) | B(GOT) | B(BYTE4)},61    {"GOT_LOAD_PAGEOFF12",62     B(ABSOLUTE) | B(EXTERN) | B(GOT) | B(LOAD) | B(BYTE4)},63    {"POINTER_TO_GOT", B(PCREL) | B(EXTERN) | B(GOT) | B(POINTER) | B(BYTE4)},64    {"TLVP_LOAD_PAGE21", B(PCREL) | B(EXTERN) | B(TLV) | B(BYTE4)},65    {"TLVP_LOAD_PAGEOFF12",66     B(ABSOLUTE) | B(EXTERN) | B(TLV) | B(LOAD) | B(BYTE4)},67    {"ADDEND", B(ADDEND)},68#undef B69}};70 71static constexpr uint32_t stubCode[] = {72    0x90000010, // 00: adrp  x16, __la_symbol_ptr@page73    0xf9400210, // 04: ldr   x16, [x16, __la_symbol_ptr@pageoff]74    0xd61f0200, // 08: br    x1675};76 77void ARM64::writeStub(uint8_t *buf8, const Symbol &sym,78                      uint64_t pointerVA) const {79  ::writeStub(buf8, stubCode, sym, pointerVA);80}81 82static constexpr uint32_t stubHelperHeaderCode[] = {83    0x90000011, // 00: adrp  x17, _dyld_private@page84    0x91000231, // 04: add   x17, x17, _dyld_private@pageoff85    0xa9bf47f0, // 08: stp   x16/x17, [sp, #-16]!86    0x90000010, // 0c: adrp  x16, dyld_stub_binder@page87    0xf9400210, // 10: ldr   x16, [x16, dyld_stub_binder@pageoff]88    0xd61f0200, // 14: br    x1689};90 91void ARM64::writeStubHelperHeader(uint8_t *buf8) const {92  ::writeStubHelperHeader<LP64>(buf8, stubHelperHeaderCode);93}94 95static constexpr uint32_t stubHelperEntryCode[] = {96    0x18000050, // 00: ldr  w16, l097    0x14000000, // 04: b    stubHelperHeader98    0x00000000, // 08: l0: .long 099};100 101void ARM64::writeStubHelperEntry(uint8_t *buf8, const Symbol &sym,102                                 uint64_t entryVA) const {103  ::writeStubHelperEntry(buf8, stubHelperEntryCode, sym, entryVA);104}105 106static constexpr uint32_t objcStubsFastCode[] = {107    0x90000001, // adrp  x1, __objc_selrefs@page108    0xf9400021, // ldr   x1, [x1, @selector("foo")@pageoff]109    0x90000010, // adrp  x16, _got@page110    0xf9400210, // ldr   x16, [x16, _objc_msgSend@pageoff]111    0xd61f0200, // br    x16112    0xd4200020, // brk   #0x1113    0xd4200020, // brk   #0x1114    0xd4200020, // brk   #0x1115};116 117static constexpr uint32_t objcStubsSmallCode[] = {118    0x90000001, // adrp  x1, __objc_selrefs@page119    0xf9400021, // ldr   x1, [x1, @selector("foo")@pageoff]120    0x14000000, // b     _objc_msgSend121};122 123void ARM64::writeObjCMsgSendStub(uint8_t *buf, Symbol *sym, uint64_t stubsAddr,124                                 uint64_t &stubOffset, uint64_t selrefVA,125                                 Symbol *objcMsgSend) const {126  uint64_t objcMsgSendAddr;127  uint64_t objcStubSize;128  uint64_t objcMsgSendIndex;129 130  if (config->objcStubsMode == ObjCStubsMode::fast) {131    objcStubSize = target->objcStubsFastSize;132    objcMsgSendAddr = in.got->addr;133    objcMsgSendIndex = objcMsgSend->gotIndex;134    ::writeObjCMsgSendFastStub<LP64>(buf, objcStubsFastCode, sym, stubsAddr,135                                     stubOffset, selrefVA, objcMsgSendAddr,136                                     objcMsgSendIndex);137  } else {138    assert(config->objcStubsMode == ObjCStubsMode::small);139    objcStubSize = target->objcStubsSmallSize;140    if (auto *d = dyn_cast<Defined>(objcMsgSend)) {141      objcMsgSendAddr = d->getVA();142      objcMsgSendIndex = 0;143    } else {144      objcMsgSendAddr = in.stubs->addr;145      objcMsgSendIndex = objcMsgSend->stubsIndex;146    }147    ::writeObjCMsgSendSmallStub<LP64>(buf, objcStubsSmallCode, sym, stubsAddr,148                                      stubOffset, selrefVA, objcMsgSendAddr,149                                      objcMsgSendIndex);150  }151  stubOffset += objcStubSize;152}153 154// A thunk is the relaxed variation of stubCode. We don't need the155// extra indirection through a lazy pointer because the target address156// is known at link time.157static constexpr uint32_t thunkCode[] = {158    0x90000010, // 00: adrp  x16, <thunk.ptr>@page159    0x91000210, // 04: add   x16, [x16,<thunk.ptr>@pageoff]160    0xd61f0200, // 08: br    x16161};162 163void ARM64::populateThunk(InputSection *thunk, Symbol *funcSym) {164  thunk->align = 4;165  thunk->data = {reinterpret_cast<const uint8_t *>(thunkCode),166                 sizeof(thunkCode)};167  thunk->relocs.emplace_back(/*type=*/ARM64_RELOC_PAGEOFF12,168                             /*pcrel=*/false, /*length=*/2,169                             /*offset=*/4, /*addend=*/0,170                             /*referent=*/funcSym);171  thunk->relocs.emplace_back(/*type=*/ARM64_RELOC_PAGE21,172                             /*pcrel=*/true, /*length=*/2,173                             /*offset=*/0, /*addend=*/0,174                             /*referent=*/funcSym);175}176// Just a single direct branch to the target function.177static constexpr uint32_t icfSafeThunkCode[] = {178    0x14000000, // 08: b    target179};180 181void ARM64::initICFSafeThunkBody(InputSection *thunk, Symbol *targetSym) const {182  // The base data here will not be itself modified, we'll just be adding a183  // reloc below. So we can directly use the constexpr above as the data.184  thunk->data = {reinterpret_cast<const uint8_t *>(icfSafeThunkCode),185                 sizeof(icfSafeThunkCode)};186 187  thunk->relocs.emplace_back(/*type=*/ARM64_RELOC_BRANCH26,188                             /*pcrel=*/true, /*length=*/2,189                             /*offset=*/0, /*addend=*/0,190                             /*referent=*/targetSym);191}192 193Symbol *ARM64::getThunkBranchTarget(InputSection *thunk) const {194  assert(thunk->relocs.size() == 1 &&195         "expected a single reloc on ARM64 ICF thunk");196  auto &reloc = thunk->relocs[0];197  assert(isa<Symbol *>(reloc.referent) &&198         "ARM64 thunk reloc is expected to point to a Symbol");199 200  return cast<Symbol *>(reloc.referent);201}202 203uint32_t ARM64::getICFSafeThunkSize() const { return sizeof(icfSafeThunkCode); }204 205ARM64::ARM64() : ARM64Common(LP64()) {206  cpuType = CPU_TYPE_ARM64;207  cpuSubtype = CPU_SUBTYPE_ARM64_ALL;208 209  stubSize = sizeof(stubCode);210  thunkSize = sizeof(thunkCode);211 212  objcStubsFastSize = sizeof(objcStubsFastCode);213  objcStubsFastAlignment = 32;214  objcStubsSmallSize = sizeof(objcStubsSmallCode);215  objcStubsSmallAlignment = 4;216 217  // Branch immediate is two's complement 26 bits, which is implicitly218  // multiplied by 4 (since all functions are 4-aligned: The branch range219  // is -4*(2**(26-1))..4*(2**(26-1) - 1).220  backwardBranchRange = 128 * 1024 * 1024;221  forwardBranchRange = backwardBranchRange - 4;222 223  modeDwarfEncoding = UNWIND_ARM64_MODE_DWARF;224  subtractorRelocType = ARM64_RELOC_SUBTRACTOR;225  unsignedRelocType = ARM64_RELOC_UNSIGNED;226 227  stubHelperHeaderSize = sizeof(stubHelperHeaderCode);228  stubHelperEntrySize = sizeof(stubHelperEntryCode);229 230  relocAttrs = {relocAttrsArray.data(), relocAttrsArray.size()};231}232 233TargetInfo *macho::createARM64TargetInfo() {234  static ARM64 t;235  return &t;236}237