@@ -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,79 @@ 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+ unsigned XPACOpc = getXPACOpcodeForKey (AuthKey);
2197+ MCSymbol *SuccessSym = createTempSymbol (" auth_success_" );
2198+
2199+ // XPAC has tied src/dst: use x17 as a temporary copy.
2200+ // mov x17, x16
2201+ EmitToStreamer (MCInstBuilder (AArch64::ORRXrs)
2202+ .addReg (AArch64::X17)
2203+ .addReg (AArch64::XZR)
2204+ .addReg (AArch64::X16)
2205+ .addImm (0 ));
2206+
2207+ // xpaci x17
2208+ EmitToStreamer (
2209+ MCInstBuilder (XPACOpc).addReg (AArch64::X17).addReg (AArch64::X17));
2210+
2211+ // cmp x16, x17
2212+ EmitToStreamer (MCInstBuilder (AArch64::SUBSXrs)
2213+ .addReg (AArch64::XZR)
2214+ .addReg (AArch64::X16)
2215+ .addReg (AArch64::X17)
2216+ .addImm (0 ));
2217+
2218+ // b.eq Lsuccess
2219+ EmitToStreamer (
2220+ MCInstBuilder (AArch64::Bcc)
2221+ .addImm (AArch64CC::EQ)
2222+ .addExpr (MCSymbolRefExpr::create (SuccessSym, OutContext)));
2223+
2224+ // Trapping sequences do a 'brk'.
2225+ // brk #<0xc470 + aut key>
2226+ EmitToStreamer (MCInstBuilder (AArch64::BRK).addImm (0xc470 | AuthKey));
2227+
2228+ // If the auth check succeeds, we can continue.
2229+ // Lsuccess:
2230+ OutStreamer->emitLabel (SuccessSym);
2231+ }
2232+ } else {
2233+ EmitToStreamer (MCInstBuilder (AArch64::LDRXui)
2234+ .addReg (AArch64::X16)
2235+ .addReg (AArch64::X16)
2236+ .addOperand (GAMCLo));
2237+ }
21392238 } else {
21402239 EmitToStreamer (MCInstBuilder (AArch64::ADDXri)
21412240 .addReg (AArch64::X16)
@@ -2203,6 +2302,45 @@ void AArch64AsmPrinter::LowerMOVaddrPAC(const MachineInstr &MI) {
22032302 EmitToStreamer (MIB);
22042303}
22052304
2305+ void AArch64AsmPrinter::LowerLOADgotAUTH (const MachineInstr &MI) {
2306+ Register DstReg = MI.getOperand (0 ).getReg ();
2307+ const MachineOperand &GAMO = MI.getOperand (1 );
2308+ assert (GAMO.getOffset () == 0 );
2309+
2310+ MachineOperand GAHiOp (GAMO);
2311+ MachineOperand GALoOp (GAMO);
2312+ GAHiOp.addTargetFlag (AArch64II::MO_PAGE);
2313+ GALoOp.addTargetFlag (AArch64II::MO_PAGEOFF | AArch64II::MO_NC);
2314+
2315+ MCOperand GAMCHi, GAMCLo;
2316+ MCInstLowering.lowerOperand (GAHiOp, GAMCHi);
2317+ MCInstLowering.lowerOperand (GALoOp, GAMCLo);
2318+
2319+ EmitToStreamer (
2320+ MCInstBuilder (AArch64::ADRP).addReg (AArch64::X16).addOperand (GAMCHi));
2321+
2322+ EmitToStreamer (MCInstBuilder (AArch64::ADDXri)
2323+ .addReg (AArch64::X16)
2324+ .addReg (AArch64::X16)
2325+ .addOperand (GAMCLo)
2326+ .addImm (0 ));
2327+
2328+ EmitToStreamer (MCInstBuilder (AArch64::LDRXui)
2329+ .addReg (DstReg)
2330+ .addReg (AArch64::X16)
2331+ .addImm (0 ));
2332+
2333+ assert (GAMO.isGlobal ());
2334+ assert (GAMO.getGlobal ()->getValueType () != nullptr );
2335+ unsigned AuthOpcode = GAMO.getGlobal ()->getValueType ()->isFunctionTy ()
2336+ ? AArch64::AUTIA
2337+ : AArch64::AUTDA;
2338+ EmitToStreamer (MCInstBuilder (AuthOpcode)
2339+ .addReg (DstReg)
2340+ .addReg (DstReg)
2341+ .addReg (AArch64::X16));
2342+ }
2343+
22062344const MCExpr *
22072345AArch64AsmPrinter::lowerBlockAddressConstant (const BlockAddress &BA) {
22082346 const MCExpr *BAE = AsmPrinter::lowerBlockAddressConstant (BA);
@@ -2381,6 +2519,10 @@ void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) {
23812519 LowerMOVaddrPAC (*MI);
23822520 return ;
23832521
2522+ case AArch64::LOADgotAUTH:
2523+ LowerLOADgotAUTH (*MI);
2524+ return ;
2525+
23842526 case AArch64::BRA:
23852527 case AArch64::BLRA:
23862528 emitPtrauthBranch (MI);
0 commit comments