これは、モード切り替えを行うことで64ビットプロセスで32ビットコードを実行することは可能ですか?の正確な複製である可能性があり ます。、しかし、その質問は1年前のものであり、ソースコードを提供しない回答は1つだけです。もっと詳しい答えを期待しています。
私は64ビットLinuxを実行しています(重要な場合はUbuntu 12.04)。ページを割り当て、64ビットコードを書き込み、そのコードを実行するコードを次に示します。
#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
}
さて、純粋に娯楽的価値のために、私は同じことをしたいと思いますがbuffer
、64ビットコードの代わりに任意の32ビット(ia32)コードを含みます。このページは、CSセグメント記述子のビットをに設定することにより、「長い互換性サブモード」に入ると、64ビットプロセッサで32ビットコードを実行できることを意味しますLMA=1, L=0, D=1
。このセットアップを実行するプロローグ/エピローグで32ビットコードをラップするつもりです。
しかし、Linuxでユーザーモードでこのセットアップを行うことはできますか?(BSD / Darwinの回答も受け入れられます。)これは、私が概念について本当にぼんやりし始めたところです。lcall
解決策には、新しいセグメント記述子をGDT(またはLDTですか?)に追加し、命令を介してそのセグメントに切り替えることが含まれると思います。しかし、それはすべてユーザーモードで実行できますか?
これは、互換性サブモードで正常に実行された場合に4を返し、ロングモードで実行された場合に8を返すサンプル関数です。%rax=4
私の目標は、カーネルモードに陥ることなく(または文書化されたシステムコールを介してのみそうすることなく)、このコードパスを取得して反対側に出てくるように命令ポインターを取得することです。
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
};