栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

如何快速动态加载经常重新生成的C代码?

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

如何快速动态加载经常重新生成的C代码?

您想做的事情是合理的,我正在用MELT(用于扩展GCC的高级领域特定语言;通过使用MELT编写的翻译器本身将MELT编译为C)来做到这一点。

首先,在生成C代码(或许多其他源语言)时,一个好的建议是在内存中保留某种抽象语法树(AST)。因此,首先构建所生成的C代码的整个AST,然后将其作为C语法发出。不要想到没有显式AST的代码生成框架(换句话说,用一堆printf生成C代码是一个维护噩梦,您需要一些中间表示形式)。

其次,生成C代码的主要原因是要利用良好的优化编译器(另一个原因是C的可移植性和普遍性)。如果您不关心所生成代码的性能(TCC将C很快地编译为非常幼稚和慢速的机器代码),则可以使用其他方法,例如,使用某些JIT库,例如Gnu
lightning
(非常快地生成慢速机器)代码),Gnu
Libjit
或ASMJIT(生成的机器代码要好一点),LLVM或GCCJIT(生成的机器代码好,但生成时间可与编译器相比)。

因此,如果您生成C代码并希望其快速运行,那么C代码的编译时间就可以忽略不计(因为您可能会派生一个

gcc -O -fPIC -shared

命令来
foo.so
从您生成的代码中创建一些共享库
foo.c
)。根据经验,生成C代码比编译它(用
gcc-O
)花费的时间少得多。在MELT中,C代码的生成速度比GCC的编译速度快10倍以上(通常快30倍)。但是由C编译器完成的优化是值得的。

发出C代码,将其编译分支为

.so
共享库后,就
dlopen
可以使用。别害羞,我的manydl.c示例演示了在Linux上您可以dlopen大量共享对象(数十万个)。真正的瓶颈是生成的C代码的编译。实际上,您实际上并不需要
dlclose
在Linux上运行(除非您正在编写一个需要运行数月的服务器程序)。一个未使用的共享模块实际上可以保留
dlopen
-ed,并且您大多数时候正在泄漏进程地址空间(这是一种廉价的资源),因为大部分未使用的共享模块都
.so
将被交换掉。
dlopen
因为要快速完成,所以花费时间是C源代码的编译,因为您确实希望优化由C编译器完成。

您可以使用许多其他方法,例如使用字节码解释器并为该字节码生成,使用Common
Lisp(例如Linux上的SBCL,可动态编译为机器代码),LuaJit,Java,metaOcaml等。

正如其他人的建议,你不要在乎写一个C文件的时候,它会停留在文件系统缓存在实践中(另见本)。而且编写它比编译它要快得多,因此保留在内存中不值得麻烦。如果您担心I
/ O时间,请使用一些 tmpfs

附加物

您问

.so
Linux上的库文件可以在运行时重新编译并 重新 加载吗?

当然可以:您应该派生一个命令,从生成的C代码构建库(例如,a

gcc -O -fPIC -shared generated.c -ogenerated.so
,但是您可以间接地做到这一点,例如,通过运行a
make -j
,特别是如果a
generated.so
足够大以使其可以将
generated.c
生成的C
拆分成几个C文件!),然后使用dlopen动态加载您的库(给出了完整的路径,例如
/some/file/path/to/generated.so
,可能还有
RTLD_NOW
它的标志),并且必须使用它
dlsym
来查找内部的相关符号。不要以为
重新
加载(第二次)相同
generated.so
,最好发出一个唯一的
generated1.c
(然后
generated2.c
等…)C文件,然后将其编译为一个
唯一的
generated1.so
(第二次到
generated2.so
等),然后至
dlopen
它(可以完成数十万次)。您可能希望在发出的
generated*.c
文件中包含一些构造函数,这些构造函数将
dlopen
generated*.so

您的基本应用程序应该已经定义了有关dlsym
-ed名称集(通常是函数)以及如何调用它们的约定。它仅应直接在

generated*.so
通过
dlsym
函数的指针中调用函数。在实践中,你将决定例如,每个
generated*.c
定义一个函数
voiddynfoo(int)
,并
intdynbar(int,int)
和使用
dlsym
"dynfoo"
"dynbar"
和调用这些通函数指针(由返回
dlsym
)。你也应该定义如何以及何时这些公约
dynfoo
,并
dynbar
会被调用。您最好将基本应用程序与链接,
-rdynamic
以便
generated*.c
文件可以调用应用程序函数。

希望你

generated*.so
重新定义 现有的
名称。例如,您不想重新定义
malloc
自己,
generated*.c
并希望所有堆分配函数都神奇地使用您的新变体(这可能不起作用,即使这样做也很危险)。

dlclose
除了在应用程序清理和退出时,您可能不会理会动态加载的共享对象(但我完全不会理会
dlclose
)。如果您要
dlclose
动态加载
generated*.so
文件,请确保其中没有使用任何文件:没有指针,甚至没有调用帧中的返回地址。

PS MELT转换器当前将MELT代码的57KLOC转换为C语言的将近1770KLOC。



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/403105.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号