0

0

c++如何实现一个简单的JIT c++即时编译器入门【进阶】

尼克

尼克

发布时间:2025-12-30 08:40:45

|

966人浏览过

|

来源于php中文网

原创

C++中的JIT是运行时按需将代码(如表达式、IR)动态编译为机器码并在内存中执行,区别于g++等传统编译器的离线静态编译;其实现可手写x86-64机器码或借助LLVM IR实现。

c++如何实现一个简单的jit c++即时编译器入门【进阶】

什么是C++中的JIT,它和普通编译有什么区别

JIT(Just-In-Time)编译器不是在程序启动前把全部代码编译成机器码,而是在运行时,按需把某段代码(比如一段字符串形式的C++表达式、字节码或自定义IR)动态编译为本地机器指令,并立即执行。它不像g++那样生成可执行文件,而是调用操作系统API(如mmap + mprotect)申请可执行内存,把生成的机器码拷进去,再通过函数指针调用。

关键区别在于:传统编译是“离线+静态”,JIT是“在线+动态+内存中执行”。对C++来说,实现一个“真正能编译C++语法”的JIT极其复杂(需完整前端),所以入门级JIT通常聚焦于:表达式求值简单函数生成(如f(x) = x*x + 2*x + 1)或LLVM IR → 机器码这一环。

从零写一个表达式JIT:三步核心流程

不依赖LLVM也能动手——用纯C++手写一个支持加减乘除和括号的浮点表达式JIT(基于机思想 + x86-64机器码生成):

  • 词法分析:把字符串如"3.14 + x * 2"切分成token(数字、变量名、运算符)
  • 语法树构建:递归下降解析,生成AST(例如二叉树,叶子是数字/变量,节点是+、*等)
  • 机器码生成:遍历AST,按x86-64调用约定(如rdi存x参数),用movsdaddsdmulsd等SSE指令生成代码,写入可执行内存

示例片段(简化):

立即学习C++免费学习笔记(深入)”;

// 假设已分配好 executable_buffer
// 生成 "return x * x" 的机器码(x来自rdi)
uint8_t code[] = {
  0x48, 0x89, 0xf8, // mov rax, rdi
  0xf2, 0x0f, 0x59, 0xc0, // mulsd xmm0, xmm0 (假设x已在xmm0)
  0xc3 // ret
};
memcpy(executable_buffer, code, sizeof(code));
mprotect(executable_buffer, size, PROT_READ | PROT_WRITE | PROT_EXEC);
auto func = reinterpret_cast(executable_buffer);
double result = func(5.0); // → 25.0

更实用的路径:用LLVM构建C++ JIT(推荐入门进阶)

LLVM提供了成熟、跨平台、生产级的JIT基础设施(llvm::orc API)。它不让你手写机器码,而是专注描述计算逻辑(用LLVM IR),由LLVM自动优化并生成机器码。

HIX Translate
HIX Translate

由 ChatGPT 提供支持的智能AI翻译器

下载

典型步骤(C++代码):

  • 初始化LLVM环境:InitializeNativeTarget()InitializeNativeTargetAsmPrinter()
  • 创建JIT引擎:orc::KaleidoscopeJITorc::ThreadSafeContext + orc::ExecutionSession
  • 构建模块:用IRBuilder生成IR(例如创建函数double add(double a, double b)
  • 添加到JIT并获取函数指针:auto sym = jit->lookup("add"); auto f = sym->getAddress();

优势明显:支持循环、条件、函数调用、链接外部符号(如printf)、自动优化(O2)、多模块热重载——这才是工业级JIT的起点。

避坑提醒:权限、ABI与调试

新手常卡在这几个地方:

  • 内存不可执行:Linux/macOS需mprotect(..., PROT_EXEC);Windows用VirtualProtect(..., PAGE_EXECUTE_READWRITE)
  • 调用约定错位:x86-64下整数参数走rdi/rsi/rdx,浮点走xmm0/xmm1;返回值:整数在rax,double在xmm0
  • 缺少符号解析:若JIT函数里调用了sinmalloc,必须提前用addGlobalMapping注册其地址
  • 调试困难:可用llvm::sys::PrintStackTrace()捕获崩溃;生成.bc文件用llc离线反汇编验证IR→asm是否合理

不复杂但容易忽略。

相关专题

更多
java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1434

2023.10.24

Go语言中的运算符有哪些
Go语言中的运算符有哪些

Go语言中的运算符有:1、加法运算符;2、减法运算符;3、乘法运算符;4、除法运算符;5、取余运算符;6、比较运算符;7、位运算符;8、按位与运算符;9、按位或运算符;10、按位异或运算符等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

222

2024.02.23

php三元运算符用法
php三元运算符用法

本专题整合了php三元运算符相关教程,阅读专题下面的文章了解更多详细内容。

84

2025.10.17

登录token无效
登录token无效

登录token无效解决方法:1、检查token的有效期限,如果token已经过期,需要重新获取一个新的token;2、检查token的签名,如果签名不正确,需要重新获取一个新的token;3、检查密钥的正确性,如果密钥不正确,需要重新获取一个新的token;4、使用HTTPS协议传输token,建议使用HTTPS协议进行传输 ;5、使用双因素认证,双因素认证可以提高账户的安全性。

6034

2023.09.14

登录token无效怎么办
登录token无效怎么办

登录token无效的解决办法有检查Token是否过期、检查Token是否正确、检查Token是否被篡改、检查Token是否与用户匹配、清除缓存或Cookie、检查网络连接和服务器状态、重新登录或请求新的Token、联系技术支持或开发人员等。本专题为大家提供token相关的文章、下载、课程内容,供大家免费下载体验。

779

2023.09.14

token怎么获取
token怎么获取

获取token值的方法:1、小程序调用“wx.login()”获取 临时登录凭证code,并回传到开发者服务器;2、开发者服务器以code换取,用户唯一标识openid和会话密钥“session_key”。想了解更详细的内容,可以阅读本专题下面的文章。

1044

2023.12.21

token什么意思
token什么意思

token是一种用于表示用户权限、记录交易信息、支付虚拟货币的数字货币。可以用来在特定的网络上进行交易,用来购买或出售特定的虚拟货币,也可以用来支付特定的服务费用。想了解更多token什么意思的相关内容可以访问本专题下面的文章。

1076

2024.03.01

printf用法大全
printf用法大全

php中文网为大家提供printf用法大全,以及其他printf函数的相关文章、相关下载资源以及各种相关课程,供大家免费下载体验。

72

2023.06.20

俄罗斯搜索引擎Yandex最新官方入口网址
俄罗斯搜索引擎Yandex最新官方入口网址

Yandex官方入口网址是https://yandex.com;用户可通过网页端直连或移动端浏览器直接访问,无需登录即可使用搜索、图片、新闻、地图等全部基础功能,并支持多语种检索与静态资源精准筛选。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

1

2025.12.29

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL 教程
PostgreSQL 教程

共48课时 | 6.2万人学习

Git 教程
Git 教程

共21课时 | 2.3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号