| 1 | //===-- AArch64TargetObjectFile.cpp - AArch64 Object Info -----------------===// |
| 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-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | |
| 9 | #include "AArch64TargetObjectFile.h" |
| 10 | #include "AArch64TargetMachine.h" |
| 11 | #include "MCTargetDesc/AArch64MCAsmInfo.h" |
| 12 | #include "MCTargetDesc/AArch64TargetStreamer.h" |
| 13 | #include "llvm/BinaryFormat/Dwarf.h" |
| 14 | #include "llvm/CodeGen/MachineModuleInfoImpls.h" |
| 15 | #include "llvm/IR/Mangler.h" |
| 16 | #include "llvm/IR/Module.h" |
| 17 | #include "llvm/MC/MCContext.h" |
| 18 | #include "llvm/MC/MCExpr.h" |
| 19 | #include "llvm/MC/MCSectionELF.h" |
| 20 | #include "llvm/MC/MCStreamer.h" |
| 21 | #include "llvm/MC/MCValue.h" |
| 22 | using namespace llvm; |
| 23 | using namespace dwarf; |
| 24 | |
| 25 | void AArch64_ELFTargetObjectFile::Initialize(MCContext &Ctx, |
| 26 | const TargetMachine &TM) { |
| 27 | TargetLoweringObjectFileELF::Initialize(Ctx, TM); |
| 28 | PLTRelativeSpecifier = AArch64::S_PLT; |
| 29 | SupportIndirectSymViaGOTPCRel = true; |
| 30 | |
| 31 | // AARCH64 ELF ABI does not define static relocation type for TLS offset |
| 32 | // within a module. Do not generate AT_location for TLS variables. |
| 33 | SupportDebugThreadLocalLocation = false; |
| 34 | |
| 35 | // Make sure the implicitly created empty .text section has the |
| 36 | // SHF_AARCH64_PURECODE flag set if the "+execute-only" target feature is |
| 37 | // present. |
| 38 | if (TM.getMCSubtargetInfo()->hasFeature(Feature: AArch64::FeatureExecuteOnly)) { |
| 39 | auto *Text = cast<MCSectionELF>(Val: TextSection); |
| 40 | Text->setFlags(Text->getFlags() | ELF::SHF_AARCH64_PURECODE); |
| 41 | } |
| 42 | } |
| 43 | |
| 44 | void AArch64_ELFTargetObjectFile::emitPersonalityValueImpl( |
| 45 | MCStreamer &Streamer, const DataLayout &DL, const MCSymbol *Sym, |
| 46 | const MachineModuleInfo *MMI) const { |
| 47 | if (!MMI->getObjFileInfo<MachineModuleInfoELF>().hasSignedPersonality()) { |
| 48 | TargetLoweringObjectFileELF::emitPersonalityValueImpl(Streamer, DL, Sym, |
| 49 | MMI); |
| 50 | return; |
| 51 | } |
| 52 | auto *TS = static_cast<AArch64TargetStreamer *>(Streamer.getTargetStreamer()); |
| 53 | // The value is ptrauth_string_discriminator("personality") |
| 54 | constexpr uint16_t Discriminator = 0x7EAD; |
| 55 | TS->emitAuthValue(Expr: MCSymbolRefExpr::create(Symbol: Sym, Ctx&: getContext()), Discriminator, |
| 56 | Key: AArch64PACKey::IA, /*HasAddressDiversity=*/true); |
| 57 | } |
| 58 | |
| 59 | const MCExpr *AArch64_ELFTargetObjectFile::getIndirectSymViaGOTPCRel( |
| 60 | const GlobalValue *GV, const MCSymbol *Sym, const MCValue &MV, |
| 61 | int64_t Offset, MachineModuleInfo *MMI, MCStreamer &Streamer) const { |
| 62 | int64_t FinalOffset = Offset + MV.getConstant(); |
| 63 | const MCExpr *Res = |
| 64 | MCSymbolRefExpr::create(Symbol: Sym, specifier: AArch64::S_GOTPCREL, Ctx&: getContext()); |
| 65 | const MCExpr *Off = MCConstantExpr::create(Value: FinalOffset, Ctx&: getContext()); |
| 66 | return MCBinaryExpr::createAdd(LHS: Res, RHS: Off, Ctx&: getContext()); |
| 67 | } |
| 68 | |
| 69 | AArch64_MachoTargetObjectFile::AArch64_MachoTargetObjectFile() { |
| 70 | SupportGOTPCRelWithOffset = false; |
| 71 | } |
| 72 | |
| 73 | const MCExpr *AArch64_MachoTargetObjectFile::getTTypeGlobalReference( |
| 74 | const GlobalValue *GV, unsigned Encoding, const TargetMachine &TM, |
| 75 | MachineModuleInfo *MMI, MCStreamer &Streamer) const { |
| 76 | // On Darwin, we can reference dwarf symbols with foo@GOT-., which |
| 77 | // is an indirect pc-relative reference. The default implementation |
| 78 | // won't reference using the GOT, so we need this target-specific |
| 79 | // version. |
| 80 | if (Encoding & (DW_EH_PE_indirect | DW_EH_PE_pcrel)) { |
| 81 | const MCSymbol *Sym = TM.getSymbol(GV); |
| 82 | const MCExpr *Res = |
| 83 | MCSymbolRefExpr::create(Symbol: Sym, specifier: AArch64::S_MACHO_GOT, Ctx&: getContext()); |
| 84 | MCSymbol *PCSym = getContext().createTempSymbol(); |
| 85 | Streamer.emitLabel(Symbol: PCSym); |
| 86 | const MCExpr *PC = MCSymbolRefExpr::create(Symbol: PCSym, Ctx&: getContext()); |
| 87 | return MCBinaryExpr::createSub(LHS: Res, RHS: PC, Ctx&: getContext()); |
| 88 | } |
| 89 | |
| 90 | return TargetLoweringObjectFileMachO::getTTypeGlobalReference( |
| 91 | GV, Encoding, TM, MMI, Streamer); |
| 92 | } |
| 93 | |
| 94 | MCSymbol *AArch64_MachoTargetObjectFile::getCFIPersonalitySymbol( |
| 95 | const GlobalValue *GV, const TargetMachine &TM, |
| 96 | MachineModuleInfo *MMI) const { |
| 97 | return TM.getSymbol(GV); |
| 98 | } |
| 99 | |
| 100 | const MCExpr *AArch64_MachoTargetObjectFile::getIndirectSymViaGOTPCRel( |
| 101 | const GlobalValue *GV, const MCSymbol *Sym, const MCValue &MV, |
| 102 | int64_t Offset, MachineModuleInfo *MMI, MCStreamer &Streamer) const { |
| 103 | assert((Offset+MV.getConstant() == 0) && |
| 104 | "Arch64 does not support GOT PC rel with extra offset" ); |
| 105 | // On ARM64 Darwin, we can reference symbols with foo@GOT-., which |
| 106 | // is an indirect pc-relative reference. |
| 107 | const MCExpr *Res = |
| 108 | MCSymbolRefExpr::create(Symbol: Sym, specifier: AArch64::S_MACHO_GOT, Ctx&: getContext()); |
| 109 | MCSymbol *PCSym = getContext().createTempSymbol(); |
| 110 | Streamer.emitLabel(Symbol: PCSym); |
| 111 | const MCExpr *PC = MCSymbolRefExpr::create(Symbol: PCSym, Ctx&: getContext()); |
| 112 | return MCBinaryExpr::createSub(LHS: Res, RHS: PC, Ctx&: getContext()); |
| 113 | } |
| 114 | |
| 115 | void AArch64_MachoTargetObjectFile::getNameWithPrefix( |
| 116 | SmallVectorImpl<char> &OutName, const GlobalValue *GV, |
| 117 | const TargetMachine &TM) const { |
| 118 | // AArch64 does not use section-relative relocations so any global symbol must |
| 119 | // be accessed via at least a linker-private symbol. |
| 120 | getMangler().getNameWithPrefix(OutName, GV, /* CannotUsePrivateLabel */ true); |
| 121 | } |
| 122 | |
| 123 | template <typename MachineModuleInfoTarget> |
| 124 | static MCSymbol *getAuthPtrSlotSymbolHelper( |
| 125 | MCContext &Ctx, const TargetMachine &TM, MachineModuleInfo *MMI, |
| 126 | MachineModuleInfoTarget &TargetMMI, const MCSymbol *RawSym, |
| 127 | AArch64PACKey::ID Key, uint16_t Discriminator) { |
| 128 | const DataLayout &DL = MMI->getModule()->getDataLayout(); |
| 129 | |
| 130 | MCSymbol *StubSym = Ctx.getOrCreateSymbol( |
| 131 | Name: DL.getLinkerPrivateGlobalPrefix() + RawSym->getName() + |
| 132 | Twine("$auth_ptr$" ) + AArch64PACKeyIDToString(KeyID: Key) + Twine('$') + |
| 133 | Twine(Discriminator)); |
| 134 | |
| 135 | const MCExpr *&StubAuthPtrRef = TargetMMI.getAuthPtrStubEntry(StubSym); |
| 136 | |
| 137 | if (StubAuthPtrRef) |
| 138 | return StubSym; |
| 139 | |
| 140 | const MCExpr *Sym = MCSymbolRefExpr::create(Symbol: RawSym, Ctx); |
| 141 | |
| 142 | StubAuthPtrRef = |
| 143 | AArch64AuthMCExpr::create(Expr: Sym, Discriminator, Key, |
| 144 | /*HasAddressDiversity=*/false, Ctx); |
| 145 | return StubSym; |
| 146 | } |
| 147 | |
| 148 | MCSymbol *AArch64_ELFTargetObjectFile::getAuthPtrSlotSymbol( |
| 149 | const TargetMachine &TM, MachineModuleInfo *MMI, const MCSymbol *RawSym, |
| 150 | AArch64PACKey::ID Key, uint16_t Discriminator) const { |
| 151 | auto &ELFMMI = MMI->getObjFileInfo<MachineModuleInfoELF>(); |
| 152 | return getAuthPtrSlotSymbolHelper(Ctx&: getContext(), TM, MMI, TargetMMI&: ELFMMI, RawSym, Key, |
| 153 | Discriminator); |
| 154 | } |
| 155 | |
| 156 | MCSymbol *AArch64_MachoTargetObjectFile::getAuthPtrSlotSymbol( |
| 157 | const TargetMachine &TM, MachineModuleInfo *MMI, const MCSymbol *RawSym, |
| 158 | AArch64PACKey::ID Key, uint16_t Discriminator) const { |
| 159 | auto &MachOMMI = MMI->getObjFileInfo<MachineModuleInfoMachO>(); |
| 160 | return getAuthPtrSlotSymbolHelper(Ctx&: getContext(), TM, MMI, TargetMMI&: MachOMMI, RawSym, |
| 161 | Key, Discriminator); |
| 162 | } |
| 163 | |
| 164 | static bool isExecuteOnlyFunction(const GlobalObject *GO, SectionKind Kind, |
| 165 | const TargetMachine &TM) { |
| 166 | if (const Function *F = dyn_cast<Function>(Val: GO)) |
| 167 | if (TM.getSubtarget<AArch64Subtarget>(F: *F).genExecuteOnly() && Kind.isText()) |
| 168 | return true; |
| 169 | return false; |
| 170 | } |
| 171 | |
| 172 | MCSection *AArch64_ELFTargetObjectFile::getExplicitSectionGlobal( |
| 173 | const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const { |
| 174 | // Set execute-only access for the explicit section |
| 175 | if (isExecuteOnlyFunction(GO, Kind, TM)) |
| 176 | Kind = SectionKind::getExecuteOnly(); |
| 177 | |
| 178 | return TargetLoweringObjectFileELF::getExplicitSectionGlobal(GO, Kind, TM); |
| 179 | } |
| 180 | |
| 181 | MCSection *AArch64_ELFTargetObjectFile::SelectSectionForGlobal( |
| 182 | const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const { |
| 183 | // Set execute-only access for the explicit section |
| 184 | if (isExecuteOnlyFunction(GO, Kind, TM)) |
| 185 | Kind = SectionKind::getExecuteOnly(); |
| 186 | |
| 187 | return TargetLoweringObjectFileELF::SelectSectionForGlobal(GO, Kind, TM); |
| 188 | } |
| 189 | |