代码之家  ›  专栏  ›  技术社区  ›  danben

为x86处理器生成程序集

  •  7
  • danben  · 技术社区  · 15 年前

    我目前正在通过Java中Andrew Appel的现代编译器实现来工作,而我正处于构建低级中间表示的关键时刻。

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

    阿佩尔的书没有详细介绍任何具体的机器架构,所以我想知道在哪里我可以找到我需要知道的一切,以进一步。

    我目前所知道的我需要知道的是:

    • 要使用的指令集。我有两台可以开发的笔记本电脑;两台都有两个双核处理器。我目前的理解是x86处理器大多使用相同的指令集,但它们并不完全相同。

    • 操作系统是否影响编译的代码生成步骤,或者是否完全依赖于处理器。例如,我知道生成在32位平台上运行的代码与在64位平台上运行的代码有些不同。

    • 如何组织堆栈帧等。当使用寄存器与将参数放入堆栈时,调用方保存与被调用方保存,所有这些。我本以为这会和指令集一起描述,但到目前为止,我在任何地方都没有看到这个特定的信息。也许我误解了什么?

    欢迎链接到资源来代替答案。

    3 回复  |  直到 15 年前
        1
  •  5
  •   Michael Williamson    15 年前

    大多数x86指令集对所有处理器都是通用的——这是一个相当安全的赌注,即您的处理器都有相同的指令集,除了在实现简单编译器时可能对您不太有用的SIMD指令(这些指令通常是使用的使多媒体应用程序等运行得更快)。指令集列在 Intel's manuals --2a和2b尤其有一个完整的指令清单和它们的行为,尽管其他的卷值得一看。

    在生成用户空间代码时,操作系统的选择对于系统调用很重要。例如,如果希望程序在64位Linux上向终端输出某些内容,则需要通过以下方式进行系统调用:

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

    返回值来自 存储在 拉克斯 .

    不同的操作系统可能具有不同的系统调用号 ,可能具有不同的传入参数的方式(x86-64 Linux系统调用始终使用 RDI , RSI , RDX , r10 , r8 r9 按此顺序排列参数,系统调用号位于 拉克斯 可能会有不同的系统调用。

    Linux上普通函数调用的约定类似——寄存器的顺序是 RDI , RSI , RDX , rcx , R8 R9 (所以除了使用 RCX 而不是 R10 ,堆栈上有更多参数,返回值位于 拉克斯 . 根据 this page ,寄存器 rbp , rbx r12 高达 r15 应该在函数调用之间保留。当然,您可以自由地编写自己的约定(除非进行系统调用),但这使得从其他人生成或编写的代码调用变得更加困难。

        2
  •  3
  •   Nathan Kitchen    15 年前

    如何堆叠帧等 有组织的。何时使用寄存器与 将参数放入堆栈, 呼叫者保存与被呼叫者保存,全部 那。我本以为这会 与描述 指令集,但到目前为止我还没有 在任何地方都能看到这个特别的信息。 也许我误解了什么 在这里?

    一般来说,这些问题没有正确的答案。您可以使用任何您想要的调用约定……除非您想与其他人的代码进行互操作。为了实现互操作性,编译器对应用程序二进制接口进行标准化。我的理解是 Itanium C++ ABI 近年来已成为一种流行的标准。试着从那里开始。

        3
  •  1
  •   Michael Petrotta user3140870    15 年前

    我不能回答你们所有的问题;但是

    • 基本x86指令集为 跨x86系列兼容 处理器。你不打算 实现任何特定的扩展, 你是吗?
    • 我不认为你的操作系统 或者架构对于代码来说非常重要 一代
    • 默认答案 任何与编译器相关的 Dragon book . 你看过吗 还没有?
    推荐文章