compiler-construction - 为 x86 处理器生成程序集

标签 compiler-construction assembly code-generation x86

我目前正在通过 Andrew Appel 的 Java 现代编译器实现工作,我正在构建低级中间表示。

最初,我决定以 JVM 为目标并忽略所有低级机器的东西,但为了学习我不太了解的东西,我改变了主意。这改变了我的 IR,因为以 JVM 为目标允许我(或多或少)在进行方法调用或构造对象时挥手致意。

Appel 书没有详细介绍任何特定的机器架构,所以我想知道在哪里可以找到我需要知道的一切以走得更远。

我目前知道我需要知道的事情是:

  • 要使用哪个指令集。我有两台可以开发的笔记本电脑;两者都有 Core 2 Duo 处理器。我目前的理解是 x86 处理器大多使用相同的指令集,但它们并不完全相同。
  • 操作系统是否影响编译的代码生成步骤,还是完全依赖于处理器。例如,我知道生成在 32 位和 64 位平台上运行的代码有所不同。
  • 如何组织堆栈帧等。何时使用寄存器与将参数放在堆栈上,调用者保存与被调用者保存,所有这些。我原以为这会与指令集一起描述,但到目前为止我还没有在任何地方看到这个特定的信息。也许我在这里误解了什么?

  • 完全欢迎链接到资源而不是答案。

    最佳答案

    大多数 x86 指令集对所有处理器都是通用的——可以合理地保证,您的处理器都具有相同的指令集,除了 SIMD 指令,这些指令在实现简单的编译器时可能对您不太有用(这些指令通常用于使多媒体应用程序等运行得更快)。指令集列在 Intel's manuals 中——特别是 2A 和 2B 有完整的指令及其行为列表,尽管其他卷值得一看。

    在生成用户空间代码时,操作系统的选择在涉及系统调用时很重要。例如,如果你想让一个程序在 64 位 Linux 上向终端输出一些东西,你需要通过以下方式进行系统调用:

  • 将值 1 加载到寄存器 rax 中以指示这是一个 write 系统调用。
  • 将值 1 加载到寄存器 rdi 中以指示应使用 stdout(1 是 stdout 的文件描述符)
  • 加载要打印的起始地址到寄存器 rsi
  • 将要打印的长度加载到寄存器 rdx
  • 设置寄存器(和内存)后执行 syscall 指令。
  • write 的返回值存储在 rax 中。

    不同的操作系统可能对 write 有不同的系统调用号,可能有不同的传入参数的方式(x86-64 Linux 系统调用总是使用 rdirsirdxr10r8r9 参数, rax 中的系统调用号),并且可能有不同的系统调用。

    Linux 上普通函数调用的约定是相似的——寄存器的顺序是 rdirsirdxrcxr8r9 (所以都是一样的,除了使用 rcx 而不是 r10 ),在堆栈上还有更多的参数和rax 中的返回值。根据 this page ,寄存器 rbprbxr12r15 应该在函数调用之间保留。当然,您可以自由制定自己的约定(除非进行系统调用),但这使得从其他人生成或编写的代码中调用更难。

    关于compiler-construction - 为 x86 处理器生成程序集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2360012/

    相关文章:

    python - Python 是将函数参数加载到寄存器中还是将它们保存在堆栈中?

    compiler-construction - 生成 C/C++ 代码时表达式的关联性和优先级?

    c++ - 将 C++ 代码转换为 SPIM 程序集

    c - 任何将 'char' 作为 'unsigned' 的编译器?

    c - Objective-C 预处理器可用吗?

    assembly - AVR sbi 命令 - 错误 : number must be positive and less than 32

    assembly - 在 ARMv7a 和 Neon 上通过 64 位签名比较来支持 CMGT 的最有效方法是什么?

    scala - 使用 Scala 生成 (PHP-) 代码

    silverlight - 错误 : The following exception occurred creating the MEF composition container

    compiler-construction - 创建编译器 : Learn OCaml or Stick With Java/C/C++