Skip to content

[AArch64][MachO] Add ptrauth ABI version to arm64e cpusubtype. #104650

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

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions llvm/include/llvm/BinaryFormat/MachO.h
Original file line number Diff line number Diff line change
Expand Up @@ -1641,8 +1641,39 @@ enum CPUSubTypeARM64 {
CPU_SUBTYPE_ARM64_ALL = 0,
CPU_SUBTYPE_ARM64_V8 = 1,
CPU_SUBTYPE_ARM64E = 2,

// arm64e uses the capability bits to encode ptrauth ABI information.
// Bit 63 marks the binary as Versioned.
CPU_SUBTYPE_ARM64E_VERSIONED_PTRAUTH_ABI_MASK = 0x80000000,
// Bit 62 marks the binary as using a kernel ABI.
CPU_SUBTYPE_ARM64E_KERNEL_PTRAUTH_ABI_MASK = 0x40000000,
// Bits [59:56] hold the 4-bit ptrauth ABI version.
CPU_SUBTYPE_ARM64E_PTRAUTH_MASK = 0x0f000000,
};

inline int CPU_SUBTYPE_ARM64E_PTRAUTH_VERSION(unsigned ST) {
return (ST & CPU_SUBTYPE_ARM64E_PTRAUTH_MASK) >> 24;
}

inline unsigned
CPU_SUBTYPE_ARM64E_WITH_PTRAUTH_VERSION(unsigned PtrAuthABIVersion,
bool PtrAuthKernelABIVersion) {
assert((PtrAuthABIVersion <= 0xF) &&
"ptrauth abi version must fit in 4 bits");
return CPU_SUBTYPE_ARM64E | CPU_SUBTYPE_ARM64E_VERSIONED_PTRAUTH_ABI_MASK |
(PtrAuthKernelABIVersion ? CPU_SUBTYPE_ARM64E_KERNEL_PTRAUTH_ABI_MASK
: 0) |
(PtrAuthABIVersion << 24);
}

inline unsigned CPU_SUBTYPE_ARM64E_IS_VERSIONED_PTRAUTH_ABI(unsigned ST) {
return ST & CPU_SUBTYPE_ARM64E_VERSIONED_PTRAUTH_ABI_MASK;
}

inline unsigned CPU_SUBTYPE_ARM64E_IS_KERNEL_PTRAUTH_ABI(unsigned ST) {
return ST & CPU_SUBTYPE_ARM64E_KERNEL_PTRAUTH_ABI_MASK;
}

enum CPUSubTypeARM64_32 { CPU_SUBTYPE_ARM64_32_V8 = 1 };

enum CPUSubTypeSPARC { CPU_SUBTYPE_SPARC_ALL = 0 };
Expand All @@ -1668,6 +1699,8 @@ enum CPUSubTypePowerPC {

Expected<uint32_t> getCPUType(const Triple &T);
Expected<uint32_t> getCPUSubType(const Triple &T);
Expected<uint32_t> getCPUSubType(const Triple &T, unsigned PtrAuthABIVersion,
bool PtrAuthKernelABIVersion);

struct x86_thread_state32_t {
uint32_t eax;
Expand Down
18 changes: 18 additions & 0 deletions llvm/lib/BinaryFormat/MachO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,3 +105,21 @@ Expected<uint32_t> MachO::getCPUSubType(const Triple &T) {
return getPowerPCSubType(T);
return unsupported("subtype", T);
}

Expected<uint32_t> MachO::getCPUSubType(const Triple &T,
unsigned PtrAuthABIVersion,
bool PtrAuthKernelABIVersion) {
Expected<uint32_t> Result = MachO::getCPUSubType(T);
if (!Result)
return Result.takeError();
if (*Result != MachO::CPU_SUBTYPE_ARM64E)
return createStringError(
std::errc::invalid_argument,
"ptrauth ABI version is only supported on arm64e.");
if (PtrAuthABIVersion > 0xF)
return createStringError(
std::errc::invalid_argument,
"The ptrauth ABI version needs to fit within 4 bits.");
return CPU_SUBTYPE_ARM64E_WITH_PTRAUTH_VERSION(PtrAuthABIVersion,
PtrAuthKernelABIVersion);
}
13 changes: 12 additions & 1 deletion llvm/lib/MC/MachObjectWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,18 @@ void MachObjectWriter::writeHeader(MachO::HeaderFileType Type,
W.write<uint32_t>(is64Bit() ? MachO::MH_MAGIC_64 : MachO::MH_MAGIC);

W.write<uint32_t>(TargetObjectWriter->getCPUType());
W.write<uint32_t>(TargetObjectWriter->getCPUSubtype());

uint32_t Cpusubtype = TargetObjectWriter->getCPUSubtype();

// Promote arm64e subtypes to always be ptrauth-ABI-versioned, at version 0.
// We never need to emit unversioned binaries.
// And we don't support arbitrary ABI versions (or the kernel flag) yet.
if (TargetObjectWriter->getCPUType() == MachO::CPU_TYPE_ARM64 &&
Cpusubtype == MachO::CPU_SUBTYPE_ARM64E)
Cpusubtype = MachO::CPU_SUBTYPE_ARM64E_WITH_PTRAUTH_VERSION(
/*PtrAuthABIVersion=*/0, /*PtrAuthKernelABIVersion=*/false);

W.write<uint32_t>(Cpusubtype);

W.write<uint32_t>(Type);
W.write<uint32_t>(NumLoadCommands);
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Object/MachOObjectFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ static unsigned getCPUType(const MachOObjectFile &O) {
}

static unsigned getCPUSubType(const MachOObjectFile &O) {
return O.getHeader().cpusubtype;
return O.getHeader().cpusubtype & ~MachO::CPU_SUBTYPE_MASK;
}

static uint32_t
Expand Down
4 changes: 2 additions & 2 deletions llvm/test/MC/AArch64/arm64e-subtype.s
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
; CHECK: 0: c0 03 5f d6 ret

; CHECK: Mach header
; CHECK: magic cputype cpusubtype caps filetype ncmds sizeofcmds flags
; CHECK: MH_MAGIC_64 ARM64 E 0x00 OBJECT 3 256 0x00000000
; CHECK: magic cputype cpusubtype caps filetype ncmds sizeofcmds flags
; CHECK: MH_MAGIC_64 ARM64 E PAC00 OBJECT 3 256 0x00000000

.globl _foo
_foo:
Expand Down
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
RUN: llvm-objdump %p/Inputs/fat.macho-arm64e-kernel-ptrauth-abi -m -p --universal-headers | FileCheck %s

CHECK: Fat headers
CHECK: fat_magic FAT_MAGIC
CHECK: nfat_arch 1
CHECK: architecture arm64e
CHECK: cputype CPU_TYPE_ARM64
CHECK: cpusubtype CPU_SUBTYPE_ARM64E
CHECK: capabilities CPU_SUBTYPE_ARM64E_KERNEL_PTRAUTH_VERSION 5

CHECK: Mach header
CHECK: magic cputype cpusubtype caps filetype ncmds sizeofcmds flags
CHECK: MH_MAGIC_64 ARM64 E PAK05 OBJECT 0 0 0x00000000
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
RUN: llvm-objdump %p/Inputs/fat.macho-arm64e-ptrauth-abi -m -p --universal-headers | FileCheck %s

CHECK: Fat headers
CHECK: fat_magic FAT_MAGIC
CHECK: nfat_arch 1
CHECK: architecture arm64e
CHECK: cputype CPU_TYPE_ARM64
CHECK: cpusubtype CPU_SUBTYPE_ARM64E
CHECK: capabilities CPU_SUBTYPE_ARM64E_PTRAUTH_VERSION 5

CHECK: Mach header
CHECK: magic cputype cpusubtype caps filetype ncmds sizeofcmds flags
CHECK: MH_MAGIC_64 ARM64 E PAC05 OBJECT 0 0 0x00000000
23 changes: 23 additions & 0 deletions llvm/test/tools/llvm-objdump/macho-ptrauth-cpusubtype.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#RUN: sed -e "s,SRC_CPUSUBTYPE,0x80000002,g" %s | yaml2obj -o -| llvm-objdump --macho -p - 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=V0
#RUN: sed -e "s,SRC_CPUSUBTYPE,0x81000002,g" %s | yaml2obj -o -| llvm-objdump --macho -p - 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=V1
#RUN: sed -e "s,SRC_CPUSUBTYPE,0xc1000002,g" %s | yaml2obj -o -| llvm-objdump --macho -p - 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=V1K
#RUN: sed -e "s,SRC_CPUSUBTYPE,0x00000002,g" %s | yaml2obj -o -| llvm-objdump --macho -p - 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=VNONE

# CHECK: Mach header
# CHECK: magic cputype cpusubtype caps filetype ncmds sizeofcmds flags
# V0: MH_MAGIC_64 ARM64 E PAC00 OBJECT 0 0 0x00000000
# V1: MH_MAGIC_64 ARM64 E PAC01 OBJECT 0 0 0x00000000
# V1K: MH_MAGIC_64 ARM64 E PAK01 OBJECT 0 0 0x00000000
# VNONE: MH_MAGIC_64 ARM64 E 0x00 OBJECT 0 0 0x00000000

--- !mach-o
FileHeader:
magic: 0xFEEDFACF
cputype: 0x0100000C
cpusubtype: SRC_CPUSUBTYPE
filetype: 0x00000001
ncmds: 0
sizeofcmds: 0
flags: 0x00000000
reserved: 0x00000000
...
3 changes: 2 additions & 1 deletion llvm/tools/dsymutil/MachOUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -523,7 +523,8 @@ bool generateDsymCompanion(
SymtabStart = alignTo(SymtabStart, 0x1000);

// We gathered all the information we need, start emitting the output file.
Writer.writeHeader(MachO::MH_DSYM, NumLoadCommands, LoadCommandSize, false);
Writer.writeHeader(MachO::MH_DSYM, NumLoadCommands, LoadCommandSize,
/*SubsectionsViaSymbols=*/false);

// Write the load commands.
assert(OutFile.tell() == HeaderSize);
Expand Down
24 changes: 21 additions & 3 deletions llvm/tools/llvm-objdump/MachODump.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2394,8 +2394,16 @@ static void printMachOUniversalHeaders(const object::MachOUniversalBinary *UB,
outs() << " cpusubtype " << (cpusubtype & ~MachO::CPU_SUBTYPE_MASK)
<< "\n";
}
if (verbose &&
(cpusubtype & MachO::CPU_SUBTYPE_MASK) == MachO::CPU_SUBTYPE_LIB64)
if (verbose && cputype == MachO::CPU_TYPE_ARM64 &&
MachO::CPU_SUBTYPE_ARM64E_IS_VERSIONED_PTRAUTH_ABI(cpusubtype)) {
outs() << " capabilities CPU_SUBTYPE_ARM64E_";
if (MachO::CPU_SUBTYPE_ARM64E_IS_KERNEL_PTRAUTH_ABI(cpusubtype))
outs() << "KERNEL_";
outs() << format("PTRAUTH_VERSION %d",
MachO::CPU_SUBTYPE_ARM64E_PTRAUTH_VERSION(cpusubtype))
<< "\n";
} else if (verbose && (cpusubtype & MachO::CPU_SUBTYPE_MASK) ==
MachO::CPU_SUBTYPE_LIB64)
outs() << " capabilities CPU_SUBTYPE_LIB64\n";
else
outs() << " capabilities "
Expand Down Expand Up @@ -8368,7 +8376,17 @@ static void PrintMachHeader(uint32_t magic, uint32_t cputype,
outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
break;
}
if ((cpusubtype & MachO::CPU_SUBTYPE_MASK) == MachO::CPU_SUBTYPE_LIB64) {

if (cputype == MachO::CPU_TYPE_ARM64 &&
MachO::CPU_SUBTYPE_ARM64E_IS_VERSIONED_PTRAUTH_ABI(cpusubtype)) {
const char *Format =
MachO::CPU_SUBTYPE_ARM64E_IS_KERNEL_PTRAUTH_ABI(cpusubtype)
? " PAK%02d"
: " PAC%02d";
outs() << format(Format,
MachO::CPU_SUBTYPE_ARM64E_PTRAUTH_VERSION(cpusubtype));
} else if ((cpusubtype & MachO::CPU_SUBTYPE_MASK) ==
MachO::CPU_SUBTYPE_LIB64) {
outs() << " LIB64";
} else {
outs() << format(" 0x%02" PRIx32,
Expand Down
53 changes: 53 additions & 0 deletions llvm/unittests/BinaryFormat/MachOTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,3 +125,56 @@ TEST(MachOTest, CPUSubType) {
}
#undef CHECK_CPUSUBTYPE
}

TEST(MachOTest, CPUSubTypePtrAuthABI) {
{
Expected<uint32_t> Type = MachO::getCPUSubType(
Triple("x86_64-apple-darwin"), /*PtrAuthABIVersion=*/5,
/*PtrAuthKernelABIVersion=*/false);
ASSERT_EQ(toString(Type.takeError()),
"ptrauth ABI version is only supported on arm64e.");
}
{
Expected<uint32_t> Type = MachO::getCPUSubType(
Triple("arm64e-apple-darwin"), /*PtrAuthABIVersion=*/0x10,
/*PtrAuthKernelABIVersion=*/false);
ASSERT_EQ(toString(Type.takeError()),
"The ptrauth ABI version needs to fit within 4 bits.");
}
{
uint32_t Type = cantFail(MachO::getCPUSubType(
Triple("arm64e-apple-darwin"),
/*PtrAuthABIVersion=*/5, /*PtrAuthKernelABIVersion=*/false));
ASSERT_EQ(Type, 0x85000002U);
}
{
uint32_t Type = cantFail(MachO::getCPUSubType(
Triple("arm64e-apple-darwin"),
/*PtrAuthABIVersion=*/5, /*PtrAuthKernelABIVersion=*/true));
ASSERT_EQ(Type, 0xC5000002U);
}
{
uint32_t Type = cantFail(MachO::getCPUSubType(
Triple("arm64e-apple-darwin"),
/*PtrAuthABIVersion=*/0xF, /*PtrAuthKernelABIVersion=*/false));
ASSERT_EQ(Type, 0x8F000002U);
}
{
uint32_t Type = cantFail(MachO::getCPUSubType(
Triple("arm64e-apple-darwin"),
/*PtrAuthABIVersion=*/0xF, /*PtrAuthKernelABIVersion=*/true));
ASSERT_EQ(Type, 0xCF000002U);
}
{
uint32_t Type = cantFail(MachO::getCPUSubType(
Triple("arm64e-apple-darwin"),
/*PtrAuthABIVersion=*/0, /*PtrAuthKernelABIVersion=*/false));
ASSERT_EQ(Type, 0x80000002U);
}
{
uint32_t Type = cantFail(MachO::getCPUSubType(
Triple("arm64e-apple-darwin"),
/*PtrAuthABIVersion=*/0, /*PtrAuthKernelABIVersion=*/true));
ASSERT_EQ(Type, 0xC0000002U);
}
}
Loading