【ARM/RISCV 嵌入式 编译系列 16 -- GCC 进制优化编译的常用方法】
文章目录
- 方法一:给函数加 __attribute__((used)) 强制保留
- 方法二:加 __attribute__((section(".text.jump"))) + 链接脚本强制放入
- 方法三:关闭函数优化和链接时清除未使用代码
- 如果是纯汇编写的(`.S`)
- 最强一招:使用 `KEEP()` 保留段内所有代码
- 验证跳转函数是否真的保留
- 总结
方法一:给函数加 attribute((used)) 强制保留
如果你是用 C 写的(而不是纯汇编),这样做可以让函数即使没被调用也不被优化掉:
__attribute__((used))
void jump_to_ilm() {asm volatile ("lui t0, 0x60000\n""jr t0\n");
}
方法二:加 attribute((section(“.text.jump”))) + 链接脚本强制放入
__attribute__((used, section(".text.jump")))
void jump_to_ilm() {asm volatile ("lui t0, 0x60000\n""jr t0\n");
}
并在链接脚本中加入:
.text : {KEEP(*(.text.jump))*(.text)
}
方法三:关闭函数优化和链接时清除未使用代码
在编译时使用以下选项:
riscv64-elf-gcc -O0 -Wl,--whole-archive -Wl,--no-gc-sections ...
或者最少加 -Wl,--gc-sections
时配合 KEEP()
保住关键段落。
如果是纯汇编写的(.S
)
确保该跳转代码出现在 _start
或其他被链接器引用的地方,否则链接器仍可能把你 .text
中的符号扔掉。
例如:
.section .text
.globl _start
_start:lui t0, 0x60000jr t0
_start
是入口符号,必须通过链接脚本 ENTRY(_start)
指定入口,否则编译器也可能不处理。
最强一招:使用 KEEP()
保留段内所有代码
在链接脚本中:
.text : {KEEP(*(.text.boot))KEEP(*(.text.jump))*(.text*)
}
只要你把函数放进 .text.jump
,它就不会被优化掉了。
验证跳转函数是否真的保留
你可以用 objdump
检查 ELF 文件:
riscv64-elf-objdump -d bootrom.elf | less
确认是否有类似:
60000000 <_ilm_main>:...
总结
方法 | 适用情况 | 是否推荐 |
---|---|---|
__attribute__((used)) | 写在 C 代码中 | 推荐 |
KEEP() + section | 写在链接脚本 + C/汇编都适用 | 强力推荐 |
直接放在 _start 中 | 简单项目 | 推荐 |
关闭优化(-O0 , --no-gc-sections ) | 调试期可用 | 有副作用,慎用 |