Switching from 32-bit mode to 64-bit (long mode) on 64-bit Linux

My program is in 32-bit mode, running on an x86_64 processor (64-bit OS, ubuntu 8.04). Is it possible to temporarily switch to 64-bit mode (long mode) in user mode? If so, how?

Background: I am writing a library related to a 32-bit program, so there should be 32-bit mode at startup. However, I would like to use faster x86_64 instructions to improve performance. Therefore, I want to switch to 64-bit mode, do some clean calculations (without interacting with the OS, without the need for 64-bit addressing) and return to 32-bit before returning to the caller.

I found that there are some related but different questions. For instance,

My question is: "Run 64-bit code in a 32-bit program, 64-bit OS"

+4
source share
2 answers

Contrary to other answers, I maintain that, in principle, the short answer is YES . This is most likely not officially supported officially, but it seems to work. At the end of this answer, I present a demo.

Linux-x86_64 32- ( X32 , GDB) CS , 0x23 - 32- 3 , GDT ( 0). 64- : 0x33 - (.. 64-) 3 ( ES, CS, SS, DS 64- ). , - 0x33, CS 64- .

jmp far 64- . , rax, 32-

dec eax
mov eax, 0xfafafafa
ud2
cli ; these two are unnecessary, but leaving them here for fun :)
hlt

, 32- CS ( SIGILL ud2).

( fasm).

format ELF executable
segment readable executable

SYS_EXIT_32BIT=1
SYS_EXIT_64BIT=60
SYS_WRITE=4
STDERR=2

entry $
    mov ax,cs
    cmp ax,0x23 ; 32 bit process on 64 bit kernel has this selector in CS
    jne kernelIs32Bit
    jmp 0x33:start64 ; switch to 64-bit segment
start64:
use64
    mov rax, qword 0xf4fa0b0ffafafafa ; would crash inside this if executed as 32 bit code
    xor rdi,rdi
    mov eax, SYS_EXIT_64BIT
    syscall
    ud2

use32
kernelIs32Bit:
    mov edx, msgLen
    mov ecx, msg
    mov ebx, STDERR
    mov eax, SYS_WRITE
    int 0x80
    dec ebx
    mov eax, SYS_EXIT_32BIT
    int 0x80
msg:
    db "Kernel appears to be 32 bit, can't jump to long mode segment",10
msgLen = $-msg
+11

. , 64bit code ( 64- , , ..), 64 32- . 64- 32- . , gcc unsigned long long uin64_t, 8- x86 x86_64. x86 x86_64. , 64- 32- . , 64- . , 64- 32- . 64- x86_64 32- x86. , . , , - 64- 32-:

#if defined(__LP64__) || defined(_LP64)
# define BUILD_64   1
#endif

:

#ifdef BUILD_64
    printf (" x : %ld,  hex: %lx,\nfmtbinstr_64 (d, 4, \"-\"): %s\n",
            d, d, fmtbinstr_64 (d, 4, "-"));
#else
    printf (" x : %lld,  hex: %llx,\nfmtbinstr_64 (d, 4, \"-\"): %s\n",
            d, d, fmtbinstr_64 (d, 4, "-"));
#endif

, . , , .

-2

All Articles