福仔 发表于 2023-6-27 12:22

保姆级编译BeaEngine库

本帖最后由 福仔 于 2023-6-27 12:30 编辑

## 起因:
因为要写一个汇编查看器, 所以需要弄一个反汇编库
百度搜索后, 发现这个库还不错, 于是跟着搜到的资料进行编译
《三个反汇编库的简单介绍和使用》 我是跟着这篇文章编译的
然后编译成静态库后, 也出现了帖子里的错误
于是自己鼓捣一下, 发现就是 BEA_ENGINE_STATIC 这个宏的问题
于是自己尝试一下编译, 不依靠CMake

整个编译流程大致的方向
1. 创建静态库项目
2. 把 src\BeaEngine.c 这个文件加入到项目中
3. 编译...

大概的流程就这么简单
但是本帖是保姆级的编译流程, 所以一些细节就都拿出来讲

----
## 1. 创建项目

#### 输入名字选择保存目录后点击创建就行



创建后把几个默认创建的文件删除

## 2. 添加源文件
把 src\BeaEngine.c 这个文件加入到项目中
src\BeaEngine.c 这个文件从哪里来?
可以去github上下载 https://github.com/BeaEngine/beaengine
使用git clone 或者手动下载
然后把 `headers``include` `src` 这3个目录拷贝到你项目下
可以查看帖子结尾我的目录




## 3. 尝试编译
加入后开始尝试第一次编译
报了下面的错误, 这个错误是预编译头的错误, 设置里关闭就行




#### 关闭预编译头



### 第二次尝试编译
又报了下面的错误, 这个是找不到包含文件, 设置里加一下包含目录


### 设置包含目录




### 第三次尝试编译
加入包含目录后再次尝试编译, 报了下面的错误, 这个是安全函数的问题, 预处理器里加上 _CRT_SECURE_NO_WARNINGS 就行



#### 加入 _CRT_SECURE_NO_WARNINGS 宏


### 第四次尝试编译
再次尝试编译, 编译成功了, 但是出现了下面的警告



#### 双击进来看看警告的原因是什么


通过上面的图能看到, 函数的声明多了一个 `BEA_API`, 定义这里没有 `BEA_API`
跳转到 `BEA_API` 的定义位置
```
#if !defined(BEA_ENGINE_STATIC)
      #if defined(BUILD_BEA_ENGINE_DLL)
                #define BEA_API bea__api_export__
      #else
                #define BEA_API bea__api_import__
      #endif
#else
      #define BEA_API
#endif
```
这里可以看到, 如果没有定义 `BEA_ENGINE_STATIC`, 那里面就会根据 `BUILD_BEA_ENGINE_DLL` 这个宏来定义 `BEA_API`
现在 `BEA_ENGINE_STATIC` 没有定义, `BUILD_BEA_ENGINE_DLL` 也没有定义
所以最后是定义了` #define BEA_API bea__api_import__ `
然后再去看 `bea__api_import__` 的定义
```
#   define bea__api_import__                __declspec(dllimport)
```

`bea__api_import__` 定义成了 `__declspec(dllimport)`
所以, 如果不加入 `BEA_ENGINE_STATIC` 的话, 函数声明就变成了
`__declspec(dllimport) int __bea_callspec__ Disasm (PDISASM pMyDisasm);`
而定义是 `int __bea_callspec__ Disasm (PDISASM pMyDisasm);`
所以就出现了DLL 链接不一样的警告
既然知道了原因, 那就加上这个宏 `BEA_ENGINE_STATIC`



### 第五次尝试编译
加入后再次尝试编译, 0警告, 0错误, 完美....

#### 到这里就已经编译完成了, 其实这个编译和CMake编译的结果差不多




## 创建测试项目
下面来创建一个程序测试调用, 因为根据我看的那篇文章报错的是调用程序报错


## 测试程序代码
新建后做好以上配置后, 写上以下代码作为测试程序


```
#include <iostream>
#include <Windows.h>


#include <beaengine/BeaEngine.h>


// 反汇编字节数组
void DisassembleCodeByte(BYTE* ptr, int len)
{
    DISASM Disasm_Info;
    char* end_offset = (char*)ptr + len;
    (void)memset(&Disasm_Info, 0, sizeof(DISASM));
    Disasm_Info.EIP = (UInt64)ptr;
    Disasm_Info.Archi = 0;                      // 1 = 表示反汇编32位 / 0 = 表示反汇编64位
    Disasm_Info.Options = MasmSyntax;         // 指定语法格式 MASM

    while ( !Disasm_Info.Error )
    {
      Disasm_Info.SecurityBlock = (UInt64)end_offset - Disasm_Info.EIP;
      if ( Disasm_Info.SecurityBlock <= 0 )
            break;
      len = Disasm(&Disasm_Info);
      switch ( Disasm_Info.Error )
      {
      case OUT_OF_BLOCK:
            break;
      case UNKNOWN_OPCODE:
            Disasm_Info.EIP += 1;
            Disasm_Info.Error = 0;
            break;
      default:
            printf("%s \n", &Disasm_Info.CompleteInstr);
            Disasm_Info.EIP += len;
      }
    }
}

int main()
{
    int address = 0;
    // 从 &address 这个变量地址开始的位置, 打印100个字节转换成汇编的结果
    DisassembleCodeByte((BYTE*)( &address ), 100);
    std::cout << "Hello World!\n";
}

```


加入包含目录后编译测试调用程序, 然后就出现了文章中提到的错误


根据上面我们说的函数声明那, 如果没有定义 BEA_ENGINE_STATIC 宏
那么函数声明是 `__declspec(dllimport) int __bea_callspec__ Disasm (LPDISASM pDisAsm);` 这样的
我们需要把 `__declspec(dllimport)` 这个去掉
怎么去掉呢? 是不是跟上面一样, 加上 `BEA_ENGINE_STATIC` 这个宏就行了
这里直接加入了


最后再尝试编译运行, 调用成功.....




最后附上工程目录下的文件列表

vethenc 发表于 2023-6-27 13:34

感谢分享,实用教程

不知道改成啥 发表于 2023-6-27 13:59

虽然看不懂,顶上去让更多人看见

moruye 发表于 2023-6-27 17:06

yaoguen 发表于 2023-6-28 12:55

学习了,多谢分享

beerzhong 发表于 2023-7-19 17:31

感谢分享
页: [1]
查看完整版本: 保姆级编译BeaEngine库