jit汇编程序,使用C函数
jit assembler in C++, using C functions
我正在用C++开发一个简单的JIT汇编系统,但是,我想在这个JIT系统中调用C函数,所以,我的想法。。。我需要命令的指针。。。但是,我不知道我怎么能得到这个。。。
这是我的代码
#include <cstdio>
#include <vector>
#include <windows.h>
int Execute(std::vector<unsigned char> code)
{
int eaxRegister;
unsigned char* func = (unsigned char*)VirtualAlloc( 0, code.size() + 1, 0x1000, 0x40 );
memcpy( func, code.data(), code.size() );
func[code.size()] = 0xC3; // add the ret to the final of code final
CallWindowProc( (WNDPROC)func, 0, 0, 0, 0 );
_asm mov eaxRegister, eax;
VirtualFree( func, code.size() + 1, 0x4000 );
return eaxRegister;
}
int main()
{
std::vector<unsigned char> code;
//mov eax, 10
code.push_back( 0xc7 );
code.push_back( 0xc0 );
code.push_back( 0xa );
code.push_back( 0x0 );
code.push_back( 0x0 );
code.push_back( 0x0 );
//mov ecx, 10
code.push_back( 0xc7 );
code.push_back( 0xc1 );
code.push_back( 0xa );
code.push_back( 0x0 );
code.push_back( 0x0 );
code.push_back( 0x0 );
//add eax, ecx
code.push_back( 0x3 );
code.push_back( 0xc1 );
// push MESSAGE
const char* ohi = "HI";
code.push_back( 0x69 );
code.push_back( *ohi );
// call prinf ?????
code.push_back( 0xe8 );
code.push_back( 0xfff/* offset of printf */ ) ;
// add esp, 4
code.push_back( 0x83 );
code.push_back( 0xc4 );
code.push_back( 0x04 );
code.push_back( 0x0 );
code.push_back( 0x0 );
code.push_back( 0x0 );
int exec = Execute( code );
printf("SUM = %d", exec);
return 0;
}
所以,我的问题是,如何获得在JIT中使用的printf命令的偏移量,或者,如何使用JIT使用C函数???
谢谢Alexandre
printf
(没有parens(将计算为函数printf
的地址,因此您显然想要code.push_back(printf);
编辑:当然,因为您已经将code
定义为一个简单的向量,所以它不会按原样工作。您需要一次推送一个地址的单个字节。这里有一个快速演示,显示将其向后推,然后打印出结果,并显示它与您通过将地址传递给printf并使用%p:转换得到的结果几乎相同
#include <vector>
#include <stdio.h>
#include <iostream>
int main() {
std::vector<unsigned char> code;
auto a = printf;
char *p = (char *) &a;
printf("%pn", printf);
for (int i=0; i<sizeof(a); i++)
code.push_back(*p++);
for (int i=0; i<code.size(); i++)
std::cout << std::hex << (unsigned int)code[i] << " ";
return 0;
}
正如您所看到的,%p一起显示整个指针,而这一次显示一个字节。在Windows(小端序硬件(上,这将导致字节的顺序相反。
正如Jerry所指出的,只需使用函数的名称就可以获得extern "C"
函数的地址。问题是,仅仅把它放在代码流中是没有好处的——你需要生成一个实际的CALL指令。更糟糕的是,x86(0xe8(上的普通CALL指令使用PC相对寻址,这是你不容易使用的,因为你不知道你的代码最终会到达什么地址(最终调用VirtualAlloc
会返回的值(。你可以通过不使用PC相对寻址模式来绕过这一点:
void gen_call(std::vector<unsigned char> &code, void *address) {
// mov eax,address
code.push_back(0xb8);
code.push_back((uint32_t)address & 0xff);
code.push_back(((uint32_t)address >> 8) & 0xff);
code.push_back(((uint32_t)address >> 16) & 0xff);
code.push_back(((uint32_t)address >> 24) & 0xff);
// call eax
code.push_back(0xff);
code.push_back(0xd0);
}
此外,您的"推送消息"代码是错误的——您正在推送消息的第一个字符,但您真正想要的是推送字符串的地址。
我已经解决了这个问题,我通过了使用interpret_cast
这是我的解决方案:
#include <cstdio>
#include <vector>
#include <windows.h>
using namespace std;
class Buffer: public vector<unsigned char>
{
public:
void push_dword(DWORD dw)
{
push_back(dw);
push_back(dw >> 8);
push_back(dw >> 16);
push_back(dw >> 24);
}
void push_ptr(const void *p)
{
push_dword(reinterpret_cast<DWORD>(p));
}
int Execute()
{
char *func = reinterpret_cast<char *>(VirtualAlloc(
0, size() + 1, MEM_COMMIT, PAGE_EXECUTE_READWRITE ));
memcpy( func, data(), size() );
func[size()] = 0xC3; // add the ret to the final of code final
int ret = (*reinterpret_cast<int(*)()>(func))();
VirtualFree( func, 0, MEM_RELEASE );
return ret;
}
};
int main()
{
Buffer code;
// push MESSAGE
const char* ohi = "HIn";
code.push_back( 0x68 );
code.push_ptr( ohi );
// mov eax, printf
code.push_back( 0xb8 );
code.push_ptr( reinterpret_cast<void *>(&printf) );
// call eax
code.push_back( 0xff );
code.push_back( 0xd0 );
// add esp, 4
code.push_back( 0x83 );
code.push_back( 0xc4 );
code.push_back( 0x04 );
int exec = code.Execute();
printf("SUM = %dn", exec);
return 0;
}
相关文章:
- 有没有什么方法可以使用一个函数中定义的常量变量,也可以由c++中同一程序中的其他函数使用
- 使用自定义比较函数使用std::sort()对矢量字符串进行排序时出现问题
- 模板,函数使用错误的构造函数来复制我的对象
- 函数不接受 X 参数,函数使用默认参数
- 在模板函数中推导模板函数(使用C++概念)
- 静态成员函数使用相同的名称时出现模板类型名称错误
- C++ 尝试在不存在的构造函数中引用已删除的函数(使用 rapidJson)
- c++ lambda:柯里和函数:使用按值捕获与按引用捕获返回不同的结果
- 带有自动参数的函数使用 GCC 编译,但不使用 Visual C++ 编译
- 为什么 memcpy() 和其他类似的函数使用汇编?
- 如何释放 googletest ASSERT_THROW语句中的函数使用的资源?
- 有条件地将默认参数传递给函数(使用"?"运算符)
- std::set<Key,Compare,Allocator>::find() 函数使用"<"运算符而不是"=="运算符背后的直觉是什么?
- C++类析构函数使用新值而不是实际值
- lambda 函数使用其参数作为模板参数调用模板函数
- 创建一个函数,该函数使用模板创建类或子类的对象
- 如果函数使用 OPENCV Mat 作为输入,如何编写头文件?
- std::value templated 方法的函数使用 clang 和 g++ 进行编译,但不使用 msvc 进行编译
- 为什么 STL 函数使用节点的颜色来计算 std::map 节点前身
- 如何选择waveIn/waveOut函数C++使用的输入/输出设备