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;
@@ -211,6 +214,12 @@ class AArch64AsmPrinter : public AsmPrinter {
211214 // authenticating)
212215 void LowerLOADgotAUTH (const MachineInstr &MI);
213216
217+ const MCExpr *emitPAuthRelocationAsIRelative (const MCExpr *Target,
218+ uint16_t Disc,
219+ AArch64PACKey::ID KeyID,
220+ bool HasAddressDiversity,
221+ bool IsDSOLocal);
222+
214223 // / tblgen'erated driver function for lowering simple MI->MC
215224 // / pseudo instructions.
216225 bool lowerPseudoInstExpansion (const MachineInstr *MI, MCInst &Inst);
@@ -2299,6 +2308,182 @@ void AArch64AsmPrinter::emitPtrauthBranch(const MachineInstr *MI) {
22992308 EmitToStreamer (*OutStreamer, BRInst);
23002309}
23012310
2311+ static void emitAddress (MCStreamer &Streamer, MCRegister Reg,
2312+ const MCExpr *Expr, bool DSOLocal,
2313+ const MCSubtargetInfo &STI) {
2314+ MCValue Val;
2315+ if (!Expr->evaluateAsRelocatable (Val, nullptr ))
2316+ report_fatal_error (" emitAddress could not evaluate" );
2317+ if (DSOLocal) {
2318+ Streamer.emitInstruction (
2319+ MCInstBuilder (AArch64::ADRP)
2320+ .addReg (Reg)
2321+ .addExpr (MCSpecifierExpr::create (Expr, AArch64::S_ABS_PAGE,
2322+ Streamer.getContext ())),
2323+ STI);
2324+ Streamer.emitInstruction (
2325+ MCInstBuilder (AArch64::ADDXri)
2326+ .addReg (Reg)
2327+ .addReg (Reg)
2328+ .addExpr (MCSpecifierExpr::create (Expr, AArch64::S_LO12,
2329+ Streamer.getContext ()))
2330+ .addImm (0 ),
2331+ STI);
2332+ } else {
2333+ auto *SymRef =
2334+ MCSymbolRefExpr::create (Val.getAddSym (), Streamer.getContext ());
2335+ Streamer.emitInstruction (
2336+ MCInstBuilder (AArch64::ADRP)
2337+ .addReg (Reg)
2338+ .addExpr (MCSpecifierExpr::create (SymRef, AArch64::S_GOT_PAGE,
2339+ Streamer.getContext ())),
2340+ STI);
2341+ Streamer.emitInstruction (
2342+ MCInstBuilder (AArch64::LDRXui)
2343+ .addReg (Reg)
2344+ .addReg (Reg)
2345+ .addExpr (MCSpecifierExpr::create (SymRef, AArch64::S_GOT_LO12,
2346+ Streamer.getContext ())),
2347+ STI);
2348+ if (Val.getConstant ())
2349+ Streamer.emitInstruction (MCInstBuilder (AArch64::ADDXri)
2350+ .addReg (Reg)
2351+ .addReg (Reg)
2352+ .addImm (Val.getConstant ())
2353+ .addImm (0 ),
2354+ STI);
2355+ }
2356+ }
2357+
2358+ static bool targetSupportsPAuthRelocation (const Triple &TT,
2359+ const MCExpr *Target) {
2360+ // No released version of glibc supports PAuth relocations.
2361+ if (TT.isOSGlibc ())
2362+ return false ;
2363+
2364+ // We emit PAuth constants as IRELATIVE relocations in cases where the
2365+ // constant cannot be represented as a PAuth relocation:
2366+ // 1) The signed value is not a symbol.
2367+ return !isa<MCConstantExpr>(Target);
2368+ }
2369+
2370+ static bool targetSupportsIRelativeRelocation (const Triple &TT) {
2371+ // IFUNCs are ELF-only.
2372+ if (!TT.isOSBinFormatELF ())
2373+ return false ;
2374+
2375+ // musl doesn't support IFUNCs.
2376+ if (TT.isMusl ())
2377+ return false ;
2378+
2379+ return true ;
2380+ }
2381+
2382+ // Emit an ifunc resolver that returns a signed pointer to the specified target,
2383+ // and return a FUNCINIT reference to the resolver. In the linked binary, this
2384+ // function becomes the target of an IRELATIVE relocation. This resolver is used
2385+ // to relocate signed pointers in global variable initializers in special cases
2386+ // where the standard R_AARCH64_AUTH_ABS64 relocation would not work.
2387+ //
2388+ // Example (signed null pointer, not address discriminated):
2389+ //
2390+ // .8byte .Lpauth_ifunc0
2391+ // .pushsection .text.startup,"ax",@progbits
2392+ // .Lpauth_ifunc0:
2393+ // mov x0, #0
2394+ // mov x1, #12345
2395+ // b __emupac_pacda
2396+ //
2397+ // Example (signed null pointer, address discriminated):
2398+ //
2399+ // .Ltmp:
2400+ // .8byte .Lpauth_ifunc0
2401+ // .pushsection .text.startup,"ax",@progbits
2402+ // .Lpauth_ifunc0:
2403+ // mov x0, #0
2404+ // adrp x1, .Ltmp
2405+ // add x1, x1, :lo12:.Ltmp
2406+ // b __emupac_pacda
2407+ // .popsection
2408+ //
2409+ // Example (signed pointer to symbol, not address discriminated):
2410+ //
2411+ // .Ltmp:
2412+ // .8byte .Lpauth_ifunc0
2413+ // .pushsection .text.startup,"ax",@progbits
2414+ // .Lpauth_ifunc0:
2415+ // adrp x0, symbol
2416+ // add x0, x0, :lo12:symbol
2417+ // mov x1, #12345
2418+ // b __emupac_pacda
2419+ // .popsection
2420+ const MCExpr *AArch64AsmPrinter::emitPAuthRelocationAsIRelative (
2421+ const MCExpr *Target, uint16_t Disc, AArch64PACKey::ID KeyID,
2422+ bool HasAddressDiversity, bool IsDSOLocal) {
2423+ const Triple &TT = TM.getTargetTriple ();
2424+
2425+ // We only emit an IRELATIVE relocation if the target supports IRELATIVE and
2426+ // does not support the kind of PAuth relocation that we are trying to emit.
2427+ if (targetSupportsPAuthRelocation (TT, Target) ||
2428+ !targetSupportsIRelativeRelocation (TT))
2429+ return nullptr ;
2430+
2431+ // For now, only the DA key is supported.
2432+ if (KeyID != AArch64PACKey::DA)
2433+ return nullptr ;
2434+
2435+ std::unique_ptr<MCSubtargetInfo> STI (
2436+ TM.getTarget ().createMCSubtargetInfo (TT, " " , " " ));
2437+ assert (STI && " Unable to create subtarget info" );
2438+
2439+ MCSymbol *Place = OutStreamer->getContext ().createTempSymbol ();
2440+ OutStreamer->emitLabel (Place);
2441+ OutStreamer->pushSection ();
2442+
2443+ OutStreamer->switchSection (OutStreamer->getContext ().getELFSection (
2444+ " .text.startup" , ELF::SHT_PROGBITS, ELF::SHF_ALLOC | ELF::SHF_EXECINSTR,
2445+ 0 , " " , true , PAuthIFuncNextUniqueID++, nullptr ));
2446+
2447+ MCSymbol *IRelativeSym =
2448+ OutStreamer->getContext ().createLinkerPrivateSymbol (" pauth_ifunc" );
2449+ OutStreamer->emitLabel (IRelativeSym);
2450+ if (isa<MCConstantExpr>(Target)) {
2451+ OutStreamer->emitInstruction (MCInstBuilder (AArch64::MOVZXi)
2452+ .addReg (AArch64::X0)
2453+ .addExpr (Target)
2454+ .addImm (0 ),
2455+ *STI);
2456+ } else {
2457+ emitAddress (*OutStreamer, AArch64::X0, Target, IsDSOLocal, *STI);
2458+ }
2459+ if (HasAddressDiversity) {
2460+ auto *PlacePlusDisc = MCBinaryExpr::createAdd (
2461+ MCSymbolRefExpr::create (Place, OutStreamer->getContext ()),
2462+ MCConstantExpr::create (static_cast <int16_t >(Disc),
2463+ OutStreamer->getContext ()),
2464+ OutStreamer->getContext ());
2465+ emitAddress (*OutStreamer, AArch64::X1, PlacePlusDisc, /* IsDSOLocal=*/ true ,
2466+ *STI);
2467+ } else {
2468+ emitMOVZ (AArch64::X1, Disc, 0 );
2469+ }
2470+
2471+ // We don't know the subtarget because this is being emitted for a global
2472+ // initializer. Because the performance of IFUNC resolvers is unimportant, we
2473+ // always call the EmuPAC runtime, which will end up using the PAC instruction
2474+ // if the target supports PAC.
2475+ MCSymbol *EmuPAC =
2476+ OutStreamer->getContext ().getOrCreateSymbol (" __emupac_pacda" );
2477+ const MCSymbolRefExpr *EmuPACRef =
2478+ MCSymbolRefExpr::create (EmuPAC, OutStreamer->getContext ());
2479+ OutStreamer->emitInstruction (MCInstBuilder (AArch64::B).addExpr (EmuPACRef),
2480+ *STI);
2481+ OutStreamer->popSection ();
2482+
2483+ return MCSymbolRefExpr::create (IRelativeSym, AArch64::S_FUNCINIT,
2484+ OutStreamer->getContext ());
2485+ }
2486+
23022487const MCExpr *
23032488AArch64AsmPrinter::lowerConstantPtrAuth (const ConstantPtrAuth &CPA) {
23042489 MCContext &Ctx = OutContext;
@@ -2310,23 +2495,20 @@ AArch64AsmPrinter::lowerConstantPtrAuth(const ConstantPtrAuth &CPA) {
23102495
23112496 auto *BaseGVB = dyn_cast<GlobalValue>(BaseGV);
23122497
2313- // If we can't understand the referenced ConstantExpr, there's nothing
2314- // else we can do: emit an error.
2315- if (!BaseGVB) {
2316- BaseGV->getContext ().emitError (
2317- " cannot resolve target base/addend of ptrauth constant" );
2318- return nullptr ;
2498+ const MCExpr *Sym;
2499+ if (BaseGVB) {
2500+ // If there is an addend, turn that into the appropriate MCExpr.
2501+ Sym = MCSymbolRefExpr::create (getSymbol (BaseGVB), Ctx);
2502+ if (Offset.sgt (0 ))
2503+ Sym = MCBinaryExpr::createAdd (
2504+ Sym, MCConstantExpr::create (Offset.getSExtValue (), Ctx), Ctx);
2505+ else if (Offset.slt (0 ))
2506+ Sym = MCBinaryExpr::createSub (
2507+ Sym, MCConstantExpr::create ((-Offset).getSExtValue (), Ctx), Ctx);
2508+ } else {
2509+ Sym = MCConstantExpr::create (Offset.getSExtValue (), Ctx);
23192510 }
23202511
2321- // If there is an addend, turn that into the appropriate MCExpr.
2322- const MCExpr *Sym = MCSymbolRefExpr::create (getSymbol (BaseGVB), Ctx);
2323- if (Offset.sgt (0 ))
2324- Sym = MCBinaryExpr::createAdd (
2325- Sym, MCConstantExpr::create (Offset.getSExtValue (), Ctx), Ctx);
2326- else if (Offset.slt (0 ))
2327- Sym = MCBinaryExpr::createSub (
2328- Sym, MCConstantExpr::create ((-Offset).getSExtValue (), Ctx), Ctx);
2329-
23302512 uint64_t KeyID = CPA.getKey ()->getZExtValue ();
23312513 // We later rely on valid KeyID value in AArch64PACKeyIDToString call from
23322514 // AArch64AuthMCExpr::printImpl, so fail fast.
@@ -2344,6 +2526,12 @@ AArch64AsmPrinter::lowerConstantPtrAuth(const ConstantPtrAuth &CPA) {
23442526 Disc = 0 ;
23452527 }
23462528
2529+ // Check if we need to represent this with an IRELATIVE and emit it if so.
2530+ if (auto *IFuncSym = emitPAuthRelocationAsIRelative (
2531+ Sym, Disc, AArch64PACKey::ID (KeyID), CPA.hasAddressDiscriminator (),
2532+ BaseGVB && BaseGVB->isDSOLocal ()))
2533+ return IFuncSym;
2534+
23472535 // Finally build the complete @AUTH expr.
23482536 return AArch64AuthMCExpr::create (Sym, Disc, AArch64PACKey::ID (KeyID),
23492537 CPA.hasAddressDiscriminator (), Ctx);
0 commit comments