使用内联汇编调用rdpkru指令读取PKRU寄存器时为何触发段错误?
问题原因与解决方案
你的段错误主要是因为内联汇编的clobber寄存器列表不完整,加上手动赋值ECX的方式存在编译器优化干扰的风险,具体分析和修正如下:
核心问题
rdpkru指令执行时,除了将PKRU值写入EAX,还会自动清零EDX寄存器。你的代码只在clobber列表中声明了ECX,却没有声明EDX——编译器会默认EDX的值在汇编块执行前后保持不变,若编译器在汇编块前将EDX用于存储其他变量,执行rdpkru后EDX被清零会破坏原有数据,进而导致后续代码逻辑错误,最终触发段错误。
另外,手动用movl $0, %%ecx赋值ECX的方式不够可靠:编译器的优化可能在汇编块执行前修改ECX的值(尽管你用了asm volatile,但仍存在风险)。
修正后的代码
#include <stdint.h> #include <sys/mman.h> #include <stdio.h> static uint32_t pkru; static inline void read__rdpkru_u32(void) { // 用输入约束直接指定ECX为0,同时声明EDX为被修改的寄存器 asm volatile("rdpkru" : "=a"(pkru) : "c"(0) : "edx"); } int main(void) { int pkey = pkey_alloc(0, 0); // 必须检查pkey_alloc的返回值,确认PKU功能可用 if (pkey == -1) { perror("pkey_alloc failed"); return 1; } read__rdpkru_u32(); // 后续处理逻辑 printf("PKRU value: 0x%x\n", pkru); return 0; }
关键修正点
- 用输入约束指定ECX值:通过
"c"(0)告诉编译器将ECX设为0,比手动mov更可靠,能避免编译器优化带来的寄存器干扰。 - 补充EDX到clobber列表:明确告知编译器EDX会被rdpkru修改,避免寄存器数据被意外破坏。
- 检查pkey_alloc返回值:如果pkey_alloc返回-1,说明当前系统不支持PKU(CPU无PKU特性或未开启),此时执行rdpkru会触发无效指令异常,提前检查能避免无意义的错误。
内容的提问来源于stack exchange,提问作者Rihijonk
相关产品推荐
相关产品推荐

