我有一个在内核(2.6.30 x86_64)模式(r0)下运行的示例代码,试图模拟iret。我根据英特尔手册的指导推送变量。但事实证明,在iret指令的位置出现了运行时故障:
一般保护故障:fffc[#]SMP
asm volatile(
"mov %%ss,%%ax nt"
"push %%rax nt"/*ss*/
"push %%rsp nt"/*rsp*/
"pushfq nt"/*rflags*/
"mov %%cs,%%ax nt"
"push %%rax nt"/*cs*/
"mov $._restart_code,%%rax nt"
"push %%rax nt"/*rip*/
"iret nt"/*here is the fault rip!!!!!!*/
"._restart_code:"
"nop" :);
我不确定它是否能解决您的问题,但这里有一些注意事项:
"mov %%cs,%%ax nt"
"push %%rax nt"/*cs*/
您正在更新EAX的低阶字节,因此RAX的高阶字节可能与0不同(不应该)。
"mov $._restart_code,%%rax nt"
这里也一样,您应该断言$._restart_code
是规范形式的
"mov %%ss,%%ax nt"
"push %%rax nt"/*ss*/
"push %%rsp nt"/*rsp*/
没用,因为你回到了相同的特权级别。
错误是rsp在推送后发生了更改。
asm volatile(
"mov %%ss,%%ax nt"
"push %%rax nt"/*ss*/
"push %%rsp nt"/*rsp ##########error here!!!!!!! */
"pushfq nt"/*rflags*/
"mov %%cs,%%ax nt"
"push %%rax nt"/*cs*/
"mov $._restart_code,%%rax nt"
"push %%rax nt"/*rip*/
"iret nt"/*###iretq should be used under 64bit mode*/
"._restart_code:"
"nop" :);
因此,在所有推送指令之前保存rsp。正确的代码是:
asm volatile(
"mov %%rsp,%%rbx nt"
"mov %%ss,%%ax nt"
"push %%rax nt"/*ss*/
"push %%rbx nt"/*rsp*/
"pushfq nt"/*rflags*/
"mov %%cs,%%ax nt"
"push %%rax nt"/*cs*/
"mov $._restart_code,%%rax nt"
"push %%rax nt"/*rip*/
"iretq nt"
"._restart_code:"
"nop" :);
谢谢!!!