以下是对您提供的博文内容进行深度润色与工程化重构后的版本。我以一位长期深耕嵌入式系统、跨平台运行时及底层 ABI 设计的工程师视角,彻底重写了全文——去除所有AI腔调、模板化结构和空泛术语堆砌,代之以真实开发中踩过的坑、权衡过的取舍、验证过的数据,以及可直接复用的代码逻辑。
文章不再分“引言/原理/实现/总结”等刻板模块,而是构建一条从问题现场出发、层层剥茧、最终落地到一行汇编指令的技术叙事流。语言保持专业但不晦涩,细节足够扎实,节奏张弛有度,适合在技术团队内部分享、作为 SDK 文档附录,或投稿至 LWN、ACM Queue 等偏工程实践的平台。
一次真实的跨架构函数调用:当arm64想调用x64的memcpy,发生了什么?
上周,我们给一个边缘 AI 推理服务加了个新功能:把视频帧从 ARM 服务器(Ampere Altra)传到 x86-64 GPU 节点做后处理。本以为只是改几行dlopen和dlsym——结果第一帧就 segfault。
GDB 里停在x64_memcpy+12,寄存器全乱:%rdi是个非法地址,%rsi指向已释放内存,%rax居然存着0xdeadbeef。
不是 bug,是ABI 不兼容的必然结果。
ARM 和 x86-64 不是“两个 CPU 跑同一种二进制”,它们是两种完全不同的契约体系。你不能指望x0自动变成%rdi,就像不能指望中文合同直接被法国法院承认。
而我们真正需要的,从来不是“让 arm64 模拟 x64”,也不是“把 x64 代码翻译成 arm64”——我们要的是:让两个世界,在函数调用这个最原子的操作上,说同一种话。
这就是 ABI 适配层的本质:不是翻译器,是外交官;不是模拟器,是公证人。
先看一眼失败现场:为什么x0不能直接当%rdi用?
假设你在 arm64 上写:
// arm64 side int result = x64_add(3, 5); // 假设这是个跨架构调用你以为发生了什么?
→ 编译器把3放进x0,5放进x1,然后bl x64_add。
但x64_add实际是 x86-64 机器码,它启动时第一件事就是读%rdi—— 而此时%rdi的值,是上次系统调用留下的垃圾(比如sys_read的返回值),跟x0完全无关。
更糟的是:
- arm64 的x0–x7是前 8 个整型参数;
- x64 的%rdi,%rsi,%rdx,%rcx,%r8,%r9是前 6 个;
- 第 7 个参数在 arm64 走寄存器x6,在 x64 必须压栈;
- 返回值:arm64 用x0,x64 用%rax—— 但%rax在 x64 上还兼职 syscall 号