54
54
#include " llvm/MC/MCSectionMachO.h"
55
55
#include " llvm/MC/MCStreamer.h"
56
56
#include " llvm/MC/MCSymbol.h"
57
+ #include " llvm/MC/MCValue.h"
57
58
#include " llvm/MC/TargetRegistry.h"
58
59
#include " llvm/Support/Casting.h"
59
60
#include " llvm/Support/CommandLine.h"
@@ -84,6 +85,7 @@ class AArch64AsmPrinter : public AsmPrinter {
84
85
bool EnableImportCallOptimization = false ;
85
86
DenseMap<MCSection *, std::vector<std::pair<MCSymbol *, MCSymbol *>>>
86
87
SectionToImportedFunctionCalls;
88
+ unsigned PAuthIFuncNextUniqueID = 1 ;
87
89
88
90
public:
89
91
AArch64AsmPrinter (TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer)
@@ -191,6 +193,10 @@ class AArch64AsmPrinter : public AsmPrinter {
191
193
// authenticating)
192
194
void LowerLOADgotAUTH (const MachineInstr &MI);
193
195
196
+ const MCExpr *emitPAuthRelocationAsIRelative (
197
+ const MCExpr *Target, uint16_t Disc, AArch64PACKey::ID KeyID,
198
+ bool HasAddressDiversity, bool IsDSOLocal);
199
+
194
200
// / tblgen'erated driver function for lowering simple MI->MC
195
201
// / pseudo instructions.
196
202
bool lowerPseudoInstExpansion (const MachineInstr *MI, MCInst &Inst);
@@ -2218,6 +2224,145 @@ void AArch64AsmPrinter::emitPtrauthBranch(const MachineInstr *MI) {
2218
2224
EmitToStreamer (*OutStreamer, BRInst);
2219
2225
}
2220
2226
2227
+ static void emitAddress (MCStreamer &Streamer, MCRegister Reg,
2228
+ const MCExpr *Expr, bool DSOLocal,
2229
+ const MCSubtargetInfo &STI) {
2230
+ MCValue Val;
2231
+ if (!Expr->evaluateAsRelocatable (Val, nullptr ))
2232
+ report_fatal_error (" emitAddress could not evaluate" );
2233
+ if (DSOLocal) {
2234
+ Streamer.emitInstruction (
2235
+ MCInstBuilder (AArch64::ADRP)
2236
+ .addReg (Reg)
2237
+ .addExpr (AArch64MCExpr::create (Expr, AArch64MCExpr::VK_ABS_PAGE,
2238
+ Streamer.getContext ())),
2239
+ STI);
2240
+ Streamer.emitInstruction (
2241
+ MCInstBuilder (AArch64::ADDXri)
2242
+ .addReg (Reg)
2243
+ .addReg (Reg)
2244
+ .addExpr (AArch64MCExpr::create (Expr, AArch64MCExpr::VK_LO12,
2245
+ Streamer.getContext ()))
2246
+ .addImm (0 ),
2247
+ STI);
2248
+ } else {
2249
+ Streamer.emitInstruction (MCInstBuilder (AArch64::ADRP)
2250
+ .addReg (Reg)
2251
+ .addExpr (AArch64MCExpr::create (
2252
+ Val.getSymA (), AArch64MCExpr::VK_GOT_PAGE,
2253
+ Streamer.getContext ())),
2254
+ STI);
2255
+ Streamer.emitInstruction (MCInstBuilder (AArch64::LDRXui)
2256
+ .addReg (Reg)
2257
+ .addReg (Reg)
2258
+ .addExpr (AArch64MCExpr::create (
2259
+ Val.getSymA (), AArch64MCExpr::VK_GOT_LO12,
2260
+ Streamer.getContext ())),
2261
+ STI);
2262
+ if (Val.getConstant ())
2263
+ Streamer.emitInstruction (MCInstBuilder (AArch64::ADDXri)
2264
+ .addReg (Reg)
2265
+ .addReg (Reg)
2266
+ .addImm (Val.getConstant ())
2267
+ .addImm (0 ),
2268
+ STI);
2269
+ }
2270
+ }
2271
+
2272
+ static bool targetSupportsPAuthRelocation (const Triple &TT,
2273
+ const MCExpr *Target) {
2274
+ // No released version of glibc supports PAuth relocations.
2275
+ if (TT.isOSGlibc ())
2276
+ return false ;
2277
+
2278
+ // We emit PAuth constants as IRELATIVE relocations in cases where the
2279
+ // constant cannot be represented as a PAuth relocation:
2280
+ // 1) The signed value is not a symbol.
2281
+ return !isa<MCConstantExpr>(Target);
2282
+ }
2283
+
2284
+ static bool targetSupportsIRelativeRelocation (const Triple &TT) {
2285
+ // IFUNCs are ELF-only.
2286
+ if (!TT.isOSBinFormatELF ())
2287
+ return false ;
2288
+
2289
+ // musl doesn't support IFUNCs.
2290
+ if (TT.isMusl ())
2291
+ return false ;
2292
+
2293
+ return true ;
2294
+ }
2295
+
2296
+ const MCExpr *AArch64AsmPrinter::emitPAuthRelocationAsIRelative (
2297
+ const MCExpr *Target, uint16_t Disc, AArch64PACKey::ID KeyID,
2298
+ bool HasAddressDiversity, bool IsDSOLocal) {
2299
+ const Triple &TT = TM.getTargetTriple ();
2300
+
2301
+ // We only emit an IRELATIVE relocation if the target supports IRELATIVE and
2302
+ // does not support the kind of PAuth relocation that we are trying to emit.
2303
+ if (targetSupportsPAuthRelocation (TT, Target, DSExpr) ||
2304
+ !targetSupportsIRelativeRelocation (TT))
2305
+ return nullptr ;
2306
+
2307
+ // For now, only the DA key is supported.
2308
+ if (KeyID != AArch64PACKey::DA)
2309
+ return nullptr ;
2310
+
2311
+ std::unique_ptr<MCSubtargetInfo> STI (
2312
+ TM.getTarget ().createMCSubtargetInfo (TT.str (), " " , " " ));
2313
+ assert (STI && " Unable to create subtarget info" );
2314
+
2315
+ MCSymbol *Place = OutStreamer->getContext ().createTempSymbol ();
2316
+ OutStreamer->emitLabel (Place);
2317
+ OutStreamer->pushSection ();
2318
+
2319
+ OutStreamer->switchSection (OutStreamer->getContext ().getELFSection (
2320
+ " .text.startup" , ELF::SHT_PROGBITS, ELF::SHF_ALLOC | ELF::SHF_EXECINSTR,
2321
+ 0 , " " , true , PAuthIFuncNextUniqueID++, nullptr ));
2322
+
2323
+ MCSymbol *IFuncSym =
2324
+ OutStreamer->getContext ().createLinkerPrivateSymbol (" pauth_ifunc" );
2325
+ OutStreamer->emitSymbolAttribute (IFuncSym, MCSA_ELF_TypeIndFunction);
2326
+ OutStreamer->emitLabel (IFuncSym);
2327
+ if (isa<MCConstantExpr>(Target)) {
2328
+ OutStreamer->emitInstruction (MCInstBuilder (AArch64::MOVZXi)
2329
+ .addReg (AArch64::X0)
2330
+ .addExpr (Target)
2331
+ .addImm (0 ),
2332
+ *STI);
2333
+ } else {
2334
+ emitAddress (*OutStreamer, AArch64::X0, Target, IsDSOLocal, *STI);
2335
+ }
2336
+ if (HasAddressDiversity) {
2337
+ auto *PlacePlusDisc = MCBinaryExpr::createAdd (
2338
+ MCSymbolRefExpr::create (Place, OutStreamer->getContext ()),
2339
+ MCConstantExpr::create (static_cast <int16_t >(Disc),
2340
+ OutStreamer->getContext ()),
2341
+ OutStreamer->getContext ());
2342
+ emitAddress (*OutStreamer, AArch64::X1, PlacePlusDisc, /* IsDSOLocal=*/ true ,
2343
+ *STI);
2344
+ } else {
2345
+ emitMOVZ (AArch64::X1, Disc, 0 );
2346
+ }
2347
+
2348
+ MCSymbol *PrePACInst = OutStreamer->getContext ().createTempSymbol ();
2349
+ OutStreamer->emitLabel (PrePACInst);
2350
+
2351
+ // We don't know the subtarget because this is being emitted for a global
2352
+ // initializer. Because the performance of IFUNC resolvers is unimportant, we
2353
+ // always call the EmuPAC runtime, which will end up using the PAC instruction
2354
+ // if the target supports PAC.
2355
+ MCSymbol *EmuPAC =
2356
+ OutStreamer->getContext ().getOrCreateSymbol (" __emupac_pacda" );
2357
+ const MCSymbolRefExpr *EmuPACRef =
2358
+ MCSymbolRefExpr::create (EmuPAC, OutStreamer->getContext ());
2359
+ OutStreamer->emitInstruction (MCInstBuilder (AArch64::B).addExpr (EmuPACRef),
2360
+ *STI);
2361
+ OutStreamer->popSection ();
2362
+
2363
+ return MCSymbolRefExpr::create (IFuncSym, OutStreamer->getContext ());
2364
+ }
2365
+
2221
2366
const MCExpr *
2222
2367
AArch64AsmPrinter::lowerConstantPtrAuth (const ConstantPtrAuth &CPA) {
2223
2368
MCContext &Ctx = OutContext;
@@ -2229,23 +2374,20 @@ AArch64AsmPrinter::lowerConstantPtrAuth(const ConstantPtrAuth &CPA) {
2229
2374
2230
2375
auto *BaseGVB = dyn_cast<GlobalValue>(BaseGV);
2231
2376
2232
- // If we can't understand the referenced ConstantExpr, there's nothing
2233
- // else we can do: emit an error.
2234
- if (!BaseGVB) {
2235
- BaseGV->getContext ().emitError (
2236
- " cannot resolve target base/addend of ptrauth constant" );
2237
- return nullptr ;
2377
+ const MCExpr *Sym;
2378
+ if (BaseGVB) {
2379
+ // If there is an addend, turn that into the appropriate MCExpr.
2380
+ Sym = MCSymbolRefExpr::create (getSymbol (BaseGVB), Ctx);
2381
+ if (Offset.sgt (0 ))
2382
+ Sym = MCBinaryExpr::createAdd (
2383
+ Sym, MCConstantExpr::create (Offset.getSExtValue (), Ctx), Ctx);
2384
+ else if (Offset.slt (0 ))
2385
+ Sym = MCBinaryExpr::createSub (
2386
+ Sym, MCConstantExpr::create ((-Offset).getSExtValue (), Ctx), Ctx);
2387
+ } else {
2388
+ Sym = MCConstantExpr::create (Offset.getSExtValue (), Ctx);
2238
2389
}
2239
2390
2240
- // If there is an addend, turn that into the appropriate MCExpr.
2241
- const MCExpr *Sym = MCSymbolRefExpr::create (getSymbol (BaseGVB), Ctx);
2242
- if (Offset.sgt (0 ))
2243
- Sym = MCBinaryExpr::createAdd (
2244
- Sym, MCConstantExpr::create (Offset.getSExtValue (), Ctx), Ctx);
2245
- else if (Offset.slt (0 ))
2246
- Sym = MCBinaryExpr::createSub (
2247
- Sym, MCConstantExpr::create ((-Offset).getSExtValue (), Ctx), Ctx);
2248
-
2249
2391
uint64_t KeyID = CPA.getKey ()->getZExtValue ();
2250
2392
// We later rely on valid KeyID value in AArch64PACKeyIDToString call from
2251
2393
// AArch64AuthMCExpr::printImpl, so fail fast.
@@ -2259,6 +2401,12 @@ AArch64AsmPrinter::lowerConstantPtrAuth(const ConstantPtrAuth &CPA) {
2259
2401
report_fatal_error (" AArch64 PAC Discriminator '" + Twine (Disc) +
2260
2402
" ' out of range [0, 0xFFFF]" );
2261
2403
2404
+ // Check if we need to represent this with an IRELATIVE and emit it if so.
2405
+ if (auto *IFuncSym = emitPAuthRelocationAsIRelative (
2406
+ Sym, Disc, AArch64PACKey::ID (KeyID), CPA.hasAddressDiscriminator (),
2407
+ BaseGVB && BaseGVB->isDSOLocal ()))
2408
+ return IFuncSym;
2409
+
2262
2410
// Finally build the complete @AUTH expr.
2263
2411
return AArch64AuthMCExpr::create (Sym, Disc, AArch64PACKey::ID (KeyID),
2264
2412
CPA.hasAddressDiscriminator (), Ctx);
0 commit comments