我目前正在通过 Andrew Appel 的 Java 现代编译器实现工作,我正在构建低级中间表示。
最初,我决定以 JVM 为目标并忽略所有低级机器的东西,但为了学习我不太了解的东西,我改变了主意。这改变了我的 IR,因为以 JVM 为目标允许我(或多或少)在进行方法调用或构造对象时挥手致意。
Appel 书没有详细介绍任何特定的机器架构,所以我想知道在哪里可以找到我需要知道的一切以走得更远。
我目前知道我需要知道的事情是:
完全欢迎链接到资源而不是答案。
最佳答案
大多数 x86 指令集对所有处理器都是通用的——可以合理地保证,您的处理器都具有相同的指令集,除了 SIMD 指令,这些指令在实现简单的编译器时可能对您不太有用(这些指令通常用于使多媒体应用程序等运行得更快)。指令集列在 Intel's manuals 中——特别是 2A 和 2B 有完整的指令及其行为列表,尽管其他卷值得一看。
在生成用户空间代码时,操作系统的选择在涉及系统调用时很重要。例如,如果你想让一个程序在 64 位 Linux 上向终端输出一些东西,你需要通过以下方式进行系统调用:
rax
中以指示这是一个 write
系统调用。 rdi
中以指示应使用 stdout(1 是 stdout 的文件描述符)rsi
rdx
syscall
指令。 write
的返回值存储在 rax
中。不同的操作系统可能对
write
有不同的系统调用号,可能有不同的传入参数的方式(x86-64 Linux 系统调用总是使用 rdi
、 rsi
、 rdx
、 r10
、 r8
和 r9
参数, rax
中的系统调用号),并且可能有不同的系统调用。Linux 上普通函数调用的约定是相似的——寄存器的顺序是
rdi
、 rsi
、 rdx
、 rcx
、 r8
和 r9
(所以都是一样的,除了使用 rcx
而不是 r10
),在堆栈上还有更多的参数和rax
中的返回值。根据 this page ,寄存器 rbp
、 rbx
和 r12
到 r15
应该在函数调用之间保留。当然,您可以自由制定自己的约定(除非进行系统调用),但这使得从其他人生成或编写的代码中调用更难。
关于compiler-construction - 为 x86 处理器生成程序集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2360012/