gpt4 book ai didi

c++ - ebp + 6 而不是 JIT 编译器中的 +8

转载 作者:塔克拉玛干 更新时间:2023-11-03 08:08:57 24 4
gpt4 key购买 nike

我在 VM 中实现了一个简单的 JIT 编译器,我是为了好玩而编写的(主要是为了学习更多关于语言设计的知识),但我遇到了一些奇怪的行为,也许有人可以告诉我原因。

首先,我为 C 和 C++ 定义了一个 JIT“原型(prototype)”:

#ifdef __cplusplus 
typedef void* (*_JIT_METHOD) (...);
#else
typedef (*_JIT_METHOD) ();
#endif

我有一个 compile() 函数,可以将内容编译成 ASM 并将其保存在内存中的某个位置:

void* compile (void* something)
{
// grab some memory
unsigned char* buffer = (unsigned char*) malloc (1024);

// xor eax, eax
// inc eax
// inc eax
// inc eax
// ret -> eax should be 3
/* WORKS!
buffer[0] = 0x67;
buffer[1] = 0x31;
buffer[2] = 0xC0;
buffer[3] = 0x67;
buffer[4] = 0x40;
buffer[5] = 0x67;
buffer[6] = 0x40;
buffer[7] = 0x67;
buffer[8] = 0x40;
buffer[9] = 0xC3; */

// xor eax, eax
// mov eax, 9
// ret 4 -> eax should be 9
/* WORKS!
buffer[0] = 0x67;
buffer[1] = 0x31;
buffer[2] = 0xC0;
buffer[3] = 0x67;
buffer[4] = 0xB8;
buffer[5] = 0x09;
buffer[6] = 0x00;
buffer[7] = 0x00;
buffer[8] = 0x00;
buffer[9] = 0xC3; */


// push ebp
// mov ebp, esp
// mov eax, [ebp + 6] ; wtf? shouldn't this be [ebp + 8]!?
// mov esp, ebp
// pop ebp
// ret -> eax should be the first value sent to the function
/* WORKS! */
buffer[0] = 0x66;
buffer[1] = 0x55;
buffer[2] = 0x66;
buffer[3] = 0x89;
buffer[4] = 0xE5;
buffer[5] = 0x66;
buffer[6] = 0x66;
buffer[7] = 0x8B;
buffer[8] = 0x45;
buffer[9] = 0x06;
buffer[10] = 0x66;
buffer[11] = 0x89;
buffer[12] = 0xEC;
buffer[13] = 0x66;
buffer[14] = 0x5D;
buffer[15] = 0xC3;

// mov eax, 5
// add eax, ecx
// ret -> eax should be 50
/* WORKS!
buffer[0] = 0x67;
buffer[1] = 0xB8;
buffer[2] = 0x05;
buffer[3] = 0x00;
buffer[4] = 0x00;
buffer[5] = 0x00;
buffer[6] = 0x66;
buffer[7] = 0x01;
buffer[8] = 0xC8;
buffer[9] = 0xC3; */

return buffer;
}

最后我有了程序的主要部分:

int main (int argc, char **args)
{
DWORD oldProtect = (DWORD) NULL;
int i = 667, j = 1, k = 5, l = 0;

// generate some arbitrary function
_JIT_METHOD someFunc = (_JIT_METHOD) compile(NULL);

// windows only
#if defined _WIN64 || defined _WIN32
// set memory permissions and flush CPU code cache
VirtualProtect(someFunc,1024,PAGE_EXECUTE_READWRITE, &oldProtect);
FlushInstructionCache(GetCurrentProcess(), someFunc, 1024);
#endif

// this asm just for some debugging/testing purposes
__asm mov ecx, i

// run compiled function (from wherever *someFunc is pointing to)
l = (int)someFunc(i, k);

// did it work?
printf("result: %d", l);

free (someFunc);
_getch();

return 0;
}

正如您所看到的,compile() 函数有几个我运行的测试以确保我得到预期的结果,几乎一切正常,但我有一个问题...

在大多数教程或文档资源中,要获取传递的函数的第一个值(在整数的情况下),您可以执行 [ebp+8],第二个 [ebp+12 ] 等等。出于某种原因,我必须执行 [ebp+6] 然后 [ebp+10] 等等。谁能告诉我为什么?

最佳答案

您的操作码看起来很可疑:它们充满了 0x660x67 地址/数据大小覆盖前缀,(在 32 位代码段中)将变为 32位操作转换为 16 位操作。例如

buffer[0] = 0x66;
buffer[1] = 0x55;
buffer[2] = 0x66;
buffer[3] = 0x89;
buffer[4] = 0xE5;
...

push bp
mov bp, sp

而不是

push ebp
mov ebp, esp

(这似乎解释了观察到的行为:插入 bp 将堆栈指针递减 2 而不是 4)。

关于c++ - ebp + 6 而不是 JIT 编译器中的 +8,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3009210/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com