64位CPU(amd64)在兼容模式下支持32位Intel指令。另外,如果ELF标头说它是32位可执行文件,则64位Linux安装允许运行包含32位指令的ELF。
我想知道是否可以在ELF内放入一些汇编指令,从而在程序中间将CPU切换为32位兼容模式(然后再返回)。如果内核不允许这些汇编指令,也许有什么方法可以使内核将已经运行的进程切换为32位?
出于好奇,这主要是一个问题,因为我真的看不到任何用例。
通过更改CS在长模式和兼容模式之间切换。用户模式代码无法修改描述符表,但是可以对描述符表中已经存在的代码段执行远跳转或远调用。我认为,例如在Linux中,存在所需的兼容模式描述符。
这是Linux(Ubuntu)的示例代码。建立
$ gcc -no-pie switch_mode.c switch_cs.s
switch_mode.c:
#include <stdlib.h> #include <stdio.h> #include <stdbool.h> extern bool switch_cs(int cs, bool (*f)()); extern bool check_mode(); int main(int argc, char **argv) { int cs = 0x23; if (argc > 1) cs = strtoull(argv[1], 0, 16); printf("switch to CS=%02x\n", cs); bool r = switch_cs(cs, check_mode); if (r) printf("cs=%02x: 64-bit mode\n", cs); else printf("cs=%02x: 32-bit mode\n", cs); return 0; }
switch_cs.s:
.intel_syntax noprefix .code64 .text .globl switch_cs switch_cs: push rbx push rbp mov rbp, rsp sub rsp, 0x18 mov rbx, rsp movq [rbx], offset .L1 mov [rbx+4], edi // Before the lcall, switch to a stack below 4GB. // This assumes that the data segment is below 4GB. mov rsp, offset stack+0xf0 lcall [rbx] // restore rsp to the original stack leave pop rbx ret .code32 .L1: call esi lret .code64 .globl check_mode // returns false for 32-bit mode; true for 64-bit mode check_mode: xor eax, eax // In 32-bit mode, this instruction is executed as // inc eax; test eax, eax test rax, rax setz al ret .data .align 16 stack: .space 0x100