@@ -169,6 +169,11 @@ class AArch64AsmPrinter : public AsmPrinter {
169
169
// adrp-add followed by PAC sign)
170
170
void LowerMOVaddrPAC (const MachineInstr &MI);
171
171
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
+
172
177
// / tblgen'erated driver function for lowering simple MI->MC
173
178
// / pseudo instructions.
174
179
bool lowerPseudoInstExpansion (const MachineInstr *MI, MCInst &Inst);
@@ -873,6 +878,22 @@ void AArch64AsmPrinter::emitEndOfAsmFile(Module &M) {
873
878
874
879
OutStreamer->addBlankLine ();
875
880
}
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);
876
897
}
877
898
878
899
// Emit stack and fault map information.
@@ -2068,6 +2089,10 @@ void AArch64AsmPrinter::LowerLOADauthptrstatic(const MachineInstr &MI) {
2068
2089
2069
2090
void AArch64AsmPrinter::LowerMOVaddrPAC (const MachineInstr &MI) {
2070
2091
const bool IsGOTLoad = MI.getOpcode () == AArch64::LOADgotPAC;
2092
+ const bool IsELFSignedGOT = MI.getParent ()
2093
+ ->getParent ()
2094
+ ->getInfo <AArch64FunctionInfo>()
2095
+ ->hasELFSignedGOT ();
2071
2096
MachineOperand GAOp = MI.getOperand (0 );
2072
2097
const uint64_t KeyC = MI.getOperand (1 ).getImm ();
2073
2098
assert (KeyC <= AArch64PACKey::LAST &&
@@ -2084,9 +2109,17 @@ void AArch64AsmPrinter::LowerMOVaddrPAC(const MachineInstr &MI) {
2084
2109
// Emit:
2085
2110
// target materialization:
2086
2111
// - 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
2090
2123
//
2091
2124
// - direct:
2092
2125
// adrp x16, target
@@ -2129,13 +2162,79 @@ void AArch64AsmPrinter::LowerMOVaddrPAC(const MachineInstr &MI) {
2129
2162
MCInstLowering.lowerOperand (GAMOLo, GAMCLo);
2130
2163
2131
2164
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));
2133
2168
2134
2169
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
+ }
2139
2238
} else {
2140
2239
EmitToStreamer (MCInstBuilder (AArch64::ADDXri)
2141
2240
.addReg (AArch64::X16)
@@ -2203,6 +2302,45 @@ void AArch64AsmPrinter::LowerMOVaddrPAC(const MachineInstr &MI) {
2203
2302
EmitToStreamer (MIB);
2204
2303
}
2205
2304
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
+
2206
2344
const MCExpr *
2207
2345
AArch64AsmPrinter::lowerBlockAddressConstant (const BlockAddress &BA) {
2208
2346
const MCExpr *BAE = AsmPrinter::lowerBlockAddressConstant (BA);
@@ -2381,6 +2519,10 @@ void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) {
2381
2519
LowerMOVaddrPAC (*MI);
2382
2520
return ;
2383
2521
2522
+ case AArch64::LOADgotAUTH:
2523
+ LowerLOADgotAUTH (*MI);
2524
+ return ;
2525
+
2384
2526
case AArch64::BRA:
2385
2527
case AArch64::BLRA:
2386
2528
emitPtrauthBranch (MI);
0 commit comments