aot在运行前就已经编译成了机器码可以直接运行
而jit由于不是目标机器语言因此需要虚拟机帮忙做转换工作。
在生成目标文件时,编译器会将代码区的内存页保护措施临时关闭,以便将代码写入到代码区并设置可执行文件权限。
内存页申请内存(提前计算好需要多大内存空间),内存页权限修改为可写 把代码加载到内存中设置可执行权限,然后关闭内存页写的权限。这样之后使用一个指针指向这块内存地址就可以运行这个动态的代码了。
由于jit可以在运行时拿到具体的目标机器信息,因此优化的内容会更多范围会更广;
而aot不知道目标机器信息因此这部分得不到很好的机器优化。
由于aot已经编译成了机器码直接可以运行,所以代码可以直接加载到内存中 的代码区域,操作系统会给这块区域可执行权限让其运行
操作系统会给内存的每个区域都设置权限,对于链接的库来说也会进行编译并生成符号表设置到使用的模块中
使用:模块--》符号表中链接的地址--》真实的内存地址
而jit的加载过程和链接过程和aot不同:由于是运行时编译,因此代码区需要动态申请一块内存然后把指令放到这块内存中,在通过一个指针指向这块内存,调用这个指针,文末图就行这个过程
编译器生成的二进制代码支持重定向,在aot静态编译时由于编译的时候就可以知道引用库里面的符号表信息,因此可以在编译阶段的时候 就进行重定向:重定向指向对应引用库里面的符号信息
对于jit来说,由于是动态加载的代码,所以链接过程也要在运行时动态去做:
把引入的库函数中用到的变量,方法的地址放到符号表中,运行的时候通过符号表找到模块对应的内存地址
运行的时候进行重定向,使用位置无关pic的技术,让代码加载到不同的进城中,这样不同进城最终引用的是不同的地址。这样为了安全性(固定的地址很容易进行攻击)
为什么要先进行映射到不同地址空间在进行重定向?(安全因素,防止对共享的模块进行攻击)
官方定义:
LLVM支持动态链接和地址无关性技术,使得编译生成的代码可以在运行时加载和链接所需的共享库,并解析符号引用。
在LLVM的JIT编译中,所有模块的IR都是先被加载到内存中,然后根据需要动态链接和重定向。 **这种设计可以使得JIT编译的过程更加高效,同时也提供了更好的灵活性,可以在_运行时进行动态的符号解析和链接。**_
每个模块都已经编译成IR存储在内存中,且只需要一次加载统计符号表的过程: **模块_里面的变量方法这些在编译的时候都会存放到符号表中**_。
如果jit生成的代码需要访问这些模块,这些模块会映射到不同的进程空间,然后根据需要在进行映射到对应进城地址空间完成重定向。
利用内存溢出攻击计算机,一段内存是有可执行权限的话,只要黑客写的代码溢出到这块区域,就可以执行这些代码攻击。因此内存w的权限要谨慎设置。
JIT和AOT在编译细节上存在一些区别。JIT需要动态生成目标文件并使用动态链接器进行符号解析和链接,而AOT则是在编译阶段进行符号表的链接,不需要在运行时进行动态生成和链接。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。