Können Sie den x64-32-Bit-Submodus für lange Kompatibilität außerhalb des Kernel-Modus eingeben?

Dies könnte ein genaues Duplikat von seinIst es möglich, 32-Bit-Code in einem 64-Bit-Prozess auszuführen, indem der Modus umgeschaltet wird?, aber diese Frage stammt aus einem Jahr und hat nur eine Antwort, die keinen Quellcode liefert. Ich hoffe auf genauere Antworten.

Ich verwende 64-Bit-Linux (Ubuntu 12.04, falls es darauf ankommt). Hier ist ein Code, der eine Seite zuweist, einen 64-Bit-Code hineinschreibt und diesen Code ausführt.

#include <assert.h>
#include <malloc.h>
#include <stdio.h>
#include <sys/mman.h>  // mprotect
#include <unistd.h>  // sysconf

unsigned char test_function[] = { 0xC3 };  // RET
int main()
{
    int pagesize = sysconf(_SC_PAGE_SIZE);
    unsigned char *buffer = memalign(pagesize, pagesize);
    void (*func)() = (void (*)())buffer;

    memcpy(buffer, test_function, sizeof test_function);

    // func();  // will segfault 
    mprotect(buffer, pagesize, PROT_EXEC);
    func();  // works fine
}

Jetzt möchte ich nur zur Unterhaltung das Gleiche tun, aber mitbuffer mit beliebigem 32-Bit-Code (ia32) anstelle von 64-Bit-Code.Diese Seite Dies impliziert, dass Sie 32-Bit-Code auf einem 64-Bit-Prozessor ausführen können, indem Sie in den "Long Compatibility Sub-Mode" wechseln, indem Sie die Bits des CS-Segment-Deskriptors auf setzenLMA=1, L=0, D=1. Ich bin bereit, meinen 32-Bit-Code in einen Prolog / Epilog zu packen, der dieses Setup ausführt.

Aberkönnen Ich mache dieses Setup, unter Linux, im Usermode? (BSD / Darwin-Antworten werden ebenfalls akzeptiert.) Hier fange ich an, mich mit den Konzepten zu beschäftigen. Ich denke, die Lösung besteht darin, dem GDT einen neuen Segment-Deskriptor hinzuzufügen (oder ist es der LDT?) Und dann über ein zu diesem Segment zu wechselnlcall Anweisung. Aber kann das alles im Usermode gemacht werden?

Hier ist eine Beispielfunktion, die bei erfolgreicher Ausführung im Kompatibilitäts-Untermodus 4 und bei Ausführung im Langmodus 8 zurückgeben sollte. Mein Ziel ist es, den Befehlszeiger dazu zu bringen, diesen Codepfad zu nehmen und auf die andere Seite zu gelangen%rax=4, ohne jemals in den Kernel-Modus zu wechseln (oder nur über dokumentierte Systemaufrufe).

unsigned char behave_differently_depending_on_processor_mode[] = {
    0x89, 0xE0,  // movl %esp, %eax
    0x56,        // push %{e,r}si
    0x29, 0xE0,  // subl %esp, %eax
    0x5E,        // pop %{e,r}si
    0xC3         // ret
};

Antworten auf die Frage(1)

Ihre Antwort auf die Frage