You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

为何ARM64平台GCC编译的可执行文件比x86_64平台更大?

为何ARM64平台GCC编译的可执行文件比x86_64平台更大?

这个问题我自己折腾ARM开发的时候也遇到过,当时也纳闷咋差这么多——都是64位架构,按说大小不该差这么悬殊啊!咱们一条条捋捋可能的原因:

  • 指令集本身的代码密度差异
    ARM64的指令是固定4字节长度的,不管是简单的赋值还是复杂运算,每条指令都占4个字节;但x86_64是变长指令,很多常用的简单操作比如movpush,1个字节就能搞定。就拿你那个Hello World的main函数来说,ARM64的机器码总长度肯定比x86_64的长,小项目里这种差异就特别显眼。

  • 启动初始化代码的差异
    你用GCC编译出来的二进制不是直接从main函数开始的,前面还有glibc的启动代码(也就是_start那段),负责初始化运行环境、设置栈、最终调用main。ARM64的glibc启动实现里,默认加了不少针对ARM硬件的兼容性处理——比如检测CPU支持的扩展指令集、初始化浮点环境,甚至还有一些安全校验逻辑;而x86_64的硬件兼容性更好,启动代码能做得更精简,这部分的大小差距就拉开了。

  • 动态链接相关的结构开销
    动态链接的ELF文件里有PLT(过程链接表)和GOT(全局偏移表),用来处理运行时的符号重定位。ARM64的动态链接机制设计得更保守,默认会预留更多的PLT/GOT条目,而且重定位信息也比x86_64的多。你可以在两个平台分别跑readelf -S命令查看二进制的段信息,一眼就能看到ARM64的这些段比x86_64的大不少。

  • 发行版默认编译选项的差异
    虽然你都是用的gcc foo.c这种默认命令,但Raspberry Pi OS的GCC和Debian x86_64的GCC默认选项可能不一样。比如Raspberry Pi OS的GCC可能默认启用了-fstack-protector-strong这类栈保护特性,或者针对ARMv8-A的特定优化,这些都会给二进制增加额外的代码。你可以分别在两个平台跑gcc -v foo.c,看看输出的默认参数对比一下,就能找到具体差异了。

  • libc库的实现差异
    ARM64版的glibc和x86_64版的代码实现有不小区别。ARM版本为了兼容更多ARM硬件(比如老款树莓派),没有做极致的精简;而x86_64的glibc经过多年优化,代码密度做得很高。这种差异会反映在动态链接的符号引用和重定位信息上,间接让ARM64的二进制变大。

如果你想验证这些原因,或者想缩小ARM64二进制的大小,可以试试这些操作:

  • strip命令去掉两个二进制的符号表,看看大小差距会不会缩小——如果缩小很多,说明符号表占了不少空间;
  • objdump -d反汇编两个二进制,对比main函数和启动代码的长度,能直观看到指令集带来的差异;
  • 要是想优化ARM64二进制的大小,可以试试用-Os选项(专门针对代码大小的优化),或者关闭一些不必要的安全选项(比如-fno-stack-protector),不过后者不推荐在生产环境使用。

总的来说,就是指令集天生的代码密度、启动/库实现的差异,加上发行版默认编译选项的不同,共同导致了这么大的大小差距。这不是你的操作有问题,而是不同架构的默认配置和实现逻辑本来就有区别~

火山引擎 最新活动