GCC是否存在优化遗漏?从.rodata加载16位整数而非立即数存储
GCC优化疑问:为何生成.rodata常量而非直接使用立即数?
相关C代码
#include <stdint.h> extern struct __attribute__((packed)) { uint8_t size; uint8_t pad; uint16_t sec_num; uint16_t offset; uint16_t segment; uint64_t sec_id; } ldap; //uint16_t x __attribute__((aligned(4096))); void kkk() { ldap.size = 16; ldap.pad = 0; //x = 16; }
GCC 12.2编译后的汇编代码
编译参数:-O2/-O3/-Ofast(Ubuntu 22.10通过apt安装的版本)
.globl kkk .type kkk, @function kkk: movzwl .LC0(%rip), %eax movw %ax, ldap(%rip) ret .size kkk, .-kkk .section .rodata.cst2,"aM",@progbits,2 .align 2 .LC0: .byte 16 .byte 0
预期的最优汇编实现
第一种(最理想):
kkk: movw $16, ldap(%rip) ret
第二种(可接受):
kkk: movl $16, %eax movw %ax, ldap(%rip) ret
疑问与解析
1. .rodata中.LC0的作用
.LC0是GCC在只读数据段(.rodata)生成的2字节常量,把size=16和pad=0这两个相邻字节的赋值内容打包成一个16位值,让代码可以通过一次16位内存读写完成两个字段的赋值。
2. 这是否属于GCC的优化遗漏?
是的,这属于优化不够彻底的情况。因为16的十六进制是0x0010,正好对应低字节size=16、高字节pad=0,完全可以直接用立即数$16通过movw指令一次性写入,不需要额外读取.rodata里的常量。
对比来看,原生成的汇编多了一次内存访问,指令总长度也更长;而直接用立即数的版本不仅更高效,代码也更简洁。这应该是GCC在处理packed结构体相邻字节赋值时,没识别到可以直接合并为立即数写入的场景。
内容的提问来源于stack exchange,提问作者untitled
相关产品推荐
相关产品推荐

