@@ -169,6 +169,11 @@ class AArch64AsmPrinter : public AsmPrinter {
169169 // adrp-add followed by PAC sign)
170170 void LowerMOVaddrPAC (const MachineInstr &MI);
171171
172+ // Emit the sequence for LOADgotAUTH (load signed pointer from signed ELF GOT
173+ // and authenticate it with, if FPAC bit is not set, check+trap sequence after
174+ // authenticating)
175+ void LowerLOADgotAUTH (const MachineInstr &MI);
176+
172177 // / tblgen'erated driver function for lowering simple MI->MC
173178 // / pseudo instructions.
174179 bool lowerPseudoInstExpansion (const MachineInstr *MI, MCInst &Inst);
@@ -873,6 +878,22 @@ void AArch64AsmPrinter::emitEndOfAsmFile(Module &M) {
873878
874879 OutStreamer->addBlankLine ();
875880 }
881+
882+ // With signed ELF GOT enabled, the linker looks at the symbol type to
883+ // choose between keys IA (for STT_FUNC) and DA (for other types). Symbols
884+ // for functions not defined in the module have STT_NOTYPE type by default.
885+ // This makes linker to emit signing schema with DA key (instead of IA) for
886+ // corresponding R_AARCH64_AUTH_GLOB_DAT dynamic reloc. To avoid that, force
887+ // all function symbols used in the module to have STT_FUNC type. See
888+ // https://github.com/ARM-software/abi-aa/blob/main/pauthabielf64/pauthabielf64.rst#default-signing-schema
889+ const auto *PtrAuthELFGOTFlag = mdconst::extract_or_null<ConstantInt>(
890+ M.getModuleFlag (" ptrauth-elf-got" ));
891+ if (PtrAuthELFGOTFlag && PtrAuthELFGOTFlag->getZExtValue () == 1 )
892+ for (const GlobalValue &GV : M.global_values ())
893+ if (!GV.use_empty () && isa<Function>(GV) &&
894+ !GV.getName ().starts_with (" llvm." ))
895+ OutStreamer->emitSymbolAttribute (getSymbol (&GV),
896+ MCSA_ELF_TypeFunction);
876897 }
877898
878899 // Emit stack and fault map information.
@@ -2068,6 +2089,10 @@ void AArch64AsmPrinter::LowerLOADauthptrstatic(const MachineInstr &MI) {
20682089
20692090void AArch64AsmPrinter::LowerMOVaddrPAC (const MachineInstr &MI) {
20702091 const bool IsGOTLoad = MI.getOpcode () == AArch64::LOADgotPAC;
2092+ const bool IsELFSignedGOT = MI.getParent ()
2093+ ->getParent ()
2094+ ->getInfo <AArch64FunctionInfo>()
2095+ ->hasELFSignedGOT ();
20712096 MachineOperand GAOp = MI.getOperand (0 );
20722097 const uint64_t KeyC = MI.getOperand (1 ).getImm ();
20732098 assert (KeyC <= AArch64PACKey::LAST &&
@@ -2084,9 +2109,17 @@ void AArch64AsmPrinter::LowerMOVaddrPAC(const MachineInstr &MI) {
20842109 // Emit:
20852110 // target materialization:
20862111 // - via GOT:
2087- // adrp x16, :got:target
2088- // ldr x16, [x16, :got_lo12:target]
2089- // add offset to x16 if offset != 0
2112+ // - unsigned GOT:
2113+ // adrp x16, :got:target
2114+ // ldr x16, [x16, :got_lo12:target]
2115+ // add offset to x16 if offset != 0
2116+ // - ELF signed GOT:
2117+ // adrp x17, :got:target
2118+ // add x17, x17, :got_auth_lo12:target
2119+ // ldr x16, [x17]
2120+ // aut{i|d}a x16, x17
2121+ // check+trap sequence (if no FPAC)
2122+ // add offset to x16 if offset != 0
20902123 //
20912124 // - direct:
20922125 // adrp x16, target
@@ -2129,13 +2162,48 @@ void AArch64AsmPrinter::LowerMOVaddrPAC(const MachineInstr &MI) {
21292162 MCInstLowering.lowerOperand (GAMOLo, GAMCLo);
21302163
21312164 EmitToStreamer (
2132- MCInstBuilder (AArch64::ADRP).addReg (AArch64::X16).addOperand (GAMCHi));
2165+ MCInstBuilder (AArch64::ADRP)
2166+ .addReg (IsGOTLoad && IsELFSignedGOT ? AArch64::X17 : AArch64::X16)
2167+ .addOperand (GAMCHi));
21332168
21342169 if (IsGOTLoad) {
2135- EmitToStreamer (MCInstBuilder (AArch64::LDRXui)
2136- .addReg (AArch64::X16)
2137- .addReg (AArch64::X16)
2138- .addOperand (GAMCLo));
2170+ if (IsELFSignedGOT) {
2171+ EmitToStreamer (MCInstBuilder (AArch64::ADDXri)
2172+ .addReg (AArch64::X17)
2173+ .addReg (AArch64::X17)
2174+ .addOperand (GAMCLo)
2175+ .addImm (0 ));
2176+
2177+ EmitToStreamer (MCInstBuilder (AArch64::LDRXui)
2178+ .addReg (AArch64::X16)
2179+ .addReg (AArch64::X17)
2180+ .addImm (0 ));
2181+
2182+ assert (GAOp.isGlobal ());
2183+ assert (GAOp.getGlobal ()->getValueType () != nullptr );
2184+ unsigned AuthOpcode = GAOp.getGlobal ()->getValueType ()->isFunctionTy ()
2185+ ? AArch64::AUTIA
2186+ : AArch64::AUTDA;
2187+
2188+ EmitToStreamer (MCInstBuilder (AuthOpcode)
2189+ .addReg (AArch64::X16)
2190+ .addReg (AArch64::X16)
2191+ .addReg (AArch64::X17));
2192+
2193+ if (!STI->hasFPAC ()) {
2194+ auto AuthKey = (AuthOpcode == AArch64::AUTIA ? AArch64PACKey::IA
2195+ : AArch64PACKey::DA);
2196+
2197+ emitPtrauthCheckAuthenticatedValue (AArch64::X16, AArch64::X17, AuthKey,
2198+ /* ShouldTrap=*/ true ,
2199+ /* OnFailure=*/ nullptr );
2200+ }
2201+ } else {
2202+ EmitToStreamer (MCInstBuilder (AArch64::LDRXui)
2203+ .addReg (AArch64::X16)
2204+ .addReg (AArch64::X16)
2205+ .addOperand (GAMCLo));
2206+ }
21392207 } else {
21402208 EmitToStreamer (MCInstBuilder (AArch64::ADDXri)
21412209 .addReg (AArch64::X16)
@@ -2203,6 +2271,69 @@ void AArch64AsmPrinter::LowerMOVaddrPAC(const MachineInstr &MI) {
22032271 EmitToStreamer (MIB);
22042272}
22052273
2274+ void AArch64AsmPrinter::LowerLOADgotAUTH (const MachineInstr &MI) {
2275+ Register DstReg = MI.getOperand (0 ).getReg ();
2276+ Register AuthResultReg = STI->hasFPAC () ? DstReg : AArch64::X16;
2277+ const MachineOperand &GAMO = MI.getOperand (1 );
2278+ assert (GAMO.getOffset () == 0 );
2279+
2280+ MachineOperand GAHiOp (GAMO);
2281+ MachineOperand GALoOp (GAMO);
2282+ GAHiOp.addTargetFlag (AArch64II::MO_PAGE);
2283+ GALoOp.addTargetFlag (AArch64II::MO_PAGEOFF | AArch64II::MO_NC);
2284+
2285+ MCOperand GAMCHi, GAMCLo;
2286+ MCInstLowering.lowerOperand (GAHiOp, GAMCHi);
2287+ MCInstLowering.lowerOperand (GALoOp, GAMCLo);
2288+
2289+ EmitToStreamer (
2290+ MCInstBuilder (AArch64::ADRP).addReg (AArch64::X17).addOperand (GAMCHi));
2291+
2292+ EmitToStreamer (MCInstBuilder (AArch64::ADDXri)
2293+ .addReg (AArch64::X17)
2294+ .addReg (AArch64::X17)
2295+ .addOperand (GAMCLo)
2296+ .addImm (0 ));
2297+
2298+ EmitToStreamer (MCInstBuilder (AArch64::LDRXui)
2299+ .addReg (AuthResultReg)
2300+ .addReg (AArch64::X17)
2301+ .addImm (0 ));
2302+
2303+ assert (GAMO.isGlobal ());
2304+ MCSymbol *UndefWeakSym;
2305+ if (GAMO.getGlobal ()->hasExternalWeakLinkage ()) {
2306+ UndefWeakSym = createTempSymbol (" undef_weak" );
2307+ EmitToStreamer (
2308+ MCInstBuilder (AArch64::CBZX)
2309+ .addReg (AuthResultReg)
2310+ .addExpr (MCSymbolRefExpr::create (UndefWeakSym, OutContext)));
2311+ }
2312+
2313+ assert (GAMO.getGlobal ()->getValueType () != nullptr );
2314+ unsigned AuthOpcode = GAMO.getGlobal ()->getValueType ()->isFunctionTy ()
2315+ ? AArch64::AUTIA
2316+ : AArch64::AUTDA;
2317+ EmitToStreamer (MCInstBuilder (AuthOpcode)
2318+ .addReg (AuthResultReg)
2319+ .addReg (AuthResultReg)
2320+ .addReg (AArch64::X17));
2321+
2322+ if (GAMO.getGlobal ()->hasExternalWeakLinkage ())
2323+ OutStreamer->emitLabel (UndefWeakSym);
2324+
2325+ if (!STI->hasFPAC ()) {
2326+ auto AuthKey =
2327+ (AuthOpcode == AArch64::AUTIA ? AArch64PACKey::IA : AArch64PACKey::DA);
2328+
2329+ emitPtrauthCheckAuthenticatedValue (AuthResultReg, AArch64::X17, AuthKey,
2330+ /* ShouldTrap=*/ true ,
2331+ /* OnFailure=*/ nullptr );
2332+
2333+ emitMovXReg (DstReg, AuthResultReg);
2334+ }
2335+ }
2336+
22062337const MCExpr *
22072338AArch64AsmPrinter::lowerBlockAddressConstant (const BlockAddress &BA) {
22082339 const MCExpr *BAE = AsmPrinter::lowerBlockAddressConstant (BA);
@@ -2381,6 +2512,10 @@ void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) {
23812512 LowerMOVaddrPAC (*MI);
23822513 return ;
23832514
2515+ case AArch64::LOADgotAUTH:
2516+ LowerLOADgotAUTH (*MI);
2517+ return ;
2518+
23842519 case AArch64::BRA:
23852520 case AArch64::BLRA:
23862521 emitPtrauthBranch (MI);
0 commit comments