5454#include " llvm/MC/MCSectionMachO.h"
5555#include " llvm/MC/MCStreamer.h"
5656#include " llvm/MC/MCSymbol.h"
57+ #include " llvm/MC/MCValue.h"
5758#include " llvm/MC/TargetRegistry.h"
5859#include " llvm/Support/Casting.h"
5960#include " llvm/Support/CommandLine.h"
@@ -84,6 +85,7 @@ class AArch64AsmPrinter : public AsmPrinter {
8485 bool EnableImportCallOptimization = false ;
8586 DenseMap<MCSection *, std::vector<std::pair<MCSymbol *, MCSymbol *>>>
8687 SectionToImportedFunctionCalls;
88+ unsigned PAuthIFuncNextUniqueID = 1 ;
8789
8890public:
8991 AArch64AsmPrinter (TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer)
@@ -191,6 +193,10 @@ class AArch64AsmPrinter : public AsmPrinter {
191193 // authenticating)
192194 void LowerLOADgotAUTH (const MachineInstr &MI);
193195
196+ const MCExpr *emitPAuthRelocationAsIRelative (
197+ const MCExpr *Target, uint16_t Disc, AArch64PACKey::ID KeyID,
198+ bool HasAddressDiversity, bool IsDSOLocal);
199+
194200 // / tblgen'erated driver function for lowering simple MI->MC
195201 // / pseudo instructions.
196202 bool lowerPseudoInstExpansion (const MachineInstr *MI, MCInst &Inst);
@@ -2218,6 +2224,145 @@ void AArch64AsmPrinter::emitPtrauthBranch(const MachineInstr *MI) {
22182224 EmitToStreamer (*OutStreamer, BRInst);
22192225}
22202226
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+
22212366const MCExpr *
22222367AArch64AsmPrinter::lowerConstantPtrAuth (const ConstantPtrAuth &CPA) {
22232368 MCContext &Ctx = OutContext;
@@ -2229,23 +2374,20 @@ AArch64AsmPrinter::lowerConstantPtrAuth(const ConstantPtrAuth &CPA) {
22292374
22302375 auto *BaseGVB = dyn_cast<GlobalValue>(BaseGV);
22312376
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);
22382389 }
22392390
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-
22492391 uint64_t KeyID = CPA.getKey ()->getZExtValue ();
22502392 // We later rely on valid KeyID value in AArch64PACKeyIDToString call from
22512393 // AArch64AuthMCExpr::printImpl, so fail fast.
@@ -2259,6 +2401,12 @@ AArch64AsmPrinter::lowerConstantPtrAuth(const ConstantPtrAuth &CPA) {
22592401 report_fatal_error (" AArch64 PAC Discriminator '" + Twine (Disc) +
22602402 " ' out of range [0, 0xFFFF]" );
22612403
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+
22622410 // Finally build the complete @AUTH expr.
22632411 return AArch64AuthMCExpr::create (Sym, Disc, AArch64PACKey::ID (KeyID),
22642412 CPA.hasAddressDiscriminator (), Ctx);
0 commit comments