如何解决写入可执行内存时避免自修改代码 (SMC) 机器清除
我遇到了一个奇怪的问题,CPU 认为我正在修改当前执行的代码,并反复触发 self-modifying code (SMC) machine clears。
我的(简化的)程序执行以下操作:
- 分配一个可执行缓冲区。
- 将 64 字节的有效负载复制到缓冲区中的某个位置 X。
- 在位置 X 调用有效载荷。
- 返回 2。
... 100'000'000 次迭代。
main.c:
#include <stdint.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
extern void smc(void *bufferPtr,void *bufferEndPtr);
int main()
{
const int BUFFER_LENGTH = 4096;
void *bufferPtr = mmap(0,BUFFER_LENGTH,PROT_READ | PROT_WRITE | PROT_EXEC,MAP_ANONYMOUS | MAP_PRIVATE,0);
void *bufferEndPtr = bufferPtr + BUFFER_LENGTH;
printf("Instruction block buffer: %p,%s\n",bufferPtr,strerror(errno));
smc(bufferPtr,bufferEndPtr);
return 0;
}
smc.asm:
[section .text]
align 64
payload:
ret
%define BUFFER_STEP 64
align 64
[global smc]
; rdi: bufferPtr
; rsi: bufferEndPtr
smc:
push r10
push r11
push r12
mov rax,100_000_000
mov r10,rdi ; r10 points to begin of buffer
mov r11,rdi ; r11 points to current buffer position
mov r12,rsi ; r12 points to end of buffer
.loop:
; Done?
dec rax
je .end
mov rcx,64
mov rdi,r11
lea rsi,[rel payload]
; Store
rep movsb
; Call
call r11
; Move buffer pointer
lea r11,[r11 + BUFFER_STEP]
cmp r11,r12
jb .next
mov r11,r10
.next:
jmp .loop
.end:
pop r12
pop r11
pop r10
ret
编译:
nasm smc.asm -f elf64 -o smc.o
gcc -c main.c -O2 -o main.o
gcc main.o smc.o -o prog
我使用
测量程序的执行时间和MACHINE_CLEARS.SMC
performance counter
sudo perf stat -e r04c3 ./prog
在英特尔酷睿 i7-7567U 上的结果:
BUFFER_LENGTH (字节) |
BUFFER_STEP (字节) |
MACHINE_CLEARS.SMC |
执行时间(秒) |
---|---|---|---|
1 x 4K | 0 | 199'999'982 | 14.53 |
1 x 4K | 64 | 199'999'740 | 14.91 |
256 x 4K | 2048 | 105'550'699 | 7.89 |
256 x 4K | 4096 | 130'573'069 | 9.83 |
尽管我正在移动存储目的地(每次写入不同的位置),但我仍然清除了数百万个 SMC 机器,这导致了巨大的性能损失。
在 store 之前/之后添加各种围栏和/或序列化指令不会产生任何显着的改进。请注意,虽然移位在一定程度上减少了机器清除的次数,但也会导致 call
指令处出现大量分支目标错误预测。
当我使用 4K 缓冲区、0 字节步长、mfence
存储后和 call payload
而不是 call r11
运行相同的程序时,它只需要大约 1.74 秒,即考虑到已执行指令的总数。
是什么导致了如此大量的机器清除,我该如何解决?
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。