C语言程序简单模拟JVM模板解释器、JIT用到的硬编码编织技术

首先,我们调用一个普通函数的代码如下:

#include <stdio.h>

int new();

int main() {
    int obj1 = new();

    printf("obj1=%d\n", obj1);

    return 0;
}

int new() {
    return 16;
}

接着,我们借助 Clion 中 GDB 工具查看函数 new 的反汇编代码:

(gdb) disassemble /mr new
Dump of assembler code for function new:
13	int new() {
   0x000055555555517f <+0>:	f3 0f 1e fa	endbr64 
   0x0000555555555183 <+4>:	55	push   %rbp
   0x0000555555555184 <+5>:	48 89 e5	mov    %rsp,%rbp

14	    return 16;
   0x0000555555555187 <+8>:	b8 10 00 00 00	mov    $0x10,%eax

15	}
=> 0x000055555555518c <+13>:	5d	pop    %rbp
   0x000055555555518d <+14>:	c3	ret    

End of assembler dump.

注意,我这里用的是C语言工程,因为 C++ 中 new 是关键字,那你可能要换个函数名。

接着,我就把汇编编译后的原始字节值存入了以下源码的 asm_code 数组中,

#include <stdio.h>
#include <sys/mman.h>
#include <unistd.h>
#include <memory.h>

int new();

int template_new();

int main() {
    int obj1 = new();
    int obj2 = template_new();

    printf("obj1=%d\n", obj1);
    printf("obj2=%d\n", obj2);

    return 0;
}

int new() {
    return 16;
}

int template_new() {
    typedef int (*p_fun)();

    char asm_code[] = {
            0x55,
            0x48, 0x89, 0xe5,
            0xb8, 0x10, 0x00, 0x00, 0x00,
            0x5d,
            0xc3
    };

    void* temp = mmap(NULL, // 映射区的开始地址,设置NULL或者0表示由系统决定
                      getpagesize(), // 申请的内存大小按照内存页对齐,这里直接调用函数获取内存页大小
                      PROT_READ | PROT_WRITE | PROT_EXEC, // 映射的内存区的权限,可读可写可执行
                      MAP_ANONYMOUS | MAP_PRIVATE, // 映射对象类型
                      -1,
                      0);

    // 将函数机器码写入内存
    memcpy(temp, asm_code, sizeof(asm_code));

    p_fun fun = temp;

    return fun();
}

asm_code 中代码还可以进一步精简。

JVM模板解释器针对的是单个字节码指令的优化;
JIT针对的是热点代码的优化;

posted @   极客子羽  阅读(159)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
点击右上角即可分享
微信分享提示