@@ -150,6 +150,12 @@ class AArch64AsmPrinter : public AsmPrinter {
150150 // Emit the sequence for BRA/BLRA (authenticate + branch/call).
151151 void emitPtrauthBranch (const MachineInstr *MI);
152152
153+ void emitPtrauthCheckAuthenticatedValue (Register TestedReg,
154+ Register ScratchReg,
155+ AArch64PACKey::ID Key,
156+ bool ShouldTrap,
157+ const MCSymbol *OnFailure);
158+
153159 // Emit the sequence for AUT or AUTPAC.
154160 void emitPtrauthAuthResign (const MachineInstr *MI);
155161
@@ -1719,45 +1725,37 @@ unsigned AArch64AsmPrinter::emitPtrauthDiscriminator(uint16_t Disc,
17191725 return AArch64::X17;
17201726}
17211727
1722- void AArch64AsmPrinter::emitPtrauthAuthResign (const MachineInstr *MI) {
1723- const bool IsAUTPAC = MI->getOpcode () == AArch64::AUTPAC;
1724-
1725- // We can expand AUT/AUTPAC into 3 possible sequences:
1726- // - unchecked:
1727- // autia x16, x0
1728- // pacib x16, x1 ; if AUTPAC
1728+ // / Emits a code sequence to check an authenticated pointer value.
1729+ // /
1730+ // / If OnFailure argument is passed, jump there on check failure instead
1731+ // / of proceeding to the next instruction (only if ShouldTrap is false).
1732+ void AArch64AsmPrinter::emitPtrauthCheckAuthenticatedValue (
1733+ Register TestedReg, Register ScratchReg, AArch64PACKey::ID Key,
1734+ bool ShouldTrap, const MCSymbol *OnFailure) {
1735+ // Insert a sequence to check if authentication of TestedReg succeeded,
1736+ // such as:
17291737 //
17301738 // - checked and clearing:
1731- // mov x17, x0
1732- // movk x17, #disc, lsl #48
1733- // autia x16, x17
1739+ // ; x16 is TestedReg, x17 is ScratchReg
17341740 // mov x17, x16
17351741 // xpaci x17
17361742 // cmp x16, x17
17371743 // b.eq Lsuccess
17381744 // mov x16, x17
17391745 // b Lend
1740- // Lsuccess:
1741- // mov x17, x1
1742- // movk x17, #disc, lsl #48
1743- // pacib x16, x17
1744- // Lend:
1745- // Where we only emit the AUT if we started with an AUT.
1746+ // Lsuccess:
1747+ // ; skipped if authentication failed
1748+ // Lend:
1749+ // ...
17461750 //
17471751 // - checked and trapping:
1748- // mov x17, x0
1749- // movk x17, #disc, lsl #48
1750- // autia x16, x0
17511752 // mov x17, x16
17521753 // xpaci x17
17531754 // cmp x16, x17
17541755 // b.eq Lsuccess
17551756 // brk #<0xc470 + aut key>
1756- // Lsuccess:
1757- // mov x17, x1
1758- // movk x17, #disc, lsl #48
1759- // pacib x16, x17 ; if AUTPAC
1760- // Where the b.eq skips over the trap if the PAC is valid.
1757+ // Lsuccess:
1758+ // ...
17611759 //
17621760 // This sequence is expensive, but we need more information to be able to
17631761 // do better.
@@ -1770,6 +1768,71 @@ void AArch64AsmPrinter::emitPtrauthAuthResign(const MachineInstr *MI) {
17701768 // Either way, we also don't always know whether TBI is enabled or not for
17711769 // the specific target environment.
17721770
1771+ unsigned XPACOpc = getXPACOpcodeForKey (Key);
1772+
1773+ MCSymbol *SuccessSym = createTempSymbol (" auth_success_" );
1774+
1775+ // mov Xscratch, Xtested
1776+ emitMovXReg (ScratchReg, TestedReg);
1777+
1778+ // xpac(i|d) Xscratch
1779+ EmitToStreamer (MCInstBuilder (XPACOpc).addReg (ScratchReg).addReg (ScratchReg));
1780+
1781+ // cmp Xtested, Xscratch
1782+ EmitToStreamer (MCInstBuilder (AArch64::SUBSXrs)
1783+ .addReg (AArch64::XZR)
1784+ .addReg (TestedReg)
1785+ .addReg (ScratchReg)
1786+ .addImm (0 ));
1787+
1788+ // b.eq Lsuccess
1789+ EmitToStreamer (MCInstBuilder (AArch64::Bcc)
1790+ .addImm (AArch64CC::EQ)
1791+ .addExpr (MCSymbolRefExpr::create (SuccessSym, OutContext)));
1792+
1793+ if (ShouldTrap) {
1794+ assert (!OnFailure && " Cannot specify OnFailure with ShouldTrap" );
1795+ // Trapping sequences do a 'brk'.
1796+ // brk #<0xc470 + aut key>
1797+ EmitToStreamer (MCInstBuilder (AArch64::BRK).addImm (0xc470 | Key));
1798+ } else {
1799+ // Non-trapping checked sequences return the stripped result in TestedReg,
1800+ // skipping over success-only code (such as re-signing the pointer) if
1801+ // there is one.
1802+ // Note that this can introduce an authentication oracle (such as based on
1803+ // the high bits of the re-signed value).
1804+
1805+ // FIXME: Can we simply return the AUT result, already in TestedReg?
1806+ // mov Xtested, Xscratch
1807+ emitMovXReg (TestedReg, ScratchReg);
1808+
1809+ if (OnFailure) {
1810+ // b Lend
1811+ EmitToStreamer (
1812+ MCInstBuilder (AArch64::B)
1813+ .addExpr (MCSymbolRefExpr::create (OnFailure, OutContext)));
1814+ }
1815+ }
1816+
1817+ // If the auth check succeeds, we can continue.
1818+ // Lsuccess:
1819+ OutStreamer->emitLabel (SuccessSym);
1820+ }
1821+
1822+ void AArch64AsmPrinter::emitPtrauthAuthResign (const MachineInstr *MI) {
1823+ const bool IsAUTPAC = MI->getOpcode () == AArch64::AUTPAC;
1824+
1825+ // We expand AUT/AUTPAC into a sequence of the form
1826+ //
1827+ // ; authenticate x16
1828+ // ; check pointer in x16
1829+ // Lsuccess:
1830+ // ; sign x16 (if AUTPAC)
1831+ // Lend: ; if not trapping on failure
1832+ //
1833+ // with the checking sequence chosen depending on whether we should check
1834+ // the pointer and whether we should trap on failure.
1835+
17731836 // By default, auth/resign sequences check for auth failures.
17741837 bool ShouldCheck = true ;
17751838 // In the checked sequence, we only trap if explicitly requested.
@@ -1800,8 +1863,6 @@ void AArch64AsmPrinter::emitPtrauthAuthResign(const MachineInstr *MI) {
18001863 uint64_t AUTDisc = MI->getOperand (1 ).getImm ();
18011864 unsigned AUTAddrDisc = MI->getOperand (2 ).getReg ();
18021865
1803- unsigned XPACOpc = getXPACOpcodeForKey (AUTKey);
1804-
18051866 // Compute aut discriminator into x17
18061867 assert (isUInt<16 >(AUTDisc));
18071868 unsigned AUTDiscReg = emitPtrauthDiscriminator (AUTDisc, AUTAddrDisc);
@@ -1824,59 +1885,12 @@ void AArch64AsmPrinter::emitPtrauthAuthResign(const MachineInstr *MI) {
18241885
18251886 MCSymbol *EndSym = nullptr ;
18261887
1827- // Checked sequences do an additional strip-and-compare.
18281888 if (ShouldCheck) {
1829- MCSymbol *SuccessSym = createTempSymbol (" auth_success_" );
1830-
1831- // XPAC has tied src/dst: use x17 as a temporary copy.
1832- // mov x17, x16
1833- emitMovXReg (AArch64::X17, AArch64::X16);
1834-
1835- // xpaci x17
1836- EmitToStreamer (
1837- *OutStreamer,
1838- MCInstBuilder (XPACOpc).addReg (AArch64::X17).addReg (AArch64::X17));
1839-
1840- // cmp x16, x17
1841- EmitToStreamer (*OutStreamer, MCInstBuilder (AArch64::SUBSXrs)
1842- .addReg (AArch64::XZR)
1843- .addReg (AArch64::X16)
1844- .addReg (AArch64::X17)
1845- .addImm (0 ));
1846-
1847- // b.eq Lsuccess
1848- EmitToStreamer (*OutStreamer, MCInstBuilder (AArch64::Bcc)
1849- .addImm (AArch64CC::EQ)
1850- .addExpr (MCSymbolRefExpr::create (
1851- SuccessSym, OutContext)));
1852-
1853- if (ShouldTrap) {
1854- // Trapping sequences do a 'brk'.
1855- // brk #<0xc470 + aut key>
1856- EmitToStreamer (*OutStreamer,
1857- MCInstBuilder (AArch64::BRK).addImm (0xc470 | AUTKey));
1858- } else {
1859- // Non-trapping checked sequences return the stripped result in x16,
1860- // skipping over the PAC if there is one.
1861-
1862- // FIXME: can we simply return the AUT result, already in x16? without..
1863- // ..traps this is usable as an oracle anyway, based on high bits
1864- // mov x17, x16
1865- emitMovXReg (AArch64::X16, AArch64::X17);
1866-
1867- if (IsAUTPAC) {
1868- EndSym = createTempSymbol (" resign_end_" );
1869-
1870- // b Lend
1871- EmitToStreamer (*OutStreamer, MCInstBuilder (AArch64::B)
1872- .addExpr (MCSymbolRefExpr::create (
1873- EndSym, OutContext)));
1874- }
1875- }
1889+ if (IsAUTPAC && !ShouldTrap)
1890+ EndSym = createTempSymbol (" resign_end_" );
18761891
1877- // If the auth check succeeds, we can continue.
1878- // Lsuccess:
1879- OutStreamer->emitLabel (SuccessSym);
1892+ emitPtrauthCheckAuthenticatedValue (AArch64::X16, AArch64::X17, AUTKey,
1893+ ShouldTrap, EndSym);
18801894 }
18811895
18821896 // We already emitted unchecked and checked-but-non-trapping AUTs.
0 commit comments