49
49
#include " llvm/IR/Module.h"
50
50
#include " llvm/MC/MCAsmInfo.h"
51
51
#include " llvm/MC/MCContext.h"
52
+ #include " llvm/MC/MCExpr.h"
52
53
#include " llvm/MC/MCInst.h"
53
54
#include " llvm/MC/MCInstBuilder.h"
54
55
#include " llvm/MC/MCSectionELF.h"
55
56
#include " llvm/MC/MCSectionMachO.h"
56
57
#include " llvm/MC/MCStreamer.h"
57
58
#include " llvm/MC/MCSymbol.h"
59
+ #include " llvm/MC/MCValue.h"
58
60
#include " llvm/MC/TargetRegistry.h"
59
61
#include " llvm/Support/Casting.h"
60
62
#include " llvm/Support/CommandLine.h"
@@ -95,6 +97,7 @@ class AArch64AsmPrinter : public AsmPrinter {
95
97
bool EnableImportCallOptimization = false ;
96
98
DenseMap<MCSection *, std::vector<std::pair<MCSymbol *, MCSymbol *>>>
97
99
SectionToImportedFunctionCalls;
100
+ unsigned PAuthIFuncNextUniqueID = 1 ;
98
101
99
102
public:
100
103
static char ID;
@@ -209,6 +212,10 @@ class AArch64AsmPrinter : public AsmPrinter {
209
212
// authenticating)
210
213
void LowerLOADgotAUTH (const MachineInstr &MI);
211
214
215
+ const MCExpr *emitPAuthRelocationAsIRelative (
216
+ const MCExpr *Target, uint16_t Disc, AArch64PACKey::ID KeyID,
217
+ bool HasAddressDiversity, bool IsDSOLocal);
218
+
212
219
// / tblgen'erated driver function for lowering simple MI->MC
213
220
// / pseudo instructions.
214
221
bool lowerPseudoInstExpansion (const MachineInstr *MI, MCInst &Inst);
@@ -2225,6 +2232,146 @@ void AArch64AsmPrinter::emitPtrauthBranch(const MachineInstr *MI) {
2225
2232
EmitToStreamer (*OutStreamer, BRInst);
2226
2233
}
2227
2234
2235
+ static void emitAddress (MCStreamer &Streamer, MCRegister Reg,
2236
+ const MCExpr *Expr, bool DSOLocal,
2237
+ const MCSubtargetInfo &STI) {
2238
+ MCValue Val;
2239
+ if (!Expr->evaluateAsRelocatable (Val, nullptr ))
2240
+ report_fatal_error (" emitAddress could not evaluate" );
2241
+ if (DSOLocal) {
2242
+ Streamer.emitInstruction (
2243
+ MCInstBuilder (AArch64::ADRP)
2244
+ .addReg (Reg)
2245
+ .addExpr (MCSpecifierExpr::create (Expr, AArch64::S_ABS_PAGE,
2246
+ Streamer.getContext ())),
2247
+ STI);
2248
+ Streamer.emitInstruction (
2249
+ MCInstBuilder (AArch64::ADDXri)
2250
+ .addReg (Reg)
2251
+ .addReg (Reg)
2252
+ .addExpr (MCSpecifierExpr::create (Expr, AArch64::S_LO12,
2253
+ Streamer.getContext ()))
2254
+ .addImm (0 ),
2255
+ STI);
2256
+ } else {
2257
+ auto *SymRef = MCSymbolRefExpr::create (Val.getAddSym (), Streamer.getContext ());
2258
+ Streamer.emitInstruction (
2259
+ MCInstBuilder (AArch64::ADRP)
2260
+ .addReg (Reg)
2261
+ .addExpr (MCSpecifierExpr::create (SymRef, AArch64::S_GOT_PAGE,
2262
+ Streamer.getContext ())),
2263
+ STI);
2264
+ Streamer.emitInstruction (
2265
+ MCInstBuilder (AArch64::LDRXui)
2266
+ .addReg (Reg)
2267
+ .addReg (Reg)
2268
+ .addExpr (MCSpecifierExpr::create (SymRef, AArch64::S_GOT_LO12,
2269
+ Streamer.getContext ())),
2270
+ STI);
2271
+ if (Val.getConstant ())
2272
+ Streamer.emitInstruction (MCInstBuilder (AArch64::ADDXri)
2273
+ .addReg (Reg)
2274
+ .addReg (Reg)
2275
+ .addImm (Val.getConstant ())
2276
+ .addImm (0 ),
2277
+ STI);
2278
+ }
2279
+ }
2280
+
2281
+ static bool targetSupportsPAuthRelocation (const Triple &TT,
2282
+ const MCExpr *Target) {
2283
+ // No released version of glibc supports PAuth relocations.
2284
+ if (TT.isOSGlibc ())
2285
+ return false ;
2286
+
2287
+ // We emit PAuth constants as IRELATIVE relocations in cases where the
2288
+ // constant cannot be represented as a PAuth relocation:
2289
+ // 1) The signed value is not a symbol.
2290
+ return !isa<MCConstantExpr>(Target);
2291
+ }
2292
+
2293
+ static bool targetSupportsIRelativeRelocation (const Triple &TT) {
2294
+ // IFUNCs are ELF-only.
2295
+ if (!TT.isOSBinFormatELF ())
2296
+ return false ;
2297
+
2298
+ // musl doesn't support IFUNCs.
2299
+ if (TT.isMusl ())
2300
+ return false ;
2301
+
2302
+ return true ;
2303
+ }
2304
+
2305
+ const MCExpr *AArch64AsmPrinter::emitPAuthRelocationAsIRelative (
2306
+ const MCExpr *Target, uint16_t Disc, AArch64PACKey::ID KeyID,
2307
+ bool HasAddressDiversity, bool IsDSOLocal) {
2308
+ const Triple &TT = TM.getTargetTriple ();
2309
+
2310
+ // We only emit an IRELATIVE relocation if the target supports IRELATIVE and
2311
+ // does not support the kind of PAuth relocation that we are trying to emit.
2312
+ if (targetSupportsPAuthRelocation (TT, Target) ||
2313
+ !targetSupportsIRelativeRelocation (TT))
2314
+ return nullptr ;
2315
+
2316
+ // For now, only the DA key is supported.
2317
+ if (KeyID != AArch64PACKey::DA)
2318
+ return nullptr ;
2319
+
2320
+ std::unique_ptr<MCSubtargetInfo> STI (
2321
+ TM.getTarget ().createMCSubtargetInfo (TT.str (), " " , " " ));
2322
+ assert (STI && " Unable to create subtarget info" );
2323
+
2324
+ MCSymbol *Place = OutStreamer->getContext ().createTempSymbol ();
2325
+ OutStreamer->emitLabel (Place);
2326
+ OutStreamer->pushSection ();
2327
+
2328
+ OutStreamer->switchSection (OutStreamer->getContext ().getELFSection (
2329
+ " .text.startup" , ELF::SHT_PROGBITS, ELF::SHF_ALLOC | ELF::SHF_EXECINSTR,
2330
+ 0 , " " , true , PAuthIFuncNextUniqueID++, nullptr ));
2331
+
2332
+ MCSymbol *IRelativeSym =
2333
+ OutStreamer->getContext ().createLinkerPrivateSymbol (" pauth_ifunc" );
2334
+ OutStreamer->emitLabel (IRelativeSym);
2335
+ if (isa<MCConstantExpr>(Target)) {
2336
+ OutStreamer->emitInstruction (MCInstBuilder (AArch64::MOVZXi)
2337
+ .addReg (AArch64::X0)
2338
+ .addExpr (Target)
2339
+ .addImm (0 ),
2340
+ *STI);
2341
+ } else {
2342
+ emitAddress (*OutStreamer, AArch64::X0, Target, IsDSOLocal, *STI);
2343
+ }
2344
+ if (HasAddressDiversity) {
2345
+ auto *PlacePlusDisc = MCBinaryExpr::createAdd (
2346
+ MCSymbolRefExpr::create (Place, OutStreamer->getContext ()),
2347
+ MCConstantExpr::create (static_cast <int16_t >(Disc),
2348
+ OutStreamer->getContext ()),
2349
+ OutStreamer->getContext ());
2350
+ emitAddress (*OutStreamer, AArch64::X1, PlacePlusDisc, /* IsDSOLocal=*/ true ,
2351
+ *STI);
2352
+ } else {
2353
+ emitMOVZ (AArch64::X1, Disc, 0 );
2354
+ }
2355
+
2356
+ MCSymbol *PrePACInst = OutStreamer->getContext ().createTempSymbol ();
2357
+ OutStreamer->emitLabel (PrePACInst);
2358
+
2359
+ // We don't know the subtarget because this is being emitted for a global
2360
+ // initializer. Because the performance of IFUNC resolvers is unimportant, we
2361
+ // always call the EmuPAC runtime, which will end up using the PAC instruction
2362
+ // if the target supports PAC.
2363
+ MCSymbol *EmuPAC =
2364
+ OutStreamer->getContext ().getOrCreateSymbol (" __emupac_pacda" );
2365
+ const MCSymbolRefExpr *EmuPACRef =
2366
+ MCSymbolRefExpr::create (EmuPAC, OutStreamer->getContext ());
2367
+ OutStreamer->emitInstruction (MCInstBuilder (AArch64::B).addExpr (EmuPACRef),
2368
+ *STI);
2369
+ OutStreamer->popSection ();
2370
+
2371
+ return MCSpecifierExpr::create (IRelativeSym, AArch64::S_FUNCINIT,
2372
+ OutStreamer->getContext ());
2373
+ }
2374
+
2228
2375
const MCExpr *
2229
2376
AArch64AsmPrinter::lowerConstantPtrAuth (const ConstantPtrAuth &CPA) {
2230
2377
MCContext &Ctx = OutContext;
@@ -2236,23 +2383,20 @@ AArch64AsmPrinter::lowerConstantPtrAuth(const ConstantPtrAuth &CPA) {
2236
2383
2237
2384
auto *BaseGVB = dyn_cast<GlobalValue>(BaseGV);
2238
2385
2239
- // If we can't understand the referenced ConstantExpr, there's nothing
2240
- // else we can do: emit an error.
2241
- if (!BaseGVB) {
2242
- BaseGV->getContext ().emitError (
2243
- " cannot resolve target base/addend of ptrauth constant" );
2244
- return nullptr ;
2386
+ const MCExpr *Sym;
2387
+ if (BaseGVB) {
2388
+ // If there is an addend, turn that into the appropriate MCExpr.
2389
+ Sym = MCSymbolRefExpr::create (getSymbol (BaseGVB), Ctx);
2390
+ if (Offset.sgt (0 ))
2391
+ Sym = MCBinaryExpr::createAdd (
2392
+ Sym, MCConstantExpr::create (Offset.getSExtValue (), Ctx), Ctx);
2393
+ else if (Offset.slt (0 ))
2394
+ Sym = MCBinaryExpr::createSub (
2395
+ Sym, MCConstantExpr::create ((-Offset).getSExtValue (), Ctx), Ctx);
2396
+ } else {
2397
+ Sym = MCConstantExpr::create (Offset.getSExtValue (), Ctx);
2245
2398
}
2246
2399
2247
- // If there is an addend, turn that into the appropriate MCExpr.
2248
- const MCExpr *Sym = MCSymbolRefExpr::create (getSymbol (BaseGVB), Ctx);
2249
- if (Offset.sgt (0 ))
2250
- Sym = MCBinaryExpr::createAdd (
2251
- Sym, MCConstantExpr::create (Offset.getSExtValue (), Ctx), Ctx);
2252
- else if (Offset.slt (0 ))
2253
- Sym = MCBinaryExpr::createSub (
2254
- Sym, MCConstantExpr::create ((-Offset).getSExtValue (), Ctx), Ctx);
2255
-
2256
2400
uint64_t KeyID = CPA.getKey ()->getZExtValue ();
2257
2401
// We later rely on valid KeyID value in AArch64PACKeyIDToString call from
2258
2402
// AArch64AuthMCExpr::printImpl, so fail fast.
@@ -2270,6 +2414,12 @@ AArch64AsmPrinter::lowerConstantPtrAuth(const ConstantPtrAuth &CPA) {
2270
2414
Disc = 0 ;
2271
2415
}
2272
2416
2417
+ // Check if we need to represent this with an IRELATIVE and emit it if so.
2418
+ if (auto *IFuncSym = emitPAuthRelocationAsIRelative (
2419
+ Sym, Disc, AArch64PACKey::ID (KeyID), CPA.hasAddressDiscriminator (),
2420
+ BaseGVB && BaseGVB->isDSOLocal ()))
2421
+ return IFuncSym;
2422
+
2273
2423
// Finally build the complete @AUTH expr.
2274
2424
return AArch64AuthMCExpr::create (Sym, Disc, AArch64PACKey::ID (KeyID),
2275
2425
CPA.hasAddressDiscriminator (), Ctx);
0 commit comments