Skip to content

Commit 70f1743

Browse files
Implement a new kcfi_x86_arity feature that encodes an indirect call target's arity (i.e., the number of live-in registers) in the function's __cfi header.
1 parent c1e7e45 commit 70f1743

File tree

4 files changed

+82
-6
lines changed

4 files changed

+82
-6
lines changed

clang/include/clang/Basic/Features.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@ FEATURE(is_trivially_constructible, LangOpts.CPlusPlus)
254254
FEATURE(is_trivially_copyable, LangOpts.CPlusPlus)
255255
FEATURE(is_union, LangOpts.CPlusPlus)
256256
FEATURE(kcfi, LangOpts.Sanitize.has(SanitizerKind::KCFI))
257+
FEATURE(kcfi_x86_arity, LangOpts.Sanitize.has(SanitizerKind::KCFI))
257258
FEATURE(modules, LangOpts.Modules)
258259
FEATURE(safe_stack, LangOpts.Sanitize.has(SanitizerKind::SafeStack))
259260
FEATURE(shadow_call_stack,

llvm/lib/Target/X86/X86AsmPrinter.cpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,8 +181,26 @@ void X86AsmPrinter::emitKCFITypeId(const MachineFunction &MF) {
181181
// Embed the type hash in the X86::MOV32ri instruction to avoid special
182182
// casing object file parsers.
183183
EmitKCFITypePadding(MF);
184+
185+
Register MovReg = X86::EAX;
186+
const auto &Triple = MF.getTarget().getTargetTriple();
187+
if (Triple.isArch64Bit() && Triple.isOSLinux()) {
188+
// Determine the function's arity (i.e., the number of arguments) at the ABI
189+
// level by counting the number of parameters that are passed
190+
// as registers, such as pointers and 64-bit (or smaller) integers. The
191+
// Linux x86-64 ABI allows up to 6 parameters to be passed in GPRs.
192+
// Additional parameters or parameters larger than 64 bits may be passed on
193+
// the stack, in which case the arity is denoted as 7.
194+
const unsigned ArityToRegMap[8] = {X86::EAX, X86::ECX, X86::EDX, X86::EBX,
195+
X86::ESP, X86::EBP, X86::ESI, X86::EDI};
196+
int Arity = MF.getInfo<X86MachineFunctionInfo>()->getArgumentStackSize() > 0
197+
? 7
198+
: MF.getRegInfo().liveins().size();
199+
MovReg = ArityToRegMap[Arity];
200+
}
201+
184202
EmitAndCountInstruction(MCInstBuilder(X86::MOV32ri)
185-
.addReg(X86::EAX)
203+
.addReg(MovReg)
186204
.addImm(MaskKCFIType(Type->getZExtValue())));
187205

188206
if (MAI->hasDotTypeDotSizeDirective()) {

llvm/test/CodeGen/X86/kcfi-patchable-function-prefix.ll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
; CHECK: .p2align 4
44
; CHECK-LABEL: __cfi_f1:
55
; CHECK-COUNT-11: nop
6-
; CHECK-NEXT: movl $12345678, %eax
6+
; CHECK-NEXT: movl $12345678, %ecx
77
; CHECK-LABEL: .Lcfi_func_end0:
88
; CHECK-NEXT: .size __cfi_f1, .Lcfi_func_end0-__cfi_f1
99
; CHECK-LABEL: f1:
@@ -26,7 +26,7 @@ define void @f2(ptr noundef %x) {
2626
; CHECK: .p2align 4
2727
; CHECK-LABEL: __cfi_f3:
2828
; CHECK-NOT: nop
29-
; CHECK-NEXT: movl $12345678, %eax
29+
; CHECK-NEXT: movl $12345678, %ecx
3030
; CHECK-COUNT-11: nop
3131
; CHECK-LABEL: f3:
3232
define void @f3(ptr noundef %x) #0 !kcfi_type !1 {

llvm/test/CodeGen/X86/kcfi.ll

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
; ASM-NEXT: nop
1717
; ASM-NEXT: nop
1818
; ASM-NEXT: nop
19-
; ASM-NEXT: movl $12345678, %eax
19+
; ASM-NEXT: movl $12345678, %ecx
2020
; ASM-LABEL: .Lcfi_func_end0:
2121
; ASM-NEXT: .size __cfi_f1, .Lcfi_func_end0-__cfi_f1
2222
define void @f1(ptr noundef %x) !kcfi_type !1 {
@@ -90,7 +90,7 @@ define void @f4(ptr noundef %x) #0 {
9090

9191
;; Ensure we emit Value + 1 for unwanted values (e.g. endbr64 == 4196274163).
9292
; ASM-LABEL: __cfi_f5:
93-
; ASM: movl $4196274164, %eax # imm = 0xFA1E0FF4
93+
; ASM: movl $4196274164, %ecx # imm = 0xFA1E0FF4
9494
define void @f5(ptr noundef %x) !kcfi_type !2 {
9595
; ASM-LABEL: f5:
9696
; ASM: movl $98693132, %r10d # imm = 0x5E1F00C
@@ -100,7 +100,7 @@ define void @f5(ptr noundef %x) !kcfi_type !2 {
100100

101101
;; Ensure we emit Value + 1 for unwanted values (e.g. -endbr64 == 98693133).
102102
; ASM-LABEL: __cfi_f6:
103-
; ASM: movl $98693134, %eax # imm = 0x5E1F00E
103+
; ASM: movl $98693134, %ecx # imm = 0x5E1F00E
104104
define void @f6(ptr noundef %x) !kcfi_type !3 {
105105
; ASM-LABEL: f6:
106106
; ASM: movl $4196274162, %r10d # imm = 0xFA1E0FF2
@@ -138,10 +138,67 @@ define void @f8() {
138138
ret void
139139
}
140140

141+
%struct.S9 = type { [10 x i64] }
142+
143+
;; Ensure that functions with large (e.g., greater than 8 bytes) arguments passed on the stack are assigned arity=7
144+
; ASM-LABEL: __cfi_f9:
145+
; ASM: movl $199571451, %edi # imm = 0xBE537FB
146+
define dso_local void @f9(ptr noundef byval(%struct.S9) align 8 %s) !kcfi_type !4 {
147+
entry:
148+
ret void
149+
}
150+
151+
;; Ensure that functions with fewer than 7 register arguments and no stack arguments are assigned arity<7
152+
; ASM-LABEL: __cfi_f10:
153+
; ASM: movl $1046421190, %esi # imm = 0x3E5F1EC6
154+
define dso_local void @f10(i32 noundef %v1, i32 noundef %v2, i32 noundef %v3, i32 noundef %v4, i32 noundef %v5, i32 noundef %v6) #0 !kcfi_type !5 {
155+
entry:
156+
%v1.addr = alloca i32, align 4
157+
%v2.addr = alloca i32, align 4
158+
%v3.addr = alloca i32, align 4
159+
%v4.addr = alloca i32, align 4
160+
%v5.addr = alloca i32, align 4
161+
%v6.addr = alloca i32, align 4
162+
store i32 %v1, ptr %v1.addr, align 4
163+
store i32 %v2, ptr %v2.addr, align 4
164+
store i32 %v3, ptr %v3.addr, align 4
165+
store i32 %v4, ptr %v4.addr, align 4
166+
store i32 %v5, ptr %v5.addr, align 4
167+
store i32 %v6, ptr %v6.addr, align 4
168+
ret void
169+
}
170+
171+
;; Ensure that functions with greater than 7 register arguments and no stack arguments are assigned arity=7
172+
; ASM-LABEL: __cfi_f11:
173+
; ASM: movl $1342488295, %edi # imm = 0x5004BEE7
174+
define dso_local void @f11(i32 noundef %v1, i32 noundef %v2, i32 noundef %v3, i32 noundef %v4, i32 noundef %v5, i32 noundef %v6, i32 noundef %v7, i32 noundef %v8) #0 !kcfi_type !6 {
175+
entry:
176+
%v1.addr = alloca i32, align 4
177+
%v2.addr = alloca i32, align 4
178+
%v3.addr = alloca i32, align 4
179+
%v4.addr = alloca i32, align 4
180+
%v5.addr = alloca i32, align 4
181+
%v6.addr = alloca i32, align 4
182+
%v7.addr = alloca i32, align 4
183+
%v8.addr = alloca i32, align 4
184+
store i32 %v1, ptr %v1.addr, align 4
185+
store i32 %v2, ptr %v2.addr, align 4
186+
store i32 %v3, ptr %v3.addr, align 4
187+
store i32 %v4, ptr %v4.addr, align 4
188+
store i32 %v5, ptr %v5.addr, align 4
189+
store i32 %v6, ptr %v6.addr, align 4
190+
store i32 %v7, ptr %v7.addr, align 4
191+
store i32 %v8, ptr %v8.addr, align 4
192+
ret void
193+
}
194+
141195
attributes #0 = { "target-features"="+retpoline-indirect-branches,+retpoline-indirect-calls" }
142196

143197
!llvm.module.flags = !{!0}
144198
!0 = !{i32 4, !"kcfi", i32 1}
145199
!1 = !{i32 12345678}
146200
!2 = !{i32 4196274163}
147201
!3 = !{i32 98693133}
202+
!4 = !{i32 199571451}
203+
!5 = !{i32 1046421190}
204+
!6 = !{i32 1342488295}

0 commit comments

Comments
 (0)