compiler-construction - JIT 编译是如何在运行时实际执行机器码的?

标签 compiler-construction compilation llvm jit machine-code

我了解 JIT 编译的工作原理(在阅读了 this SO question 等资源后)。但是,我仍然想知道它是如何在运行时实际执行机器代码的?

我在操作系统或编译器优化方面没有深厚的背景,也没有直接对机器代码做过任何事情,但我开始探索它。我已经开始玩汇编,看看像 NASM 这样的东西如何获取你的汇编代码并将其编译为机器代码(可执行文件),然后你可以从命令行“调用”它,如 ./my-executable .

但是 JIT 编译器实际上是如何在运行时做到这一点的呢?它是像将机器代码流式传输到 stdin 之类的,还是它是如何工作的?如果您可以提供一个示例或一些伪代码,说明某些程序集(或类似的东西,虽然不像 C 那样高级)可能看起来如何演示基本流程,那也太棒了。

最佳答案

你提到你玩过汇编,所以你知道它是如何工作的,很好。想象一下,您编写了分配缓冲区的代码(例如:在地址 0x75612d39 处)。然后您的代码将程序集操作保存到该缓冲区以从堆栈中弹出一个数字,程序集调用打印函数来打印该数字,然后程序集“返回”。然后将数字 3 压入堆栈,并调用/跳转到地址 0x75612d39。处理器将按照说明打印您的数字,然后再次返回您的代码,并继续。在组装级别,它实际上非常简单。

我不知道任何“真正的”汇编语言,但这里有一个由我知道的字节码拼凑而成的“样本”。这台机器有 2 个字节的指针,字符串 %s位于地址 6a ,以及函数 printf位于地址 1388 .

void myfunc(int a) {
    printf("%s", a);
}

此函数的程序集如下所示:
OP Params OpName     Description
13 82 6a  PushString 82 means string, 6a is the address of "%s"
                     So this function pushes a pointer to "%s" on the stack.
13 83 00  PushInt    83 means integer, 00 means the one on the top of the stack.
                     So this function gets the integer at the top of the stack,
                     And pushes it on the stack again
17 13 88 Call        1388 is printf, so this calls the printf function
03 02    Pop         This pops the two things we pushed back off the stack
02       Return      This returns to the calling code.

所以当你的 JITTER 读入 void myfunc(int a) {printf("%s", a);} ,它为此函数分配内存(例如:在地址 0x75612d39 处),并将这些字节存储在该内存中:13 82 6a 13 83 00 17 13 88 03 02 02 .然后,要调用该函数,它只需跳转/调用地址 0x75612d39 处的函数。

关于compiler-construction - JIT 编译是如何在运行时实际执行机器码的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27627234/

相关文章:

parsing - 执行语义操作时 Ocamlyacc token 不可见

C++:const static DEBUG 和 if 语句,实际的执行时间开销是多少?

c - 为什么简单的程序会占用这么多的存储空间?

linux - 在linux中编译用户空间代码

c++ - LLVM/OpenMP 中的互斥量非常慢

objective-c - 为什么只有 NSLog 警告我使用 NSUInteger 的 %lu 字符串格式说明符?

compiler-construction - Clang 和 OS X Lion 中的默认编译器

Haskell 插件在重新编译文件时给出旧值

c++ - 有什么理由不从可执行文件中删除符号吗?

llvm - 指针所有权语义、附加调试信息和 LLVM 中的 "unsigned"用法