4949#include " llvm/IR/Module.h"
5050#include " llvm/MC/MCAsmInfo.h"
5151#include " llvm/MC/MCContext.h"
52+ #include " llvm/MC/MCExpr.h"
5253#include " llvm/MC/MCInst.h"
5354#include " llvm/MC/MCInstBuilder.h"
5455#include " llvm/MC/MCSectionELF.h"
5556#include " llvm/MC/MCSectionMachO.h"
5657#include " llvm/MC/MCStreamer.h"
5758#include " llvm/MC/MCSymbol.h"
59+ #include " llvm/MC/MCValue.h"
5860#include " llvm/MC/TargetRegistry.h"
5961#include " llvm/Support/Casting.h"
6062#include " llvm/Support/CommandLine.h"
@@ -95,6 +97,7 @@ class AArch64AsmPrinter : public AsmPrinter {
9597 bool EnableImportCallOptimization = false ;
9698 DenseMap<MCSection *, std::vector<std::pair<MCSymbol *, MCSymbol *>>>
9799 SectionToImportedFunctionCalls;
100+ unsigned PAuthIFuncNextUniqueID = 1 ;
98101
99102public:
100103 static char ID;
@@ -212,6 +215,10 @@ class AArch64AsmPrinter : public AsmPrinter {
212215 // authenticating)
213216 void LowerLOADgotAUTH (const MachineInstr &MI);
214217
218+ const MCExpr *emitPAuthRelocationAsIRelative (
219+ const MCExpr *Target, uint16_t Disc, AArch64PACKey::ID KeyID,
220+ bool HasAddressDiversity, bool IsDSOLocal);
221+
215222 // / tblgen'erated driver function for lowering simple MI->MC
216223 // / pseudo instructions.
217224 bool lowerPseudoInstExpansion (const MachineInstr *MI, MCInst &Inst);
@@ -2259,6 +2266,143 @@ void AArch64AsmPrinter::emitPtrauthBranch(const MachineInstr *MI) {
22592266 EmitToStreamer (*OutStreamer, BRInst);
22602267}
22612268
2269+ static void emitAddress (MCStreamer &Streamer, MCRegister Reg,
2270+ const MCExpr *Expr, bool DSOLocal,
2271+ const MCSubtargetInfo &STI) {
2272+ MCValue Val;
2273+ if (!Expr->evaluateAsRelocatable (Val, nullptr ))
2274+ report_fatal_error (" emitAddress could not evaluate" );
2275+ if (DSOLocal) {
2276+ Streamer.emitInstruction (
2277+ MCInstBuilder (AArch64::ADRP)
2278+ .addReg (Reg)
2279+ .addExpr (MCSpecifierExpr::create (Expr, AArch64::S_ABS_PAGE,
2280+ Streamer.getContext ())),
2281+ STI);
2282+ Streamer.emitInstruction (
2283+ MCInstBuilder (AArch64::ADDXri)
2284+ .addReg (Reg)
2285+ .addReg (Reg)
2286+ .addExpr (MCSpecifierExpr::create (Expr, AArch64::S_LO12,
2287+ Streamer.getContext ()))
2288+ .addImm (0 ),
2289+ STI);
2290+ } else {
2291+ auto *SymRef = MCSymbolRefExpr::create (Val.getAddSym (), Streamer.getContext ());
2292+ Streamer.emitInstruction (
2293+ MCInstBuilder (AArch64::ADRP)
2294+ .addReg (Reg)
2295+ .addExpr (MCSpecifierExpr::create (SymRef, AArch64::S_GOT_PAGE,
2296+ Streamer.getContext ())),
2297+ STI);
2298+ Streamer.emitInstruction (
2299+ MCInstBuilder (AArch64::LDRXui)
2300+ .addReg (Reg)
2301+ .addReg (Reg)
2302+ .addExpr (MCSpecifierExpr::create (SymRef, AArch64::S_GOT_LO12,
2303+ Streamer.getContext ())),
2304+ STI);
2305+ if (Val.getConstant ())
2306+ Streamer.emitInstruction (MCInstBuilder (AArch64::ADDXri)
2307+ .addReg (Reg)
2308+ .addReg (Reg)
2309+ .addImm (Val.getConstant ())
2310+ .addImm (0 ),
2311+ STI);
2312+ }
2313+ }
2314+
2315+ static bool targetSupportsPAuthRelocation (const Triple &TT,
2316+ const MCExpr *Target) {
2317+ // No released version of glibc supports PAuth relocations.
2318+ if (TT.isOSGlibc ())
2319+ return false ;
2320+
2321+ // We emit PAuth constants as IRELATIVE relocations in cases where the
2322+ // constant cannot be represented as a PAuth relocation:
2323+ // 1) The signed value is not a symbol.
2324+ return !isa<MCConstantExpr>(Target);
2325+ }
2326+
2327+ static bool targetSupportsIRelativeRelocation (const Triple &TT) {
2328+ // IFUNCs are ELF-only.
2329+ if (!TT.isOSBinFormatELF ())
2330+ return false ;
2331+
2332+ // musl doesn't support IFUNCs.
2333+ if (TT.isMusl ())
2334+ return false ;
2335+
2336+ return true ;
2337+ }
2338+
2339+ const MCExpr *AArch64AsmPrinter::emitPAuthRelocationAsIRelative (
2340+ const MCExpr *Target, uint16_t Disc, AArch64PACKey::ID KeyID,
2341+ bool HasAddressDiversity, bool IsDSOLocal) {
2342+ const Triple &TT = TM.getTargetTriple ();
2343+
2344+ // We only emit an IRELATIVE relocation if the target supports IRELATIVE and
2345+ // does not support the kind of PAuth relocation that we are trying to emit.
2346+ if (targetSupportsPAuthRelocation (TT, Target) ||
2347+ !targetSupportsIRelativeRelocation (TT))
2348+ return nullptr ;
2349+
2350+ // For now, only the DA key is supported.
2351+ if (KeyID != AArch64PACKey::DA)
2352+ return nullptr ;
2353+
2354+ std::unique_ptr<MCSubtargetInfo> STI (
2355+ TM.getTarget ().createMCSubtargetInfo (TT.str (), " " , " " ));
2356+ assert (STI && " Unable to create subtarget info" );
2357+
2358+ MCSymbol *Place = OutStreamer->getContext ().createTempSymbol ();
2359+ OutStreamer->emitLabel (Place);
2360+ OutStreamer->pushSection ();
2361+
2362+ OutStreamer->switchSection (OutStreamer->getContext ().getELFSection (
2363+ " .text.startup" , ELF::SHT_PROGBITS, ELF::SHF_ALLOC | ELF::SHF_EXECINSTR,
2364+ 0 , " " , true , PAuthIFuncNextUniqueID++, nullptr ));
2365+
2366+ MCSymbol *IRelativeSym =
2367+ OutStreamer->getContext ().createLinkerPrivateSymbol (" pauth_ifunc" );
2368+ OutStreamer->emitLabel (IRelativeSym);
2369+ if (isa<MCConstantExpr>(Target)) {
2370+ OutStreamer->emitInstruction (MCInstBuilder (AArch64::MOVZXi)
2371+ .addReg (AArch64::X0)
2372+ .addExpr (Target)
2373+ .addImm (0 ),
2374+ *STI);
2375+ } else {
2376+ emitAddress (*OutStreamer, AArch64::X0, Target, IsDSOLocal, *STI);
2377+ }
2378+ if (HasAddressDiversity) {
2379+ auto *PlacePlusDisc = MCBinaryExpr::createAdd (
2380+ MCSymbolRefExpr::create (Place, OutStreamer->getContext ()),
2381+ MCConstantExpr::create (static_cast <int16_t >(Disc),
2382+ OutStreamer->getContext ()),
2383+ OutStreamer->getContext ());
2384+ emitAddress (*OutStreamer, AArch64::X1, PlacePlusDisc, /* IsDSOLocal=*/ true ,
2385+ *STI);
2386+ } else {
2387+ emitMOVZ (AArch64::X1, Disc, 0 );
2388+ }
2389+
2390+ // We don't know the subtarget because this is being emitted for a global
2391+ // initializer. Because the performance of IFUNC resolvers is unimportant, we
2392+ // always call the EmuPAC runtime, which will end up using the PAC instruction
2393+ // if the target supports PAC.
2394+ MCSymbol *EmuPAC =
2395+ OutStreamer->getContext ().getOrCreateSymbol (" __emupac_pacda" );
2396+ const MCSymbolRefExpr *EmuPACRef =
2397+ MCSymbolRefExpr::create (EmuPAC, OutStreamer->getContext ());
2398+ OutStreamer->emitInstruction (MCInstBuilder (AArch64::B).addExpr (EmuPACRef),
2399+ *STI);
2400+ OutStreamer->popSection ();
2401+
2402+ return MCSymbolRefExpr::create (IRelativeSym, AArch64::S_FUNCINIT,
2403+ OutStreamer->getContext ());
2404+ }
2405+
22622406const MCExpr *
22632407AArch64AsmPrinter::lowerConstantPtrAuth (const ConstantPtrAuth &CPA) {
22642408 MCContext &Ctx = OutContext;
@@ -2270,23 +2414,20 @@ AArch64AsmPrinter::lowerConstantPtrAuth(const ConstantPtrAuth &CPA) {
22702414
22712415 auto *BaseGVB = dyn_cast<GlobalValue>(BaseGV);
22722416
2273- // If we can't understand the referenced ConstantExpr, there's nothing
2274- // else we can do: emit an error.
2275- if (!BaseGVB) {
2276- BaseGV->getContext ().emitError (
2277- " cannot resolve target base/addend of ptrauth constant" );
2278- return nullptr ;
2417+ const MCExpr *Sym;
2418+ if (BaseGVB) {
2419+ // If there is an addend, turn that into the appropriate MCExpr.
2420+ Sym = MCSymbolRefExpr::create (getSymbol (BaseGVB), Ctx);
2421+ if (Offset.sgt (0 ))
2422+ Sym = MCBinaryExpr::createAdd (
2423+ Sym, MCConstantExpr::create (Offset.getSExtValue (), Ctx), Ctx);
2424+ else if (Offset.slt (0 ))
2425+ Sym = MCBinaryExpr::createSub (
2426+ Sym, MCConstantExpr::create ((-Offset).getSExtValue (), Ctx), Ctx);
2427+ } else {
2428+ Sym = MCConstantExpr::create (Offset.getSExtValue (), Ctx);
22792429 }
22802430
2281- // If there is an addend, turn that into the appropriate MCExpr.
2282- const MCExpr *Sym = MCSymbolRefExpr::create (getSymbol (BaseGVB), Ctx);
2283- if (Offset.sgt (0 ))
2284- Sym = MCBinaryExpr::createAdd (
2285- Sym, MCConstantExpr::create (Offset.getSExtValue (), Ctx), Ctx);
2286- else if (Offset.slt (0 ))
2287- Sym = MCBinaryExpr::createSub (
2288- Sym, MCConstantExpr::create ((-Offset).getSExtValue (), Ctx), Ctx);
2289-
22902431 uint64_t KeyID = CPA.getKey ()->getZExtValue ();
22912432 // We later rely on valid KeyID value in AArch64PACKeyIDToString call from
22922433 // AArch64AuthMCExpr::printImpl, so fail fast.
@@ -2304,6 +2445,12 @@ AArch64AsmPrinter::lowerConstantPtrAuth(const ConstantPtrAuth &CPA) {
23042445 Disc = 0 ;
23052446 }
23062447
2448+ // Check if we need to represent this with an IRELATIVE and emit it if so.
2449+ if (auto *IFuncSym = emitPAuthRelocationAsIRelative (
2450+ Sym, Disc, AArch64PACKey::ID (KeyID), CPA.hasAddressDiscriminator (),
2451+ BaseGVB && BaseGVB->isDSOLocal ()))
2452+ return IFuncSym;
2453+
23072454 // Finally build the complete @AUTH expr.
23082455 return AArch64AuthMCExpr::create (Sym, Disc, AArch64PACKey::ID (KeyID),
23092456 CPA.hasAddressDiscriminator (), Ctx);
0 commit comments