assembly 在64位Linux中,是否可以在同一个可执行文件中同时使用64位和32位指令?

kx5bkwkv  于 2022-11-13  发布在  Linux
关注(0)|答案(1)|浏览(182)

64位CPU(amd64)在兼容模式下支持32位Intel指令。另外,如果ELF头文件显示它是32位可执行文件,则64位Linux安装允许运行包含32位指令的ELF。
我想知道是否有可能在ELF中放入一些汇编指令,在程序运行过程中将CPU切换到32位兼容模式(然后再返回)?如果内核不允许这些汇编指令,是否有可能让内核将一个已经运行的进程切换到32位?
这主要是出于好奇心提出的问题,因为我看不到它的任何用例。

2uluyalo

2uluyalo1#

在长模式和兼容模式之间的切换是通过改变CS来完成的。用户模式代码不能修改描述符表,但是它可以对描述符表中已经存在的代码段执行远跳转或远调用。我认为(例如)在Linux中,所需的兼容模式描述符是存在的。
下面是Linux(Ubuntu)的示例代码。

$ gcc -no-pie switch_mode.c switch_cs.s

交换机模式.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;
}

交换机_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

相关问题