【发布时间】:2018-12-06 05:23:55
【问题描述】:
最近我一直在阅读有关现代操作系统如何加载可执行程序并为它们分配内存的文章。不幸的是,我只有一本俄语的计算机科学书籍作为参考,所以,如果我错了,请纠正我,但现代操作系统似乎在可执行程序中有不同的部分用于数据和实际的处理器命令。此外,不可能将控制权交给数据部分,即不能将命令存储在那里。也无法在可执行 (text) 部分更改处理器命令。
因此,问题是:现代编译的 CL(SBCL、Clozure-CL)是如何做到的?据我所知,它会创建已编译的 FASL 文件,然后加载它们。但是在编译文件时会创建可见的 FASL 文件。评估函数形式时会发生什么?其次,CL 如何加载它们(在机器/操作系统命令级别)以便为它们分配正确的内存?此外,必须以某种方式卸载旧代码。
PS。当然,这对于解释型语言来说不是问题。对于 JIT 编译器来说,事情变得更加复杂。
【问题讨论】:
-
我不能给出完整的答案,但大致的步骤是:源代码 -> 阅读 -> 宏扩展 -> 编译 -> 链接 -> 加载 -> 运行。处理顶级表单的一种典型方法是将它们编译成一些匿名的顶级函数,该函数被调用以完成加载。例如 GC 和查找符号需要链接。在操作系统中,可以执行和不可以执行的实际分离是内存页面的属性。这在操作系统加载二进制文件时会自动适当地设置。 JIT 编译语言可以使用例如
mprotect来执行此操作。 -
当你说 JIT 编译器的事情更复杂时,你是什么意思? Common Lisp (fasl or not) 编译成原生代码与 JIT 有何不同?
-
@DanRobertson 使用 JIT,事物以中间形式(字节码)存在并编译。最重要的是,JVM,例如,监视代码执行并尝试“动态”优化代码(如何成功是另一个问题)。 CL 路由更加静态。
-
当然可以考虑 fasl 这样的字节码。至少对于某些实现?即使 JavaScript 实现输入源代码,它们是否不被视为 JIT 编译器?我不知道是否有任何跟踪 CL 编译器,但跟踪 JIT 与一般的 JIT 不同
-
@DanRobertson 是的,确实,当我在这种情况下说“JIT”时,我的意思是“跟踪 JIT”。至于 FASL 作为字节码:据我所知,SBCL 和 CCL 生成本机代码,CLISP 没有 JIT。不确定 ECL,我无法访问其他编译器。
标签: compilation common-lisp sbcl language-implementation ccl