You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 11:45:21