-
Notifications
You must be signed in to change notification settings - Fork 12.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[AArch64][Libunwind] Add Support for FEAT_PAuthLR DWARF Instruction #112171
Conversation
@llvm/pr-subscribers-backend-aarch64 @llvm/pr-subscribers-mc Author: Jack Styles (Stylie777) ChangesAs part of FEAT_PAuthLR, a new DWARF Frame Instruction was introduced,
For the ABI information, see here: https://github.com/ARM-software/abi-aa/blob/853286c7ab66048e4b819682ce17f567b77a0291/aadwarf64/aadwarf64.rst#id23 Patch is 78.23 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/112171.diff 34 Files Affected:
diff --git a/libunwind/src/DwarfInstructions.hpp b/libunwind/src/DwarfInstructions.hpp
index bd9ece60ee5881..e7c467de80adb6 100644
--- a/libunwind/src/DwarfInstructions.hpp
+++ b/libunwind/src/DwarfInstructions.hpp
@@ -74,8 +74,10 @@ class DwarfInstructions {
__builtin_unreachable();
}
#if defined(_LIBUNWIND_TARGET_AARCH64)
- static bool getRA_SIGN_STATE(A &addressSpace, R registers, pint_t cfa,
- PrologInfo &prolog);
+ static bool isReturnAddressSigned(A &addressSpace, R registers, pint_t cfa,
+ PrologInfo &prolog);
+ static bool isReturnAddressSignedWithPC(A &addressSpace, R registers,
+ pint_t cfa, PrologInfo &prolog);
#endif
};
@@ -173,8 +175,9 @@ v128 DwarfInstructions<A, R>::getSavedVectorRegister(
}
#if defined(_LIBUNWIND_TARGET_AARCH64)
template <typename A, typename R>
-bool DwarfInstructions<A, R>::getRA_SIGN_STATE(A &addressSpace, R registers,
- pint_t cfa, PrologInfo &prolog) {
+bool DwarfInstructions<A, R>::isReturnAddressSigned(A &addressSpace,
+ R registers, pint_t cfa,
+ PrologInfo &prolog) {
pint_t raSignState;
auto regloc = prolog.savedRegisters[UNW_AARCH64_RA_SIGN_STATE];
if (regloc.location == CFI_Parser<A>::kRegisterUnused)
@@ -185,6 +188,22 @@ bool DwarfInstructions<A, R>::getRA_SIGN_STATE(A &addressSpace, R registers,
// Only bit[0] is meaningful.
return raSignState & 0x01;
}
+
+template <typename A, typename R>
+bool DwarfInstructions<A, R>::isReturnAddressSignedWithPC(A &addressSpace,
+ R registers,
+ pint_t cfa,
+ PrologInfo &prolog) {
+ pint_t raSignState;
+ auto regloc = prolog.savedRegisters[UNW_AARCH64_RA_SIGN_STATE];
+ if (regloc.location == CFI_Parser<A>::kRegisterUnused)
+ raSignState = static_cast<pint_t>(regloc.value);
+ else
+ raSignState = getSavedRegister(addressSpace, registers, cfa, regloc);
+
+ // Only bit[1] is meaningful.
+ return raSignState & 0x02;
+}
#endif
template <typename A, typename R>
@@ -288,7 +307,7 @@ int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc,
// restored. autia1716 is used instead of autia as autia1716 assembles
// to a NOP on pre-v8.3a architectures.
if ((R::getArch() == REGISTERS_ARM64) &&
- getRA_SIGN_STATE(addressSpace, registers, cfa, prolog) &&
+ isReturnAddressSigned(addressSpace, registers, cfa, prolog) &&
returnAddress != 0) {
#if !defined(_LIBUNWIND_IS_NATIVE_ONLY)
return UNW_ECROSSRASIGNING;
@@ -296,13 +315,24 @@ int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc,
register unsigned long long x17 __asm("x17") = returnAddress;
register unsigned long long x16 __asm("x16") = cfa;
- // These are the autia1716/autib1716 instructions. The hint instructions
- // are used here as gcc does not assemble autia1716/autib1716 for pre
- // armv8.3a targets.
- if (cieInfo.addressesSignedWithBKey)
- asm("hint 0xe" : "+r"(x17) : "r"(x16)); // autib1716
- else
- asm("hint 0xc" : "+r"(x17) : "r"(x16)); // autia1716
+ // We use the hint versions of the authentication instructions below to
+ // ensure they're assembled by the compiler even for targets with no
+ // FEAT_PAuth/FEAT_PAuth_LR support.
+ if(isReturnAddressSignedWithPC(addressSpace, registers, cfa, prolog)) {
+ register unsigned long long x15 __asm("x15") = prolog.ptrAuthDiversifier;
+ if(cieInfo.addressesSignedWithBKey) {
+ asm("hint 0x27\n\t" // pacm
+ "hint 0xe" : "+r"(x17) : "r"(x16), "r"(x15)); // autib1716
+ } else {
+ asm("hint 0x27\n\t" // pacm
+ "hint 0xc" : "+r"(x17) : "r"(x16), "r"(x15)); // autia1716
+ }
+ } else {
+ if (cieInfo.addressesSignedWithBKey)
+ asm("hint 0xe" : "+r"(x17) : "r"(x16)); // autib1716
+ else
+ asm("hint 0xc" : "+r"(x17) : "r"(x16)); // autia1716
+ }
returnAddress = x17;
#endif
}
diff --git a/libunwind/src/DwarfParser.hpp b/libunwind/src/DwarfParser.hpp
index 0682942ce13799..b104d773ed4440 100644
--- a/libunwind/src/DwarfParser.hpp
+++ b/libunwind/src/DwarfParser.hpp
@@ -91,6 +91,9 @@ class CFI_Parser {
int64_t cfaExpression; // CFA = expression
uint32_t spExtraArgSize;
RegisterLocation savedRegisters[kMaxRegisterNumber + 1];
+ #if defined(_LIBUNWIND_TARGET_AARCH64)
+ pint_t ptrAuthDiversifier;
+ #endif
enum class InitializeTime { kLazy, kNormal };
// When saving registers, this data structure is lazily initialized.
@@ -799,6 +802,23 @@ bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace,
}
break;
+#if defined(_LIBUNWIND_TARGET_AARCH64)
+ case DW_CFA_AARCH64_negate_ra_state_with_pc: {
+ int64_t value =
+ results->savedRegisters[UNW_AARCH64_RA_SIGN_STATE].value ^ 0x3;
+ results->setRegisterValue(UNW_AARCH64_RA_SIGN_STATE, value,
+ initialState);
+ // When calucating the value of the PC, it is assumed that the CFI instruction
+ // is placed before the signing instruction, however it is placed after. Because
+ // of this, we need to take into account the CFI instruction is one instruction
+ // call later than expected, and reduce the PC value by 4 bytes to compensate.
+ results->ptrAuthDiversifier = fdeInfo.pcStart + codeOffset - 0x4;
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_AARCH64_negate_ra_state_with_pc(pc=0x%" PRIx64 ")\n",
+ static_cast<uint64_t>(results->ptrAuthDiversifier));
+ }
+ break;
+#endif
+
#else
(void)arch;
#endif
diff --git a/libunwind/src/dwarf2.h b/libunwind/src/dwarf2.h
index 174277d5a79508..2ad3d3c464e80d 100644
--- a/libunwind/src/dwarf2.h
+++ b/libunwind/src/dwarf2.h
@@ -51,7 +51,8 @@ enum {
DW_CFA_GNU_negative_offset_extended = 0x2F,
// AARCH64 extensions
- DW_CFA_AARCH64_negate_ra_state = 0x2D
+ DW_CFA_AARCH64_negate_ra_state_with_pc = 0x2C,
+ DW_CFA_AARCH64_negate_ra_state = 0x2D
};
diff --git a/llvm/include/llvm/BinaryFormat/Dwarf.def b/llvm/include/llvm/BinaryFormat/Dwarf.def
index d55947fc5103ac..9336f2a454ae47 100644
--- a/llvm/include/llvm/BinaryFormat/Dwarf.def
+++ b/llvm/include/llvm/BinaryFormat/Dwarf.def
@@ -1238,6 +1238,7 @@ HANDLE_DW_CFA(0x16, val_expression)
// Vendor extensions:
HANDLE_DW_CFA_PRED(0x1d, MIPS_advance_loc8, SELECT_MIPS64)
HANDLE_DW_CFA_PRED(0x2d, GNU_window_save, SELECT_SPARC)
+HANDLE_DW_CFA_PRED(0x2c, AARCH64_negate_ra_state_with_pc, SELECT_AARCH64)
HANDLE_DW_CFA_PRED(0x2d, AARCH64_negate_ra_state, SELECT_AARCH64)
HANDLE_DW_CFA_PRED(0x2e, GNU_args_size, SELECT_X86)
// Heterogeneous Debugging Extension defined at
diff --git a/llvm/include/llvm/MC/MCDwarf.h b/llvm/include/llvm/MC/MCDwarf.h
index bea79545d1ab96..2ceea906ea57a7 100644
--- a/llvm/include/llvm/MC/MCDwarf.h
+++ b/llvm/include/llvm/MC/MCDwarf.h
@@ -515,6 +515,7 @@ class MCCFIInstruction {
OpRegister,
OpWindowSave,
OpNegateRAState,
+ OpNegateRAStateWithPC,
OpGnuArgsSize,
OpLabel,
};
@@ -642,6 +643,13 @@ class MCCFIInstruction {
return MCCFIInstruction(OpNegateRAState, L, 0, INT64_C(0), Loc);
}
+ /// .cfi_negate_ra_state_with_pc AArch64 negate RA state with PC.
+ static MCCFIInstruction createNegateRAStateWithPC(MCSymbol *L,
+ SMLoc Loc = {}) {
+ return MCCFIInstruction(OpNegateRAStateWithPC, L, 0, INT64_C(0), Loc);
+ }
+
+
/// .cfi_restore says that the rule for Register is now the same as it
/// was at the beginning of the function, after all initial instructions added
/// by .cfi_startproc were executed.
diff --git a/llvm/include/llvm/MC/MCStreamer.h b/llvm/include/llvm/MC/MCStreamer.h
index 707aecc5dc578e..a376ba810ba515 100644
--- a/llvm/include/llvm/MC/MCStreamer.h
+++ b/llvm/include/llvm/MC/MCStreamer.h
@@ -1022,6 +1022,7 @@ class MCStreamer {
SMLoc Loc = {});
virtual void emitCFIWindowSave(SMLoc Loc = {});
virtual void emitCFINegateRAState(SMLoc Loc = {});
+ virtual void emitCFINegateRAStateWithPC(SMLoc Loc = {});
virtual void emitCFILabelDirective(SMLoc Loc, StringRef Name);
virtual void emitWinCFIStartProc(const MCSymbol *Symbol, SMLoc Loc = SMLoc());
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp
index 21d0d070c247f4..daad82d26da652 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp
@@ -236,6 +236,9 @@ void AsmPrinter::emitCFIInstruction(const MCCFIInstruction &Inst) const {
case MCCFIInstruction::OpNegateRAState:
OutStreamer->emitCFINegateRAState(Loc);
break;
+ case MCCFIInstruction::OpNegateRAStateWithPC:
+ OutStreamer->emitCFINegateRAStateWithPC(Loc);
+ break;
case MCCFIInstruction::OpSameValue:
OutStreamer->emitCFISameValue(Inst.getRegister(), Loc);
break;
diff --git a/llvm/lib/CodeGen/CFIInstrInserter.cpp b/llvm/lib/CodeGen/CFIInstrInserter.cpp
index f5bedc7b8ecdfc..4217ec6a1cca8a 100644
--- a/llvm/lib/CodeGen/CFIInstrInserter.cpp
+++ b/llvm/lib/CodeGen/CFIInstrInserter.cpp
@@ -260,6 +260,7 @@ void CFIInstrInserter::calculateOutgoingCFAInfo(MBBCFAInfo &MBBInfo) {
case MCCFIInstruction::OpEscape:
case MCCFIInstruction::OpWindowSave:
case MCCFIInstruction::OpNegateRAState:
+ case MCCFIInstruction::OpNegateRAStateWithPC:
case MCCFIInstruction::OpGnuArgsSize:
case MCCFIInstruction::OpLabel:
break;
diff --git a/llvm/lib/CodeGen/MIRParser/MILexer.cpp b/llvm/lib/CodeGen/MIRParser/MILexer.cpp
index 0809f88fde56b1..5a3806ce57335a 100644
--- a/llvm/lib/CodeGen/MIRParser/MILexer.cpp
+++ b/llvm/lib/CodeGen/MIRParser/MILexer.cpp
@@ -238,6 +238,8 @@ static MIToken::TokenKind getIdentifierKind(StringRef Identifier) {
.Case("window_save", MIToken::kw_cfi_window_save)
.Case("negate_ra_sign_state",
MIToken::kw_cfi_aarch64_negate_ra_sign_state)
+ .Case("negate_ra_sign_state_with_pc",
+ MIToken::kw_cfi_aarch64_negate_ra_sign_state_with_pc)
.Case("blockaddress", MIToken::kw_blockaddress)
.Case("intrinsic", MIToken::kw_intrinsic)
.Case("target-index", MIToken::kw_target_index)
diff --git a/llvm/lib/CodeGen/MIRParser/MILexer.h b/llvm/lib/CodeGen/MIRParser/MILexer.h
index 22547483a8a86b..3931da3eaae1d3 100644
--- a/llvm/lib/CodeGen/MIRParser/MILexer.h
+++ b/llvm/lib/CodeGen/MIRParser/MILexer.h
@@ -96,6 +96,7 @@ struct MIToken {
kw_cfi_undefined,
kw_cfi_window_save,
kw_cfi_aarch64_negate_ra_sign_state,
+ kw_cfi_aarch64_negate_ra_sign_state_with_pc,
kw_blockaddress,
kw_intrinsic,
kw_target_index,
diff --git a/llvm/lib/CodeGen/MIRParser/MIParser.cpp b/llvm/lib/CodeGen/MIRParser/MIParser.cpp
index 74f38e886a6b97..a00cf0b906d5a0 100644
--- a/llvm/lib/CodeGen/MIRParser/MIParser.cpp
+++ b/llvm/lib/CodeGen/MIRParser/MIParser.cpp
@@ -2565,6 +2565,10 @@ bool MIParser::parseCFIOperand(MachineOperand &Dest) {
case MIToken::kw_cfi_aarch64_negate_ra_sign_state:
CFIIndex = MF.addFrameInst(MCCFIInstruction::createNegateRAState(nullptr));
break;
+ case MIToken::kw_cfi_aarch64_negate_ra_sign_state_with_pc:
+ CFIIndex =
+ MF.addFrameInst(MCCFIInstruction::createNegateRAStateWithPC(nullptr));
+ break;
case MIToken::kw_cfi_escape: {
std::string Values;
if (parseCFIEscapeValues(Values))
@@ -2920,6 +2924,7 @@ bool MIParser::parseMachineOperand(const unsigned OpCode, const unsigned OpIdx,
case MIToken::kw_cfi_undefined:
case MIToken::kw_cfi_window_save:
case MIToken::kw_cfi_aarch64_negate_ra_sign_state:
+ case MIToken::kw_cfi_aarch64_negate_ra_sign_state_with_pc:
return parseCFIOperand(Dest);
case MIToken::kw_blockaddress:
return parseBlockAddressOperand(Dest);
diff --git a/llvm/lib/CodeGen/MachineOperand.cpp b/llvm/lib/CodeGen/MachineOperand.cpp
index 89d32c3f005e00..cd94213da79893 100644
--- a/llvm/lib/CodeGen/MachineOperand.cpp
+++ b/llvm/lib/CodeGen/MachineOperand.cpp
@@ -768,6 +768,10 @@ static void printCFI(raw_ostream &OS, const MCCFIInstruction &CFI,
if (MCSymbol *Label = CFI.getLabel())
MachineOperand::printSymbol(OS, *Label);
break;
+ case MCCFIInstruction::OpNegateRAStateWithPC:
+ OS << "negate_ra_sign_state_with_pc ";
+ if (MCSymbol *Label = CFI.getLabel())
+ MachineOperand::printSymbol(OS, *Label);
default:
// TODO: Print the other CFI Operations.
OS << "<unserializable cfi directive>";
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp
index aff26824dda104..38e264f233e39b 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp
@@ -288,6 +288,7 @@ Error CFIProgram::parse(DWARFDataExtractor Data, uint64_t *Offset,
case DW_CFA_remember_state:
case DW_CFA_restore_state:
case DW_CFA_GNU_window_save:
+ case DW_CFA_AARCH64_negate_ra_state_with_pc:
// No operands
addInstruction(Opcode);
break;
@@ -666,6 +667,28 @@ Error UnwindTable::parseRows(const CFIProgram &CFIP, UnwindRow &Row,
}
break;
+ case dwarf::DW_CFA_AARCH64_negate_ra_state_with_pc: {
+ constexpr uint32_t AArch64DWARFPAuthRaState = 34;
+ auto LRLoc = Row.getRegisterLocations().getRegisterLocation(
+ AArch64DWARFPAuthRaState);
+ if (LRLoc) {
+ if (LRLoc->getLocation() == UnwindLocation::Constant) {
+ // Toggle the constant value of bits[1:0] from 0 to 1 or 1 to 0.
+ LRLoc->setConstant(LRLoc->getConstant() ^ 0x3);
+ } else {
+ return createStringError(
+ errc::invalid_argument,
+ "%s encountered when existing rule for this register is not "
+ "a constant",
+ CFIP.callFrameString(Inst.Opcode).str().c_str());
+ }
+ } else {
+ Row.getRegisterLocations().setRegisterLocation(
+ AArch64DWARFPAuthRaState, UnwindLocation::createIsConstant(0x3));
+ }
+ break;
+ }
+
case dwarf::DW_CFA_undefined: {
llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);
if (!RegNum)
@@ -847,6 +870,7 @@ CFIProgram::getOperandTypes() {
DECLARE_OP0(DW_CFA_remember_state);
DECLARE_OP0(DW_CFA_restore_state);
DECLARE_OP0(DW_CFA_GNU_window_save);
+ DECLARE_OP0(DW_CFA_AARCH64_negate_ra_state_with_pc);
DECLARE_OP1(DW_CFA_GNU_args_size, OT_Offset);
DECLARE_OP0(DW_CFA_nop);
diff --git a/llvm/lib/MC/MCAsmStreamer.cpp b/llvm/lib/MC/MCAsmStreamer.cpp
index 31b519a3e5c56a..b9ad0b4eac9c7b 100644
--- a/llvm/lib/MC/MCAsmStreamer.cpp
+++ b/llvm/lib/MC/MCAsmStreamer.cpp
@@ -373,6 +373,7 @@ class MCAsmStreamer final : public MCStreamer {
SMLoc Loc) override;
void emitCFIWindowSave(SMLoc Loc) override;
void emitCFINegateRAState(SMLoc Loc) override;
+ void emitCFINegateRAStateWithPC(SMLoc Loc) override;
void emitCFIReturnColumn(int64_t Register) override;
void emitCFILabelDirective(SMLoc Loc, StringRef Name) override;
@@ -2145,6 +2146,12 @@ void MCAsmStreamer::emitCFINegateRAState(SMLoc Loc) {
EmitEOL();
}
+void MCAsmStreamer::emitCFINegateRAStateWithPC(SMLoc Loc) {
+ MCStreamer::emitCFINegateRAStateWithPC(Loc);
+ OS << "\t.cfi_negate_ra_state_with_pc";
+ EmitEOL();
+}
+
void MCAsmStreamer::emitCFIReturnColumn(int64_t Register) {
MCStreamer::emitCFIReturnColumn(Register);
OS << "\t.cfi_return_column ";
diff --git a/llvm/lib/MC/MCDwarf.cpp b/llvm/lib/MC/MCDwarf.cpp
index 8ff097f29aebd1..e058358fb8ad4b 100644
--- a/llvm/lib/MC/MCDwarf.cpp
+++ b/llvm/lib/MC/MCDwarf.cpp
@@ -1381,6 +1381,10 @@ void FrameEmitterImpl::emitCFIInstruction(const MCCFIInstruction &Instr) {
Streamer.emitInt8(dwarf::DW_CFA_AARCH64_negate_ra_state);
return;
+ case MCCFIInstruction::OpNegateRAStateWithPC:
+ Streamer.emitInt8(dwarf::DW_CFA_AARCH64_negate_ra_state_with_pc);
+ return;
+
case MCCFIInstruction::OpUndefined: {
unsigned Reg = Instr.getRegister();
Streamer.emitInt8(dwarf::DW_CFA_undefined);
diff --git a/llvm/lib/MC/MCStreamer.cpp b/llvm/lib/MC/MCStreamer.cpp
index 13b162768578c5..5474db1315f141 100644
--- a/llvm/lib/MC/MCStreamer.cpp
+++ b/llvm/lib/MC/MCStreamer.cpp
@@ -688,6 +688,16 @@ void MCStreamer::emitCFINegateRAState(SMLoc Loc) {
CurFrame->Instructions.push_back(Instruction);
}
+void MCStreamer::emitCFINegateRAStateWithPC(SMLoc Loc) {
+ MCSymbol *Label = emitCFILabel();
+ MCCFIInstruction Instruction =
+ MCCFIInstruction::createNegateRAStateWithPC(Label, Loc);
+ MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo();
+ if (!CurFrame)
+ return;
+ CurFrame->Instructions.push_back(Instruction);
+}
+
void MCStreamer::emitCFIReturnColumn(int64_t Register) {
MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo();
if (!CurFrame)
diff --git a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
index be33331be4e8ff..98293bc7ac30e2 100644
--- a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
@@ -702,7 +702,10 @@ void AArch64FrameLowering::resetCFIToInitialState(
// Flip the RA sign state.
if (MFI.shouldSignReturnAddress(MF)) {
- CFIIndex = MF.addFrameInst(MCCFIInstruction::createNegateRAState(nullptr));
+ auto CFIInst = MFI.branchProtectionPAuthLR()
+ ? MCCFIInstruction::createNegateRAStateWithPC(nullptr)
+ : MCCFIInstruction::createNegateRAState(nullptr);
+ CFIIndex = MF.addFrameInst(CFIInst);
BuildMI(MBB, InsertPt, DL, CFIDesc).addCFIIndex(CFIIndex);
}
diff --git a/llvm/lib/Target/AArch64/AArch64PointerAuth.cpp b/llvm/lib/Target/AArch64/AArch64PointerAuth.cpp
index 92ab4b5c3d251f..c3ad488fb8e4d1 100644
--- a/llvm/lib/Target/AArch64/AArch64PointerAuth.cpp
+++ b/llvm/lib/Target/AArch64/AArch64PointerAuth.cpp
@@ -71,6 +71,18 @@ FunctionPass *llvm::createAArch64PointerAuthPass() {
char AArch64PointerAuth::ID = 0;
+static void emitPACSymOffsetIntoX16(const TargetInstrInfo &TII,
+ MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator I, DebugLoc DL,
+ MCSymbol *PACSym) {
+ BuildMI(MBB, I, DL, TII.get(AArch64::ADRP), AArch64::X16)
+ .addSym(PACSym, AArch64II::MO_PAGE);
+ BuildMI(MBB, I, DL, TII.get(AArch64::ADDXri), AArch64::X16)
+ .addReg(AArch64::X16)
+ .addSym(PACSym, AArch64II::MO_PAGEOFF | AArch64II::MO_NC)
+ .addImm(0);
+}
+
// Where PAuthLR support is not known at compile time, it is supported using
// PACM. PACM is in the hint space so has no effect when PAuthLR is not
// supported by the hardware, but will alter the behaviour of PACI*SP, AUTI*SP
@@ -81,12 +93,10 @@ static void BuildPACM(const AArch64Subtarget &Subtarget, MachineBasicBlock &MBB,
const TargetInstrInfo *TII = Subtarget.getInstrInfo();
auto &MFnI = *MBB.getParent()->getInfo<AArch64FunctionInfo>();
- // ADR X16,<address_of_PACIASP>
+ // Offset to PAC*SP using ADRP + ADD.
if (PACSym) {
assert(Flags == MachineInstr::FrameDestroy);
- BuildMI(MBB, MBBI, DL, TII->get(AArch64::ADR))
- .addReg(AArch64::X16, RegState::Define)
- .addSym(PACSym);
+ emitPACSymOffsetIntoX16(*TII, MBB, MBBI, DL, PACSym);
}
// Only emit PACM if -mbranch-protection has +pc and the target does not
@@ -95,12 +105,31 @@ static void BuildPACM(const AArch64Subtarget &Subtarget, MachineBasicBlock &MBB,
BuildMI(MBB, MBBI, DL, TII->get(AArch64::PACM)).setMIFlag(Flags);
}
+static void emitPACCFI(const AArch64Subtarget &Subtarget,
+ MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
+ ...
[truncated]
|
@llvm/pr-subscribers-libunwind Author: Jack Styles (Stylie777) ChangesAs part of FEAT_PAuthLR, a new DWARF Frame Instruction was introduced,
For the ABI information, see here: https://github.com/ARM-software/abi-aa/blob/853286c7ab66048e4b819682ce17f567b77a0291/aadwarf64/aadwarf64.rst#id23 Patch is 78.23 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/112171.diff 34 Files Affected:
diff --git a/libunwind/src/DwarfInstructions.hpp b/libunwind/src/DwarfInstructions.hpp
index bd9ece60ee5881..e7c467de80adb6 100644
--- a/libunwind/src/DwarfInstructions.hpp
+++ b/libunwind/src/DwarfInstructions.hpp
@@ -74,8 +74,10 @@ class DwarfInstructions {
__builtin_unreachable();
}
#if defined(_LIBUNWIND_TARGET_AARCH64)
- static bool getRA_SIGN_STATE(A &addressSpace, R registers, pint_t cfa,
- PrologInfo &prolog);
+ static bool isReturnAddressSigned(A &addressSpace, R registers, pint_t cfa,
+ PrologInfo &prolog);
+ static bool isReturnAddressSignedWithPC(A &addressSpace, R registers,
+ pint_t cfa, PrologInfo &prolog);
#endif
};
@@ -173,8 +175,9 @@ v128 DwarfInstructions<A, R>::getSavedVectorRegister(
}
#if defined(_LIBUNWIND_TARGET_AARCH64)
template <typename A, typename R>
-bool DwarfInstructions<A, R>::getRA_SIGN_STATE(A &addressSpace, R registers,
- pint_t cfa, PrologInfo &prolog) {
+bool DwarfInstructions<A, R>::isReturnAddressSigned(A &addressSpace,
+ R registers, pint_t cfa,
+ PrologInfo &prolog) {
pint_t raSignState;
auto regloc = prolog.savedRegisters[UNW_AARCH64_RA_SIGN_STATE];
if (regloc.location == CFI_Parser<A>::kRegisterUnused)
@@ -185,6 +188,22 @@ bool DwarfInstructions<A, R>::getRA_SIGN_STATE(A &addressSpace, R registers,
// Only bit[0] is meaningful.
return raSignState & 0x01;
}
+
+template <typename A, typename R>
+bool DwarfInstructions<A, R>::isReturnAddressSignedWithPC(A &addressSpace,
+ R registers,
+ pint_t cfa,
+ PrologInfo &prolog) {
+ pint_t raSignState;
+ auto regloc = prolog.savedRegisters[UNW_AARCH64_RA_SIGN_STATE];
+ if (regloc.location == CFI_Parser<A>::kRegisterUnused)
+ raSignState = static_cast<pint_t>(regloc.value);
+ else
+ raSignState = getSavedRegister(addressSpace, registers, cfa, regloc);
+
+ // Only bit[1] is meaningful.
+ return raSignState & 0x02;
+}
#endif
template <typename A, typename R>
@@ -288,7 +307,7 @@ int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc,
// restored. autia1716 is used instead of autia as autia1716 assembles
// to a NOP on pre-v8.3a architectures.
if ((R::getArch() == REGISTERS_ARM64) &&
- getRA_SIGN_STATE(addressSpace, registers, cfa, prolog) &&
+ isReturnAddressSigned(addressSpace, registers, cfa, prolog) &&
returnAddress != 0) {
#if !defined(_LIBUNWIND_IS_NATIVE_ONLY)
return UNW_ECROSSRASIGNING;
@@ -296,13 +315,24 @@ int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc,
register unsigned long long x17 __asm("x17") = returnAddress;
register unsigned long long x16 __asm("x16") = cfa;
- // These are the autia1716/autib1716 instructions. The hint instructions
- // are used here as gcc does not assemble autia1716/autib1716 for pre
- // armv8.3a targets.
- if (cieInfo.addressesSignedWithBKey)
- asm("hint 0xe" : "+r"(x17) : "r"(x16)); // autib1716
- else
- asm("hint 0xc" : "+r"(x17) : "r"(x16)); // autia1716
+ // We use the hint versions of the authentication instructions below to
+ // ensure they're assembled by the compiler even for targets with no
+ // FEAT_PAuth/FEAT_PAuth_LR support.
+ if(isReturnAddressSignedWithPC(addressSpace, registers, cfa, prolog)) {
+ register unsigned long long x15 __asm("x15") = prolog.ptrAuthDiversifier;
+ if(cieInfo.addressesSignedWithBKey) {
+ asm("hint 0x27\n\t" // pacm
+ "hint 0xe" : "+r"(x17) : "r"(x16), "r"(x15)); // autib1716
+ } else {
+ asm("hint 0x27\n\t" // pacm
+ "hint 0xc" : "+r"(x17) : "r"(x16), "r"(x15)); // autia1716
+ }
+ } else {
+ if (cieInfo.addressesSignedWithBKey)
+ asm("hint 0xe" : "+r"(x17) : "r"(x16)); // autib1716
+ else
+ asm("hint 0xc" : "+r"(x17) : "r"(x16)); // autia1716
+ }
returnAddress = x17;
#endif
}
diff --git a/libunwind/src/DwarfParser.hpp b/libunwind/src/DwarfParser.hpp
index 0682942ce13799..b104d773ed4440 100644
--- a/libunwind/src/DwarfParser.hpp
+++ b/libunwind/src/DwarfParser.hpp
@@ -91,6 +91,9 @@ class CFI_Parser {
int64_t cfaExpression; // CFA = expression
uint32_t spExtraArgSize;
RegisterLocation savedRegisters[kMaxRegisterNumber + 1];
+ #if defined(_LIBUNWIND_TARGET_AARCH64)
+ pint_t ptrAuthDiversifier;
+ #endif
enum class InitializeTime { kLazy, kNormal };
// When saving registers, this data structure is lazily initialized.
@@ -799,6 +802,23 @@ bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace,
}
break;
+#if defined(_LIBUNWIND_TARGET_AARCH64)
+ case DW_CFA_AARCH64_negate_ra_state_with_pc: {
+ int64_t value =
+ results->savedRegisters[UNW_AARCH64_RA_SIGN_STATE].value ^ 0x3;
+ results->setRegisterValue(UNW_AARCH64_RA_SIGN_STATE, value,
+ initialState);
+ // When calucating the value of the PC, it is assumed that the CFI instruction
+ // is placed before the signing instruction, however it is placed after. Because
+ // of this, we need to take into account the CFI instruction is one instruction
+ // call later than expected, and reduce the PC value by 4 bytes to compensate.
+ results->ptrAuthDiversifier = fdeInfo.pcStart + codeOffset - 0x4;
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_AARCH64_negate_ra_state_with_pc(pc=0x%" PRIx64 ")\n",
+ static_cast<uint64_t>(results->ptrAuthDiversifier));
+ }
+ break;
+#endif
+
#else
(void)arch;
#endif
diff --git a/libunwind/src/dwarf2.h b/libunwind/src/dwarf2.h
index 174277d5a79508..2ad3d3c464e80d 100644
--- a/libunwind/src/dwarf2.h
+++ b/libunwind/src/dwarf2.h
@@ -51,7 +51,8 @@ enum {
DW_CFA_GNU_negative_offset_extended = 0x2F,
// AARCH64 extensions
- DW_CFA_AARCH64_negate_ra_state = 0x2D
+ DW_CFA_AARCH64_negate_ra_state_with_pc = 0x2C,
+ DW_CFA_AARCH64_negate_ra_state = 0x2D
};
diff --git a/llvm/include/llvm/BinaryFormat/Dwarf.def b/llvm/include/llvm/BinaryFormat/Dwarf.def
index d55947fc5103ac..9336f2a454ae47 100644
--- a/llvm/include/llvm/BinaryFormat/Dwarf.def
+++ b/llvm/include/llvm/BinaryFormat/Dwarf.def
@@ -1238,6 +1238,7 @@ HANDLE_DW_CFA(0x16, val_expression)
// Vendor extensions:
HANDLE_DW_CFA_PRED(0x1d, MIPS_advance_loc8, SELECT_MIPS64)
HANDLE_DW_CFA_PRED(0x2d, GNU_window_save, SELECT_SPARC)
+HANDLE_DW_CFA_PRED(0x2c, AARCH64_negate_ra_state_with_pc, SELECT_AARCH64)
HANDLE_DW_CFA_PRED(0x2d, AARCH64_negate_ra_state, SELECT_AARCH64)
HANDLE_DW_CFA_PRED(0x2e, GNU_args_size, SELECT_X86)
// Heterogeneous Debugging Extension defined at
diff --git a/llvm/include/llvm/MC/MCDwarf.h b/llvm/include/llvm/MC/MCDwarf.h
index bea79545d1ab96..2ceea906ea57a7 100644
--- a/llvm/include/llvm/MC/MCDwarf.h
+++ b/llvm/include/llvm/MC/MCDwarf.h
@@ -515,6 +515,7 @@ class MCCFIInstruction {
OpRegister,
OpWindowSave,
OpNegateRAState,
+ OpNegateRAStateWithPC,
OpGnuArgsSize,
OpLabel,
};
@@ -642,6 +643,13 @@ class MCCFIInstruction {
return MCCFIInstruction(OpNegateRAState, L, 0, INT64_C(0), Loc);
}
+ /// .cfi_negate_ra_state_with_pc AArch64 negate RA state with PC.
+ static MCCFIInstruction createNegateRAStateWithPC(MCSymbol *L,
+ SMLoc Loc = {}) {
+ return MCCFIInstruction(OpNegateRAStateWithPC, L, 0, INT64_C(0), Loc);
+ }
+
+
/// .cfi_restore says that the rule for Register is now the same as it
/// was at the beginning of the function, after all initial instructions added
/// by .cfi_startproc were executed.
diff --git a/llvm/include/llvm/MC/MCStreamer.h b/llvm/include/llvm/MC/MCStreamer.h
index 707aecc5dc578e..a376ba810ba515 100644
--- a/llvm/include/llvm/MC/MCStreamer.h
+++ b/llvm/include/llvm/MC/MCStreamer.h
@@ -1022,6 +1022,7 @@ class MCStreamer {
SMLoc Loc = {});
virtual void emitCFIWindowSave(SMLoc Loc = {});
virtual void emitCFINegateRAState(SMLoc Loc = {});
+ virtual void emitCFINegateRAStateWithPC(SMLoc Loc = {});
virtual void emitCFILabelDirective(SMLoc Loc, StringRef Name);
virtual void emitWinCFIStartProc(const MCSymbol *Symbol, SMLoc Loc = SMLoc());
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp
index 21d0d070c247f4..daad82d26da652 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp
@@ -236,6 +236,9 @@ void AsmPrinter::emitCFIInstruction(const MCCFIInstruction &Inst) const {
case MCCFIInstruction::OpNegateRAState:
OutStreamer->emitCFINegateRAState(Loc);
break;
+ case MCCFIInstruction::OpNegateRAStateWithPC:
+ OutStreamer->emitCFINegateRAStateWithPC(Loc);
+ break;
case MCCFIInstruction::OpSameValue:
OutStreamer->emitCFISameValue(Inst.getRegister(), Loc);
break;
diff --git a/llvm/lib/CodeGen/CFIInstrInserter.cpp b/llvm/lib/CodeGen/CFIInstrInserter.cpp
index f5bedc7b8ecdfc..4217ec6a1cca8a 100644
--- a/llvm/lib/CodeGen/CFIInstrInserter.cpp
+++ b/llvm/lib/CodeGen/CFIInstrInserter.cpp
@@ -260,6 +260,7 @@ void CFIInstrInserter::calculateOutgoingCFAInfo(MBBCFAInfo &MBBInfo) {
case MCCFIInstruction::OpEscape:
case MCCFIInstruction::OpWindowSave:
case MCCFIInstruction::OpNegateRAState:
+ case MCCFIInstruction::OpNegateRAStateWithPC:
case MCCFIInstruction::OpGnuArgsSize:
case MCCFIInstruction::OpLabel:
break;
diff --git a/llvm/lib/CodeGen/MIRParser/MILexer.cpp b/llvm/lib/CodeGen/MIRParser/MILexer.cpp
index 0809f88fde56b1..5a3806ce57335a 100644
--- a/llvm/lib/CodeGen/MIRParser/MILexer.cpp
+++ b/llvm/lib/CodeGen/MIRParser/MILexer.cpp
@@ -238,6 +238,8 @@ static MIToken::TokenKind getIdentifierKind(StringRef Identifier) {
.Case("window_save", MIToken::kw_cfi_window_save)
.Case("negate_ra_sign_state",
MIToken::kw_cfi_aarch64_negate_ra_sign_state)
+ .Case("negate_ra_sign_state_with_pc",
+ MIToken::kw_cfi_aarch64_negate_ra_sign_state_with_pc)
.Case("blockaddress", MIToken::kw_blockaddress)
.Case("intrinsic", MIToken::kw_intrinsic)
.Case("target-index", MIToken::kw_target_index)
diff --git a/llvm/lib/CodeGen/MIRParser/MILexer.h b/llvm/lib/CodeGen/MIRParser/MILexer.h
index 22547483a8a86b..3931da3eaae1d3 100644
--- a/llvm/lib/CodeGen/MIRParser/MILexer.h
+++ b/llvm/lib/CodeGen/MIRParser/MILexer.h
@@ -96,6 +96,7 @@ struct MIToken {
kw_cfi_undefined,
kw_cfi_window_save,
kw_cfi_aarch64_negate_ra_sign_state,
+ kw_cfi_aarch64_negate_ra_sign_state_with_pc,
kw_blockaddress,
kw_intrinsic,
kw_target_index,
diff --git a/llvm/lib/CodeGen/MIRParser/MIParser.cpp b/llvm/lib/CodeGen/MIRParser/MIParser.cpp
index 74f38e886a6b97..a00cf0b906d5a0 100644
--- a/llvm/lib/CodeGen/MIRParser/MIParser.cpp
+++ b/llvm/lib/CodeGen/MIRParser/MIParser.cpp
@@ -2565,6 +2565,10 @@ bool MIParser::parseCFIOperand(MachineOperand &Dest) {
case MIToken::kw_cfi_aarch64_negate_ra_sign_state:
CFIIndex = MF.addFrameInst(MCCFIInstruction::createNegateRAState(nullptr));
break;
+ case MIToken::kw_cfi_aarch64_negate_ra_sign_state_with_pc:
+ CFIIndex =
+ MF.addFrameInst(MCCFIInstruction::createNegateRAStateWithPC(nullptr));
+ break;
case MIToken::kw_cfi_escape: {
std::string Values;
if (parseCFIEscapeValues(Values))
@@ -2920,6 +2924,7 @@ bool MIParser::parseMachineOperand(const unsigned OpCode, const unsigned OpIdx,
case MIToken::kw_cfi_undefined:
case MIToken::kw_cfi_window_save:
case MIToken::kw_cfi_aarch64_negate_ra_sign_state:
+ case MIToken::kw_cfi_aarch64_negate_ra_sign_state_with_pc:
return parseCFIOperand(Dest);
case MIToken::kw_blockaddress:
return parseBlockAddressOperand(Dest);
diff --git a/llvm/lib/CodeGen/MachineOperand.cpp b/llvm/lib/CodeGen/MachineOperand.cpp
index 89d32c3f005e00..cd94213da79893 100644
--- a/llvm/lib/CodeGen/MachineOperand.cpp
+++ b/llvm/lib/CodeGen/MachineOperand.cpp
@@ -768,6 +768,10 @@ static void printCFI(raw_ostream &OS, const MCCFIInstruction &CFI,
if (MCSymbol *Label = CFI.getLabel())
MachineOperand::printSymbol(OS, *Label);
break;
+ case MCCFIInstruction::OpNegateRAStateWithPC:
+ OS << "negate_ra_sign_state_with_pc ";
+ if (MCSymbol *Label = CFI.getLabel())
+ MachineOperand::printSymbol(OS, *Label);
default:
// TODO: Print the other CFI Operations.
OS << "<unserializable cfi directive>";
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp
index aff26824dda104..38e264f233e39b 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp
@@ -288,6 +288,7 @@ Error CFIProgram::parse(DWARFDataExtractor Data, uint64_t *Offset,
case DW_CFA_remember_state:
case DW_CFA_restore_state:
case DW_CFA_GNU_window_save:
+ case DW_CFA_AARCH64_negate_ra_state_with_pc:
// No operands
addInstruction(Opcode);
break;
@@ -666,6 +667,28 @@ Error UnwindTable::parseRows(const CFIProgram &CFIP, UnwindRow &Row,
}
break;
+ case dwarf::DW_CFA_AARCH64_negate_ra_state_with_pc: {
+ constexpr uint32_t AArch64DWARFPAuthRaState = 34;
+ auto LRLoc = Row.getRegisterLocations().getRegisterLocation(
+ AArch64DWARFPAuthRaState);
+ if (LRLoc) {
+ if (LRLoc->getLocation() == UnwindLocation::Constant) {
+ // Toggle the constant value of bits[1:0] from 0 to 1 or 1 to 0.
+ LRLoc->setConstant(LRLoc->getConstant() ^ 0x3);
+ } else {
+ return createStringError(
+ errc::invalid_argument,
+ "%s encountered when existing rule for this register is not "
+ "a constant",
+ CFIP.callFrameString(Inst.Opcode).str().c_str());
+ }
+ } else {
+ Row.getRegisterLocations().setRegisterLocation(
+ AArch64DWARFPAuthRaState, UnwindLocation::createIsConstant(0x3));
+ }
+ break;
+ }
+
case dwarf::DW_CFA_undefined: {
llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);
if (!RegNum)
@@ -847,6 +870,7 @@ CFIProgram::getOperandTypes() {
DECLARE_OP0(DW_CFA_remember_state);
DECLARE_OP0(DW_CFA_restore_state);
DECLARE_OP0(DW_CFA_GNU_window_save);
+ DECLARE_OP0(DW_CFA_AARCH64_negate_ra_state_with_pc);
DECLARE_OP1(DW_CFA_GNU_args_size, OT_Offset);
DECLARE_OP0(DW_CFA_nop);
diff --git a/llvm/lib/MC/MCAsmStreamer.cpp b/llvm/lib/MC/MCAsmStreamer.cpp
index 31b519a3e5c56a..b9ad0b4eac9c7b 100644
--- a/llvm/lib/MC/MCAsmStreamer.cpp
+++ b/llvm/lib/MC/MCAsmStreamer.cpp
@@ -373,6 +373,7 @@ class MCAsmStreamer final : public MCStreamer {
SMLoc Loc) override;
void emitCFIWindowSave(SMLoc Loc) override;
void emitCFINegateRAState(SMLoc Loc) override;
+ void emitCFINegateRAStateWithPC(SMLoc Loc) override;
void emitCFIReturnColumn(int64_t Register) override;
void emitCFILabelDirective(SMLoc Loc, StringRef Name) override;
@@ -2145,6 +2146,12 @@ void MCAsmStreamer::emitCFINegateRAState(SMLoc Loc) {
EmitEOL();
}
+void MCAsmStreamer::emitCFINegateRAStateWithPC(SMLoc Loc) {
+ MCStreamer::emitCFINegateRAStateWithPC(Loc);
+ OS << "\t.cfi_negate_ra_state_with_pc";
+ EmitEOL();
+}
+
void MCAsmStreamer::emitCFIReturnColumn(int64_t Register) {
MCStreamer::emitCFIReturnColumn(Register);
OS << "\t.cfi_return_column ";
diff --git a/llvm/lib/MC/MCDwarf.cpp b/llvm/lib/MC/MCDwarf.cpp
index 8ff097f29aebd1..e058358fb8ad4b 100644
--- a/llvm/lib/MC/MCDwarf.cpp
+++ b/llvm/lib/MC/MCDwarf.cpp
@@ -1381,6 +1381,10 @@ void FrameEmitterImpl::emitCFIInstruction(const MCCFIInstruction &Instr) {
Streamer.emitInt8(dwarf::DW_CFA_AARCH64_negate_ra_state);
return;
+ case MCCFIInstruction::OpNegateRAStateWithPC:
+ Streamer.emitInt8(dwarf::DW_CFA_AARCH64_negate_ra_state_with_pc);
+ return;
+
case MCCFIInstruction::OpUndefined: {
unsigned Reg = Instr.getRegister();
Streamer.emitInt8(dwarf::DW_CFA_undefined);
diff --git a/llvm/lib/MC/MCStreamer.cpp b/llvm/lib/MC/MCStreamer.cpp
index 13b162768578c5..5474db1315f141 100644
--- a/llvm/lib/MC/MCStreamer.cpp
+++ b/llvm/lib/MC/MCStreamer.cpp
@@ -688,6 +688,16 @@ void MCStreamer::emitCFINegateRAState(SMLoc Loc) {
CurFrame->Instructions.push_back(Instruction);
}
+void MCStreamer::emitCFINegateRAStateWithPC(SMLoc Loc) {
+ MCSymbol *Label = emitCFILabel();
+ MCCFIInstruction Instruction =
+ MCCFIInstruction::createNegateRAStateWithPC(Label, Loc);
+ MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo();
+ if (!CurFrame)
+ return;
+ CurFrame->Instructions.push_back(Instruction);
+}
+
void MCStreamer::emitCFIReturnColumn(int64_t Register) {
MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo();
if (!CurFrame)
diff --git a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
index be33331be4e8ff..98293bc7ac30e2 100644
--- a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
@@ -702,7 +702,10 @@ void AArch64FrameLowering::resetCFIToInitialState(
// Flip the RA sign state.
if (MFI.shouldSignReturnAddress(MF)) {
- CFIIndex = MF.addFrameInst(MCCFIInstruction::createNegateRAState(nullptr));
+ auto CFIInst = MFI.branchProtectionPAuthLR()
+ ? MCCFIInstruction::createNegateRAStateWithPC(nullptr)
+ : MCCFIInstruction::createNegateRAState(nullptr);
+ CFIIndex = MF.addFrameInst(CFIInst);
BuildMI(MBB, InsertPt, DL, CFIDesc).addCFIIndex(CFIIndex);
}
diff --git a/llvm/lib/Target/AArch64/AArch64PointerAuth.cpp b/llvm/lib/Target/AArch64/AArch64PointerAuth.cpp
index 92ab4b5c3d251f..c3ad488fb8e4d1 100644
--- a/llvm/lib/Target/AArch64/AArch64PointerAuth.cpp
+++ b/llvm/lib/Target/AArch64/AArch64PointerAuth.cpp
@@ -71,6 +71,18 @@ FunctionPass *llvm::createAArch64PointerAuthPass() {
char AArch64PointerAuth::ID = 0;
+static void emitPACSymOffsetIntoX16(const TargetInstrInfo &TII,
+ MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator I, DebugLoc DL,
+ MCSymbol *PACSym) {
+ BuildMI(MBB, I, DL, TII.get(AArch64::ADRP), AArch64::X16)
+ .addSym(PACSym, AArch64II::MO_PAGE);
+ BuildMI(MBB, I, DL, TII.get(AArch64::ADDXri), AArch64::X16)
+ .addReg(AArch64::X16)
+ .addSym(PACSym, AArch64II::MO_PAGEOFF | AArch64II::MO_NC)
+ .addImm(0);
+}
+
// Where PAuthLR support is not known at compile time, it is supported using
// PACM. PACM is in the hint space so has no effect when PAuthLR is not
// supported by the hardware, but will alter the behaviour of PACI*SP, AUTI*SP
@@ -81,12 +93,10 @@ static void BuildPACM(const AArch64Subtarget &Subtarget, MachineBasicBlock &MBB,
const TargetInstrInfo *TII = Subtarget.getInstrInfo();
auto &MFnI = *MBB.getParent()->getInfo<AArch64FunctionInfo>();
- // ADR X16,<address_of_PACIASP>
+ // Offset to PAC*SP using ADRP + ADD.
if (PACSym) {
assert(Flags == MachineInstr::FrameDestroy);
- BuildMI(MBB, MBBI, DL, TII->get(AArch64::ADR))
- .addReg(AArch64::X16, RegState::Define)
- .addSym(PACSym);
+ emitPACSymOffsetIntoX16(*TII, MBB, MBBI, DL, PACSym);
}
// Only emit PACM if -mbranch-protection has +pc and the target does not
@@ -95,12 +105,31 @@ static void BuildPACM(const AArch64Subtarget &Subtarget, MachineBasicBlock &MBB,
BuildMI(MBB, MBBI, DL, TII->get(AArch64::PACM)).setMIFlag(Flags);
}
+static void emitPACCFI(const AArch64Subtarget &Subtarget,
+ MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
+ ...
[truncated]
|
@llvm/pr-subscribers-debuginfo Author: Jack Styles (Stylie777) ChangesAs part of FEAT_PAuthLR, a new DWARF Frame Instruction was introduced,
For the ABI information, see here: https://github.com/ARM-software/abi-aa/blob/853286c7ab66048e4b819682ce17f567b77a0291/aadwarf64/aadwarf64.rst#id23 Patch is 78.23 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/112171.diff 34 Files Affected:
diff --git a/libunwind/src/DwarfInstructions.hpp b/libunwind/src/DwarfInstructions.hpp
index bd9ece60ee5881..e7c467de80adb6 100644
--- a/libunwind/src/DwarfInstructions.hpp
+++ b/libunwind/src/DwarfInstructions.hpp
@@ -74,8 +74,10 @@ class DwarfInstructions {
__builtin_unreachable();
}
#if defined(_LIBUNWIND_TARGET_AARCH64)
- static bool getRA_SIGN_STATE(A &addressSpace, R registers, pint_t cfa,
- PrologInfo &prolog);
+ static bool isReturnAddressSigned(A &addressSpace, R registers, pint_t cfa,
+ PrologInfo &prolog);
+ static bool isReturnAddressSignedWithPC(A &addressSpace, R registers,
+ pint_t cfa, PrologInfo &prolog);
#endif
};
@@ -173,8 +175,9 @@ v128 DwarfInstructions<A, R>::getSavedVectorRegister(
}
#if defined(_LIBUNWIND_TARGET_AARCH64)
template <typename A, typename R>
-bool DwarfInstructions<A, R>::getRA_SIGN_STATE(A &addressSpace, R registers,
- pint_t cfa, PrologInfo &prolog) {
+bool DwarfInstructions<A, R>::isReturnAddressSigned(A &addressSpace,
+ R registers, pint_t cfa,
+ PrologInfo &prolog) {
pint_t raSignState;
auto regloc = prolog.savedRegisters[UNW_AARCH64_RA_SIGN_STATE];
if (regloc.location == CFI_Parser<A>::kRegisterUnused)
@@ -185,6 +188,22 @@ bool DwarfInstructions<A, R>::getRA_SIGN_STATE(A &addressSpace, R registers,
// Only bit[0] is meaningful.
return raSignState & 0x01;
}
+
+template <typename A, typename R>
+bool DwarfInstructions<A, R>::isReturnAddressSignedWithPC(A &addressSpace,
+ R registers,
+ pint_t cfa,
+ PrologInfo &prolog) {
+ pint_t raSignState;
+ auto regloc = prolog.savedRegisters[UNW_AARCH64_RA_SIGN_STATE];
+ if (regloc.location == CFI_Parser<A>::kRegisterUnused)
+ raSignState = static_cast<pint_t>(regloc.value);
+ else
+ raSignState = getSavedRegister(addressSpace, registers, cfa, regloc);
+
+ // Only bit[1] is meaningful.
+ return raSignState & 0x02;
+}
#endif
template <typename A, typename R>
@@ -288,7 +307,7 @@ int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc,
// restored. autia1716 is used instead of autia as autia1716 assembles
// to a NOP on pre-v8.3a architectures.
if ((R::getArch() == REGISTERS_ARM64) &&
- getRA_SIGN_STATE(addressSpace, registers, cfa, prolog) &&
+ isReturnAddressSigned(addressSpace, registers, cfa, prolog) &&
returnAddress != 0) {
#if !defined(_LIBUNWIND_IS_NATIVE_ONLY)
return UNW_ECROSSRASIGNING;
@@ -296,13 +315,24 @@ int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc,
register unsigned long long x17 __asm("x17") = returnAddress;
register unsigned long long x16 __asm("x16") = cfa;
- // These are the autia1716/autib1716 instructions. The hint instructions
- // are used here as gcc does not assemble autia1716/autib1716 for pre
- // armv8.3a targets.
- if (cieInfo.addressesSignedWithBKey)
- asm("hint 0xe" : "+r"(x17) : "r"(x16)); // autib1716
- else
- asm("hint 0xc" : "+r"(x17) : "r"(x16)); // autia1716
+ // We use the hint versions of the authentication instructions below to
+ // ensure they're assembled by the compiler even for targets with no
+ // FEAT_PAuth/FEAT_PAuth_LR support.
+ if(isReturnAddressSignedWithPC(addressSpace, registers, cfa, prolog)) {
+ register unsigned long long x15 __asm("x15") = prolog.ptrAuthDiversifier;
+ if(cieInfo.addressesSignedWithBKey) {
+ asm("hint 0x27\n\t" // pacm
+ "hint 0xe" : "+r"(x17) : "r"(x16), "r"(x15)); // autib1716
+ } else {
+ asm("hint 0x27\n\t" // pacm
+ "hint 0xc" : "+r"(x17) : "r"(x16), "r"(x15)); // autia1716
+ }
+ } else {
+ if (cieInfo.addressesSignedWithBKey)
+ asm("hint 0xe" : "+r"(x17) : "r"(x16)); // autib1716
+ else
+ asm("hint 0xc" : "+r"(x17) : "r"(x16)); // autia1716
+ }
returnAddress = x17;
#endif
}
diff --git a/libunwind/src/DwarfParser.hpp b/libunwind/src/DwarfParser.hpp
index 0682942ce13799..b104d773ed4440 100644
--- a/libunwind/src/DwarfParser.hpp
+++ b/libunwind/src/DwarfParser.hpp
@@ -91,6 +91,9 @@ class CFI_Parser {
int64_t cfaExpression; // CFA = expression
uint32_t spExtraArgSize;
RegisterLocation savedRegisters[kMaxRegisterNumber + 1];
+ #if defined(_LIBUNWIND_TARGET_AARCH64)
+ pint_t ptrAuthDiversifier;
+ #endif
enum class InitializeTime { kLazy, kNormal };
// When saving registers, this data structure is lazily initialized.
@@ -799,6 +802,23 @@ bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace,
}
break;
+#if defined(_LIBUNWIND_TARGET_AARCH64)
+ case DW_CFA_AARCH64_negate_ra_state_with_pc: {
+ int64_t value =
+ results->savedRegisters[UNW_AARCH64_RA_SIGN_STATE].value ^ 0x3;
+ results->setRegisterValue(UNW_AARCH64_RA_SIGN_STATE, value,
+ initialState);
+ // When calucating the value of the PC, it is assumed that the CFI instruction
+ // is placed before the signing instruction, however it is placed after. Because
+ // of this, we need to take into account the CFI instruction is one instruction
+ // call later than expected, and reduce the PC value by 4 bytes to compensate.
+ results->ptrAuthDiversifier = fdeInfo.pcStart + codeOffset - 0x4;
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_AARCH64_negate_ra_state_with_pc(pc=0x%" PRIx64 ")\n",
+ static_cast<uint64_t>(results->ptrAuthDiversifier));
+ }
+ break;
+#endif
+
#else
(void)arch;
#endif
diff --git a/libunwind/src/dwarf2.h b/libunwind/src/dwarf2.h
index 174277d5a79508..2ad3d3c464e80d 100644
--- a/libunwind/src/dwarf2.h
+++ b/libunwind/src/dwarf2.h
@@ -51,7 +51,8 @@ enum {
DW_CFA_GNU_negative_offset_extended = 0x2F,
// AARCH64 extensions
- DW_CFA_AARCH64_negate_ra_state = 0x2D
+ DW_CFA_AARCH64_negate_ra_state_with_pc = 0x2C,
+ DW_CFA_AARCH64_negate_ra_state = 0x2D
};
diff --git a/llvm/include/llvm/BinaryFormat/Dwarf.def b/llvm/include/llvm/BinaryFormat/Dwarf.def
index d55947fc5103ac..9336f2a454ae47 100644
--- a/llvm/include/llvm/BinaryFormat/Dwarf.def
+++ b/llvm/include/llvm/BinaryFormat/Dwarf.def
@@ -1238,6 +1238,7 @@ HANDLE_DW_CFA(0x16, val_expression)
// Vendor extensions:
HANDLE_DW_CFA_PRED(0x1d, MIPS_advance_loc8, SELECT_MIPS64)
HANDLE_DW_CFA_PRED(0x2d, GNU_window_save, SELECT_SPARC)
+HANDLE_DW_CFA_PRED(0x2c, AARCH64_negate_ra_state_with_pc, SELECT_AARCH64)
HANDLE_DW_CFA_PRED(0x2d, AARCH64_negate_ra_state, SELECT_AARCH64)
HANDLE_DW_CFA_PRED(0x2e, GNU_args_size, SELECT_X86)
// Heterogeneous Debugging Extension defined at
diff --git a/llvm/include/llvm/MC/MCDwarf.h b/llvm/include/llvm/MC/MCDwarf.h
index bea79545d1ab96..2ceea906ea57a7 100644
--- a/llvm/include/llvm/MC/MCDwarf.h
+++ b/llvm/include/llvm/MC/MCDwarf.h
@@ -515,6 +515,7 @@ class MCCFIInstruction {
OpRegister,
OpWindowSave,
OpNegateRAState,
+ OpNegateRAStateWithPC,
OpGnuArgsSize,
OpLabel,
};
@@ -642,6 +643,13 @@ class MCCFIInstruction {
return MCCFIInstruction(OpNegateRAState, L, 0, INT64_C(0), Loc);
}
+ /// .cfi_negate_ra_state_with_pc AArch64 negate RA state with PC.
+ static MCCFIInstruction createNegateRAStateWithPC(MCSymbol *L,
+ SMLoc Loc = {}) {
+ return MCCFIInstruction(OpNegateRAStateWithPC, L, 0, INT64_C(0), Loc);
+ }
+
+
/// .cfi_restore says that the rule for Register is now the same as it
/// was at the beginning of the function, after all initial instructions added
/// by .cfi_startproc were executed.
diff --git a/llvm/include/llvm/MC/MCStreamer.h b/llvm/include/llvm/MC/MCStreamer.h
index 707aecc5dc578e..a376ba810ba515 100644
--- a/llvm/include/llvm/MC/MCStreamer.h
+++ b/llvm/include/llvm/MC/MCStreamer.h
@@ -1022,6 +1022,7 @@ class MCStreamer {
SMLoc Loc = {});
virtual void emitCFIWindowSave(SMLoc Loc = {});
virtual void emitCFINegateRAState(SMLoc Loc = {});
+ virtual void emitCFINegateRAStateWithPC(SMLoc Loc = {});
virtual void emitCFILabelDirective(SMLoc Loc, StringRef Name);
virtual void emitWinCFIStartProc(const MCSymbol *Symbol, SMLoc Loc = SMLoc());
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp
index 21d0d070c247f4..daad82d26da652 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp
@@ -236,6 +236,9 @@ void AsmPrinter::emitCFIInstruction(const MCCFIInstruction &Inst) const {
case MCCFIInstruction::OpNegateRAState:
OutStreamer->emitCFINegateRAState(Loc);
break;
+ case MCCFIInstruction::OpNegateRAStateWithPC:
+ OutStreamer->emitCFINegateRAStateWithPC(Loc);
+ break;
case MCCFIInstruction::OpSameValue:
OutStreamer->emitCFISameValue(Inst.getRegister(), Loc);
break;
diff --git a/llvm/lib/CodeGen/CFIInstrInserter.cpp b/llvm/lib/CodeGen/CFIInstrInserter.cpp
index f5bedc7b8ecdfc..4217ec6a1cca8a 100644
--- a/llvm/lib/CodeGen/CFIInstrInserter.cpp
+++ b/llvm/lib/CodeGen/CFIInstrInserter.cpp
@@ -260,6 +260,7 @@ void CFIInstrInserter::calculateOutgoingCFAInfo(MBBCFAInfo &MBBInfo) {
case MCCFIInstruction::OpEscape:
case MCCFIInstruction::OpWindowSave:
case MCCFIInstruction::OpNegateRAState:
+ case MCCFIInstruction::OpNegateRAStateWithPC:
case MCCFIInstruction::OpGnuArgsSize:
case MCCFIInstruction::OpLabel:
break;
diff --git a/llvm/lib/CodeGen/MIRParser/MILexer.cpp b/llvm/lib/CodeGen/MIRParser/MILexer.cpp
index 0809f88fde56b1..5a3806ce57335a 100644
--- a/llvm/lib/CodeGen/MIRParser/MILexer.cpp
+++ b/llvm/lib/CodeGen/MIRParser/MILexer.cpp
@@ -238,6 +238,8 @@ static MIToken::TokenKind getIdentifierKind(StringRef Identifier) {
.Case("window_save", MIToken::kw_cfi_window_save)
.Case("negate_ra_sign_state",
MIToken::kw_cfi_aarch64_negate_ra_sign_state)
+ .Case("negate_ra_sign_state_with_pc",
+ MIToken::kw_cfi_aarch64_negate_ra_sign_state_with_pc)
.Case("blockaddress", MIToken::kw_blockaddress)
.Case("intrinsic", MIToken::kw_intrinsic)
.Case("target-index", MIToken::kw_target_index)
diff --git a/llvm/lib/CodeGen/MIRParser/MILexer.h b/llvm/lib/CodeGen/MIRParser/MILexer.h
index 22547483a8a86b..3931da3eaae1d3 100644
--- a/llvm/lib/CodeGen/MIRParser/MILexer.h
+++ b/llvm/lib/CodeGen/MIRParser/MILexer.h
@@ -96,6 +96,7 @@ struct MIToken {
kw_cfi_undefined,
kw_cfi_window_save,
kw_cfi_aarch64_negate_ra_sign_state,
+ kw_cfi_aarch64_negate_ra_sign_state_with_pc,
kw_blockaddress,
kw_intrinsic,
kw_target_index,
diff --git a/llvm/lib/CodeGen/MIRParser/MIParser.cpp b/llvm/lib/CodeGen/MIRParser/MIParser.cpp
index 74f38e886a6b97..a00cf0b906d5a0 100644
--- a/llvm/lib/CodeGen/MIRParser/MIParser.cpp
+++ b/llvm/lib/CodeGen/MIRParser/MIParser.cpp
@@ -2565,6 +2565,10 @@ bool MIParser::parseCFIOperand(MachineOperand &Dest) {
case MIToken::kw_cfi_aarch64_negate_ra_sign_state:
CFIIndex = MF.addFrameInst(MCCFIInstruction::createNegateRAState(nullptr));
break;
+ case MIToken::kw_cfi_aarch64_negate_ra_sign_state_with_pc:
+ CFIIndex =
+ MF.addFrameInst(MCCFIInstruction::createNegateRAStateWithPC(nullptr));
+ break;
case MIToken::kw_cfi_escape: {
std::string Values;
if (parseCFIEscapeValues(Values))
@@ -2920,6 +2924,7 @@ bool MIParser::parseMachineOperand(const unsigned OpCode, const unsigned OpIdx,
case MIToken::kw_cfi_undefined:
case MIToken::kw_cfi_window_save:
case MIToken::kw_cfi_aarch64_negate_ra_sign_state:
+ case MIToken::kw_cfi_aarch64_negate_ra_sign_state_with_pc:
return parseCFIOperand(Dest);
case MIToken::kw_blockaddress:
return parseBlockAddressOperand(Dest);
diff --git a/llvm/lib/CodeGen/MachineOperand.cpp b/llvm/lib/CodeGen/MachineOperand.cpp
index 89d32c3f005e00..cd94213da79893 100644
--- a/llvm/lib/CodeGen/MachineOperand.cpp
+++ b/llvm/lib/CodeGen/MachineOperand.cpp
@@ -768,6 +768,10 @@ static void printCFI(raw_ostream &OS, const MCCFIInstruction &CFI,
if (MCSymbol *Label = CFI.getLabel())
MachineOperand::printSymbol(OS, *Label);
break;
+ case MCCFIInstruction::OpNegateRAStateWithPC:
+ OS << "negate_ra_sign_state_with_pc ";
+ if (MCSymbol *Label = CFI.getLabel())
+ MachineOperand::printSymbol(OS, *Label);
default:
// TODO: Print the other CFI Operations.
OS << "<unserializable cfi directive>";
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp
index aff26824dda104..38e264f233e39b 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp
@@ -288,6 +288,7 @@ Error CFIProgram::parse(DWARFDataExtractor Data, uint64_t *Offset,
case DW_CFA_remember_state:
case DW_CFA_restore_state:
case DW_CFA_GNU_window_save:
+ case DW_CFA_AARCH64_negate_ra_state_with_pc:
// No operands
addInstruction(Opcode);
break;
@@ -666,6 +667,28 @@ Error UnwindTable::parseRows(const CFIProgram &CFIP, UnwindRow &Row,
}
break;
+ case dwarf::DW_CFA_AARCH64_negate_ra_state_with_pc: {
+ constexpr uint32_t AArch64DWARFPAuthRaState = 34;
+ auto LRLoc = Row.getRegisterLocations().getRegisterLocation(
+ AArch64DWARFPAuthRaState);
+ if (LRLoc) {
+ if (LRLoc->getLocation() == UnwindLocation::Constant) {
+ // Toggle the constant value of bits[1:0] from 0 to 1 or 1 to 0.
+ LRLoc->setConstant(LRLoc->getConstant() ^ 0x3);
+ } else {
+ return createStringError(
+ errc::invalid_argument,
+ "%s encountered when existing rule for this register is not "
+ "a constant",
+ CFIP.callFrameString(Inst.Opcode).str().c_str());
+ }
+ } else {
+ Row.getRegisterLocations().setRegisterLocation(
+ AArch64DWARFPAuthRaState, UnwindLocation::createIsConstant(0x3));
+ }
+ break;
+ }
+
case dwarf::DW_CFA_undefined: {
llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);
if (!RegNum)
@@ -847,6 +870,7 @@ CFIProgram::getOperandTypes() {
DECLARE_OP0(DW_CFA_remember_state);
DECLARE_OP0(DW_CFA_restore_state);
DECLARE_OP0(DW_CFA_GNU_window_save);
+ DECLARE_OP0(DW_CFA_AARCH64_negate_ra_state_with_pc);
DECLARE_OP1(DW_CFA_GNU_args_size, OT_Offset);
DECLARE_OP0(DW_CFA_nop);
diff --git a/llvm/lib/MC/MCAsmStreamer.cpp b/llvm/lib/MC/MCAsmStreamer.cpp
index 31b519a3e5c56a..b9ad0b4eac9c7b 100644
--- a/llvm/lib/MC/MCAsmStreamer.cpp
+++ b/llvm/lib/MC/MCAsmStreamer.cpp
@@ -373,6 +373,7 @@ class MCAsmStreamer final : public MCStreamer {
SMLoc Loc) override;
void emitCFIWindowSave(SMLoc Loc) override;
void emitCFINegateRAState(SMLoc Loc) override;
+ void emitCFINegateRAStateWithPC(SMLoc Loc) override;
void emitCFIReturnColumn(int64_t Register) override;
void emitCFILabelDirective(SMLoc Loc, StringRef Name) override;
@@ -2145,6 +2146,12 @@ void MCAsmStreamer::emitCFINegateRAState(SMLoc Loc) {
EmitEOL();
}
+void MCAsmStreamer::emitCFINegateRAStateWithPC(SMLoc Loc) {
+ MCStreamer::emitCFINegateRAStateWithPC(Loc);
+ OS << "\t.cfi_negate_ra_state_with_pc";
+ EmitEOL();
+}
+
void MCAsmStreamer::emitCFIReturnColumn(int64_t Register) {
MCStreamer::emitCFIReturnColumn(Register);
OS << "\t.cfi_return_column ";
diff --git a/llvm/lib/MC/MCDwarf.cpp b/llvm/lib/MC/MCDwarf.cpp
index 8ff097f29aebd1..e058358fb8ad4b 100644
--- a/llvm/lib/MC/MCDwarf.cpp
+++ b/llvm/lib/MC/MCDwarf.cpp
@@ -1381,6 +1381,10 @@ void FrameEmitterImpl::emitCFIInstruction(const MCCFIInstruction &Instr) {
Streamer.emitInt8(dwarf::DW_CFA_AARCH64_negate_ra_state);
return;
+ case MCCFIInstruction::OpNegateRAStateWithPC:
+ Streamer.emitInt8(dwarf::DW_CFA_AARCH64_negate_ra_state_with_pc);
+ return;
+
case MCCFIInstruction::OpUndefined: {
unsigned Reg = Instr.getRegister();
Streamer.emitInt8(dwarf::DW_CFA_undefined);
diff --git a/llvm/lib/MC/MCStreamer.cpp b/llvm/lib/MC/MCStreamer.cpp
index 13b162768578c5..5474db1315f141 100644
--- a/llvm/lib/MC/MCStreamer.cpp
+++ b/llvm/lib/MC/MCStreamer.cpp
@@ -688,6 +688,16 @@ void MCStreamer::emitCFINegateRAState(SMLoc Loc) {
CurFrame->Instructions.push_back(Instruction);
}
+void MCStreamer::emitCFINegateRAStateWithPC(SMLoc Loc) {
+ MCSymbol *Label = emitCFILabel();
+ MCCFIInstruction Instruction =
+ MCCFIInstruction::createNegateRAStateWithPC(Label, Loc);
+ MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo();
+ if (!CurFrame)
+ return;
+ CurFrame->Instructions.push_back(Instruction);
+}
+
void MCStreamer::emitCFIReturnColumn(int64_t Register) {
MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo();
if (!CurFrame)
diff --git a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
index be33331be4e8ff..98293bc7ac30e2 100644
--- a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
@@ -702,7 +702,10 @@ void AArch64FrameLowering::resetCFIToInitialState(
// Flip the RA sign state.
if (MFI.shouldSignReturnAddress(MF)) {
- CFIIndex = MF.addFrameInst(MCCFIInstruction::createNegateRAState(nullptr));
+ auto CFIInst = MFI.branchProtectionPAuthLR()
+ ? MCCFIInstruction::createNegateRAStateWithPC(nullptr)
+ : MCCFIInstruction::createNegateRAState(nullptr);
+ CFIIndex = MF.addFrameInst(CFIInst);
BuildMI(MBB, InsertPt, DL, CFIDesc).addCFIIndex(CFIIndex);
}
diff --git a/llvm/lib/Target/AArch64/AArch64PointerAuth.cpp b/llvm/lib/Target/AArch64/AArch64PointerAuth.cpp
index 92ab4b5c3d251f..c3ad488fb8e4d1 100644
--- a/llvm/lib/Target/AArch64/AArch64PointerAuth.cpp
+++ b/llvm/lib/Target/AArch64/AArch64PointerAuth.cpp
@@ -71,6 +71,18 @@ FunctionPass *llvm::createAArch64PointerAuthPass() {
char AArch64PointerAuth::ID = 0;
+static void emitPACSymOffsetIntoX16(const TargetInstrInfo &TII,
+ MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator I, DebugLoc DL,
+ MCSymbol *PACSym) {
+ BuildMI(MBB, I, DL, TII.get(AArch64::ADRP), AArch64::X16)
+ .addSym(PACSym, AArch64II::MO_PAGE);
+ BuildMI(MBB, I, DL, TII.get(AArch64::ADDXri), AArch64::X16)
+ .addReg(AArch64::X16)
+ .addSym(PACSym, AArch64II::MO_PAGEOFF | AArch64II::MO_NC)
+ .addImm(0);
+}
+
// Where PAuthLR support is not known at compile time, it is supported using
// PACM. PACM is in the hint space so has no effect when PAuthLR is not
// supported by the hardware, but will alter the behaviour of PACI*SP, AUTI*SP
@@ -81,12 +93,10 @@ static void BuildPACM(const AArch64Subtarget &Subtarget, MachineBasicBlock &MBB,
const TargetInstrInfo *TII = Subtarget.getInstrInfo();
auto &MFnI = *MBB.getParent()->getInfo<AArch64FunctionInfo>();
- // ADR X16,<address_of_PACIASP>
+ // Offset to PAC*SP using ADRP + ADD.
if (PACSym) {
assert(Flags == MachineInstr::FrameDestroy);
- BuildMI(MBB, MBBI, DL, TII->get(AArch64::ADR))
- .addReg(AArch64::X16, RegState::Define)
- .addSym(PACSym);
+ emitPACSymOffsetIntoX16(*TII, MBB, MBBI, DL, PACSym);
}
// Only emit PACM if -mbranch-protection has +pc and the target does not
@@ -95,12 +105,31 @@ static void BuildPACM(const AArch64Subtarget &Subtarget, MachineBasicBlock &MBB,
BuildMI(MBB, MBBI, DL, TII->get(AArch64::PACM)).setMIFlag(Flags);
}
+static void emitPACCFI(const AArch64Subtarget &Subtarget,
+ MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
+ ...
[truncated]
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
020a6be
to
c18dcc6
Compare
libunwind/src/DwarfParser.hpp
Outdated
results->savedRegisters[UNW_AARCH64_RA_SIGN_STATE].value ^ 0x3; | ||
results->setRegisterValue(UNW_AARCH64_RA_SIGN_STATE, value, | ||
initialState); | ||
// When calucating the value of the PC, it is assumed that the CFI |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: calculating
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
This introduces support for unwinding programs where return addresses have been signed using FEAT_PAuth_Lr, where the value of PC is used as a diversifier (-mbranch-protection=pac-ret+pc). A new vendor specific call frame instruction is added, named `DW_CFA_AARCH64_negate_ra_state_with_pc`, to instruct the unwinder tocapture the value of PC at the point of signing and update bit 1 of the existing `RA_SIGN_STATE` pseudo-register to flag the need to use it for authentication. See ARM-software/abi-aa#245 for the ABI change. Authored-by: pratlucas <[email protected]>
This introduces compiler and dwarfdump support for emitting and parsing the new `DW_CFA_AARCH64_negate_ra_state_with_pc` DWARF instruction for FEAT_PAuth_LR. This does mean that, when using FEAT_PAuthLR, the improvements introduced in llvm#96337 cannot be utilised. `.cfi_negate_ra_state_with_pc` must be emitted directly after the signing instruction, and when bundled with other CFI calls, leads to faults when running a program. There are no changes seen when not using FEAT_PAuthLR to how the CFI Instructions are generated. See ARM-software/abi-aa#245 for the ABI change that incororates FEAT_PAuthLR. Authored-by: pratlucas <[email protected]> Co-authored by: vhscampos <[email protected]> Co-authored by: Stylie777 <[email protected]>
With the introduction of `.cfi_negate_ra_state_with_pc`, the location of the CFI Instructions are inconsistent, with `.cfi_negate_ra_state_with_pc` needing to be emitted directly after the signing instruction, and `.cfi_negate_ra_state` being emitted with other CFI instructions as part of the prolog. To ensure consistency between the two CFI Instructions, they are now emitted after the CFI Instruction, regardless of which one is being used. This reverses the changes made in llvm#96377, as this is the commit that moved the CFI instructions initially.
Formatting fixes
c18dcc6
to
d93e91d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM.
There was a missing break, which led to an unannotated fallthrough when merging llvm#112171. This has caused sanitizer builds to fail. This adds the missing break in the switch statement to ensure that the fallthrough does not occur.
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/168/builds/4846 Here is the relevant piece of the build log for the reference
|
…lvm#112171) As part of FEAT_PAuthLR, a new DWARF Frame Instruction was introduced, `DW_CFA_AARCH64_negate_ra_state_with_pc`. This instructs Libunwind that the PC has been used with the signing instruction. This change includes three commits - Libunwind support for the newly introduced DWARF Instruction - CodeGen Support for the DWARF Instructions - Reversing the changes made in llvm#96377. Due to `DW_CFA_AARCH64_negate_ra_state_with_pc`'s requirements to be placed immediately after the signing instruction, this would mean the CFI Instruction location was not consistent with the generated location when not using FEAT_PAuthLR. The commit reverses the changes and makes the location consistent across the different branch protection options. While this does have a code size effect, this is a negligible one. For the ABI information, see here: https://github.com/ARM-software/abi-aa/blob/853286c7ab66048e4b819682ce17f567b77a0291/aadwarf64/aadwarf64.rst#id23
…ment (llvm#113883) There was a missing break, which led to an unannotated fallthrough when merging llvm#112171. This has caused sanitizer builds to fail. This adds the missing break in the switch statement to ensure that the fallthrough does not occur.
As part llvm#112171 support for FEAT_PAuthLR's CFI instructions were added, however the CFI instructions are emitted in the incorrect location. This leads to incorrect CodeGen being generated and possible issues when running a program. According to the ABI, the CFI instructions should be emitted before the signing instruction. This is now done properly. ABI information can be found here: https://github.com/ARM-software/abi-aa/blob/bf0e2c8047c70987165f3e05e571d7836370ade9/aadwarf64/aadwarf64.rst#44call-frame-instructions
…ion (#121559) As part #112171, support for FEAT_PAuthLR's CFI instructions was added. However, the CFI instructions are emitted in the incorrect location. This leads to incorrect CodeGen being generated and possible issues when running a program. According to the ABI, the CFI instructions should be emitted before the signing instruction. This is now done properly. ABI information can be found here: https://github.com/ARM-software/abi-aa/blob/bf0e2c8047c70987165f3e05e571d7836370ade9/aadwarf64/aadwarf64.rst#44call-frame-instructions
…ion (llvm#121559) As part llvm#112171, support for FEAT_PAuthLR's CFI instructions was added. However, the CFI instructions are emitted in the incorrect location. This leads to incorrect CodeGen being generated and possible issues when running a program. According to the ABI, the CFI instructions should be emitted before the signing instruction. This is now done properly. ABI information can be found here: https://github.com/ARM-software/abi-aa/blob/bf0e2c8047c70987165f3e05e571d7836370ade9/aadwarf64/aadwarf64.rst#44call-frame-instructions
As part of FEAT_PAuthLR, a new DWARF Frame Instruction was introduced,
DW_CFA_AARCH64_negate_ra_state_with_pc
. This instructs Libunwind that the PC has been used with the signing instruction. This change includes three commitsDW_CFA_AARCH64_negate_ra_state_with_pc
's requirements to be placed immediately after the signing instruction, this would mean the CFI Instruction location was not consistent with the generated location when not using FEAT_PAuthLR. The commit reverses the changes and makes the location consistent across the different branch protection options. While this does have a code size effect, this is a negligible one.For the ABI information, see here: https://github.com/ARM-software/abi-aa/blob/853286c7ab66048e4b819682ce17f567b77a0291/aadwarf64/aadwarf64.rst#id23