本帖最后由 jaffer 于 2021-3-28 16:20 编辑
### 背景
很多时候,在移动端的应用都存在动态更新的问题。以前还可以使用动态下发动态库的办法来解决更新。但是现在,iOS 上已经不允许这样,android 上也各种收紧。那么我的一段代码,如何下发到手机端进行运行呢?
有很多办法,例如借助一些脚本语言等。这里我将介绍一种动态下发 llvm bc 的办法。
### LLVM BC
将一段代码编译成 llvm bc 很简单。例如:
[C] 纯文本查看 复制代码 #include <stdio.h>
int k = 1111;
int test(int i) {
int tmp = k + i;
printf("i = %d\n", tmp);
return 22;
}
int main(void)
{
test(55);
printf("Hello world\n");
return 0;
}
要将这段代码编译成 bc 很简单:
[Bash shell] 纯文本查看 复制代码 clang -emit-llvm -c test.c -o test.bc
这段代码即可编译成 bc 代码。bc 代码下发到移动端就没有动态库那么多限制。
### 如何解析 BC
如何运行 BC 呢?LLVM 其实自带了 LLI 去执行。
[C] 纯文本查看 复制代码 ➜ bc git:(master) ✗ lli test.bc
i = 1166
Hello world, ret = 22
但是 LLI 太大了。端侧的解释器肯定不会允许这么大的size。
那么怎么办呢?一种办法就是自己去精简 LLI,这个里面的内容就很错综复杂。另外一种就是自己去写一个 BC 的解释器,毕竟 LLVM BC 的格式都是公开的。
很凑巧,GitHub 上有一个开源的运行 BC 的解释器。VMIR。https://github.com/andoma/vmir
里面详细介绍了它自己写的一个执行 llvm BC 的解释器。
很遗憾的是,它的代码已经很老,解析的 LLVM BC 代码格式也很老,已经不能运行了。
### 改造 VMIR
虽然 VMIR 已经不能运行,但是它的框架还是值得继续借鉴。我们只需要在它的基础上,修改一些关键逻辑,增加对新的LLVM BC 格式的支持,那么也是可以继续运行的。
主要对其的改动如下:
1、增加新的 BLOCK 块解析。
2、为 function 和 global_var 添加新的变量以确定函数名称和变量名称。
3、使用新的 magic number
4、global 以及 Function 的重新解析。
5、增加对 str tab block 的处理(所有的字符串都存储在这个位置)。
修改之后的最新代码: https://github.com/cogbee/vmir-latest
编译出来之后,打下如下:
[C] 纯文本查看 复制代码 ➜ vmir git:(master) ✗ ls -lh | grep vmir
-rwxr-xr-x 1 jaffer staff 332K 12 28 10:21 vmir
只有 332k,当然还可以继续精简,将 wasm 相关的内容也去掉。这么小的size放到移动端应该是没啥大问题的了。
运行的示例如下:
### 缺陷
我只是基于 VMIR 对 LLVM BC 相关的部分进行了简单改造。并不保障完全稳定。
同时 VMIR 存在的一些问题,例如 C++ stl 的不支持等依然存在。
### 最后
有这么一个简易的 bc 解释器,那么是否可以基于这个 vmir 修改指令集(也需要同步改动 llvm clang 编译器),构建自己的虚拟机或解释器对保护端侧敏感的代码呢?
|