Skip to content

Commit a432f11

Browse files
committed
[JITLink][arm64] Support arm64e JIT'd code (initially enabled for MachO only).
Adds two new JITLink passes to create and populate a pointer-signing function that can be called via an allocation-action attached to the LinkGraph: * createEmptyPointerSigningFunction creates a pointer signing function in a custome section, reserving sufficient space for the signing code. It should be run as a post-prune pass (to ensure that memory is reserved prior to allocation). * lowerPointer64AuthEdgesToSigningFunction pass populates the signing function by walking the graph, decoding the ptrauth info (encoded in the edge addend) and writing an instruction sequence to sign all ptrauth fixup locations. rdar://61956998
1 parent 4d6e691 commit a432f11

File tree

4 files changed

+520
-3
lines changed

4 files changed

+520
-3
lines changed

llvm/include/llvm/ExecutionEngine/JITLink/aarch64.h

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,36 @@ enum EdgeKind_aarch64 : Edge::Kind {
3131
///
3232
Pointer64 = Edge::FirstRelocation,
3333

34+
/// An arm64e authenticated pointer relocation. The addend contains a 64-bit
35+
/// struct containing the authentication parameters:
36+
///
37+
/// Addend encoding:
38+
/// int32_t addend;
39+
/// uint16_t diversityData;
40+
/// uint16_t hasAddressDiversity : 1;
41+
/// uint16_t key : 2;
42+
/// uint16_t zeroes : 12;
43+
/// uint16_t authenticated : 1;
44+
///
45+
/// Note: This means that the addend cannot be interpreted as a plain offset
46+
/// prior to lowering.
47+
///
48+
/// Authenticated pointer edges cannot be fixed up directly by JITLink as the
49+
/// signing keys are held in the executing process. They can be removed from
50+
/// the graph by a combination of the createEmptyPointerSigningFunction pass
51+
/// (post-prune) and the lowerPointer64AuthEdgesToSigningFunction pass
52+
/// (pre-fixup). Together these passes construct a signing function that will
53+
/// be run in the executing process to write the signed pointers to the fixup
54+
/// locations.
55+
///
56+
/// Fixup expression:
57+
/// NONE
58+
///
59+
/// Errors:
60+
/// - Failure to handle edges of this kind prior to the fixup phase will
61+
/// result in an unsupported error during the fixup phase.
62+
Pointer64Authenticated,
63+
3464
/// A plain 32-bit pointer value relocation.
3565
///
3666
/// Fixup expression:
@@ -832,6 +862,29 @@ class PLTTableManager : public TableManager<PLTTableManager> {
832862
Section *StubsSection = nullptr;
833863
};
834864

865+
/// Returns the name of the pointer signing function section.
866+
const char *getPointerSigningFunctionSectionName();
867+
868+
/// Creates a pointer signing function section, block, and symbol to reserve
869+
/// space for a signing function for this LinkGraph. Clients should insert this
870+
/// pass in the post-prune phase, and add the paired
871+
/// lowerPointer64AuthEdgesToSigningFunction pass to the pre-fixup phase.
872+
///
873+
/// No new Pointer64Auth edges can be inserted into the graph between when this
874+
/// pass is run and when the pass below runs (since there will not be sufficient
875+
/// space reserved in the signing function to write the signing code for them).
876+
Error createEmptyPointerSigningFunction(LinkGraph &G);
877+
878+
/// Given a LinkGraph containing Pointer64Authenticated edges, transform those
879+
/// edges to Pointer64 and add signing code to the pointer signing function
880+
/// (which must already have been created by the
881+
/// createEmptyPointerSigningFunction pass above).
882+
///
883+
/// This function will add a $__ptrauth_sign section with finalization-lifetime
884+
/// containing an anonymous function that will sign all pointers in the graph.
885+
/// An allocation action will be added to run this function during finalization.
886+
Error lowerPointer64AuthEdgesToSigningFunction(LinkGraph &G);
887+
835888
} // namespace aarch64
836889
} // namespace jitlink
837890
} // namespace llvm

llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ class MachOLinkGraphBuilder_arm64 : public MachOLinkGraphBuilder {
2828
public:
2929
MachOLinkGraphBuilder_arm64(const object::MachOObjectFile &Obj,
3030
SubtargetFeatures Features)
31-
: MachOLinkGraphBuilder(Obj, Triple("arm64-apple-darwin"),
32-
std::move(Features), aarch64::getEdgeKindName),
31+
: MachOLinkGraphBuilder(Obj, getObjectTriple(Obj), std::move(Features),
32+
aarch64::getEdgeKindName),
3333
NumSymbols(Obj.getSymtabLoadCommand().nsyms) {}
3434

3535
private:
@@ -38,6 +38,7 @@ class MachOLinkGraphBuilder_arm64 : public MachOLinkGraphBuilder {
3838
MachOPointer32,
3939
MachOPointer64,
4040
MachOPointer64Anon,
41+
MachOPointer64Authenticated,
4142
MachOPage21,
4243
MachOPageOffset12,
4344
MachOGOTPage21,
@@ -53,6 +54,18 @@ class MachOLinkGraphBuilder_arm64 : public MachOLinkGraphBuilder {
5354
MachONegDelta64,
5455
};
5556

57+
static Triple getObjectTriple(const object::MachOObjectFile &Obj) {
58+
// Get the CPU sub-type from the header.
59+
// jitLink_MachO should already have validated that the buffer is big enough
60+
// to cover a mach_header64 so this is safe.
61+
uint32_t CPUSubType =
62+
*(const support::ulittle32_t *)(Obj.getData().data() + 8);
63+
CPUSubType &= ~MachO::CPU_SUBTYPE_MASK;
64+
if (CPUSubType == MachO::CPU_SUBTYPE_ARM64E)
65+
return Triple("arm64e-apple-darwin");
66+
return Triple("arm64-apple-darwin");
67+
}
68+
5669
static Expected<MachOARM64RelocationKind>
5770
getRelocationKind(const MachO::relocation_info &RI) {
5871
switch (RI.r_type) {
@@ -103,6 +116,10 @@ class MachOLinkGraphBuilder_arm64 : public MachOLinkGraphBuilder {
103116
if (!RI.r_pcrel && !RI.r_extern && RI.r_length == 2)
104117
return MachOPairedAddend;
105118
break;
119+
case MachO::ARM64_RELOC_AUTHENTICATED_POINTER:
120+
if (!RI.r_pcrel && RI.r_extern && RI.r_length == 3)
121+
return MachOPointer64Authenticated;
122+
break;
106123
case MachO::ARM64_RELOC_TLVP_LOAD_PAGE21:
107124
if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
108125
return MachOTLVPage21;
@@ -366,12 +383,15 @@ class MachOLinkGraphBuilder_arm64 : public MachOLinkGraphBuilder {
366383
Kind = aarch64::Pointer32;
367384
break;
368385
case MachOPointer64:
386+
case MachOPointer64Authenticated:
369387
if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
370388
TargetSymbol = TargetSymbolOrErr->GraphSymbol;
371389
else
372390
return TargetSymbolOrErr.takeError();
373391
Addend = *(const ulittle64_t *)FixupContent;
374-
Kind = aarch64::Pointer64;
392+
Kind = *MachORelocKind == MachOPointer64
393+
? aarch64::Pointer64
394+
: aarch64::Pointer64Authenticated;
375395
break;
376396
case MachOPointer64Anon: {
377397
orc::ExecutorAddr TargetAddress(*(const ulittle64_t *)FixupContent);
@@ -493,6 +513,8 @@ class MachOLinkGraphBuilder_arm64 : public MachOLinkGraphBuilder {
493513
return "MachOPointer64";
494514
case MachOPointer64Anon:
495515
return "MachOPointer64Anon";
516+
case MachOPointer64Authenticated:
517+
return "MachOPointer64Authenticated";
496518
case MachOPage21:
497519
return "MachOPage21";
498520
case MachOPageOffset12:
@@ -601,6 +623,14 @@ void link_MachO_arm64(std::unique_ptr<LinkGraph> G,
601623

602624
// Add an in-place GOT/Stubs pass.
603625
Config.PostPrunePasses.push_back(buildTables_MachO_arm64);
626+
627+
// If this is an arm64e graph then add pointer signing passes.
628+
if (G->getTargetTriple().isArm64e()) {
629+
Config.PostPrunePasses.push_back(
630+
aarch64::createEmptyPointerSigningFunction);
631+
Config.PreFixupPasses.push_back(
632+
aarch64::lowerPointer64AuthEdgesToSigningFunction);
633+
}
604634
}
605635

606636
if (auto Err = Ctx->modifyPassConfig(*G, Config))

0 commit comments

Comments
 (0)