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 | |