找回密码
 立即注册
查看: 46|回复: 1

分享一个支持 "死代码消除" 的 SDCC 工具链

[复制链接]
  • 打卡等级:初来乍到
  • 打卡总天数:1
  • 最近打卡:2025-08-30 00:21:02
已绑定手机

0

主题

0

回帖

32

积分

新手上路

积分
32
发表于 4 天前 | 显示全部楼层 |阅读模式

背景

前些日子在 github 闲逛时发现了一个 sdcc+binutils 的工具链,这个工具链很有意思,它使用 sdcc 作为前端将 .c 转换为优化后的 .asm

然后使用 binutils 中的 gas 将 .asm 编译成 .o 文件,最后使用 ld 链接为 elf, 然后使用 objcopy 生成 hex

我突然意识到,这个组合可以完美解决 sdcc 一直以来不支持的 “死代码消除”功能。

何为 “死代码消除”? SDCC 的链接器无法删除掉不使用的函数,比如你有一个 foo.c 文件,里面有 100 个函数,即使你的程序只使用了其中的1个,SDCC 在链接时也会将

剩下的 99 的不使用的函数也链接到最终的 hex 文件中,这样生成的代码尺寸就会很大。

而 binutils 中的 gas 支持 .section 伪指令(这样可以为每一个函数生成一个 .section),ld 是支持 --gc-sections 命令的,这个参数可以用来移除 .o 中未被使用的函数。于是乎开始折腾。。。

折腾过程

当时我浏览的源码仓库是这个:https://github.com/volumit/sdcc_aurix_scr_42

这个仓库包含了一个经过修改的 sdcc 和 binutils 并且提供了编译好的二进制

但是我尝试了一下下载下来的二进制好像用不了,然后我自行编译,也编译失败。而且我检查了一下它使用的是 sdcc 4.2.0 + binutils 2.2 这是很老的版本

竟然这么多坑?想了想还是自己再移植一遍,于是乎开干,经过2个星期的折腾,终于搞定,而且我编译了可用了二进制版本

源码基于 SDCC 4.5.0 最新 + binutils 2.38 最新 版修改

最终的源码仓库:github0null/sdcc-binutils-mcs51: use sdcc+as+ld to build your mcs51 project

可用的二进制:Release sdcc-with-binutils v0.2.1 · github0null/sdcc-binutils-mcs51

效果

使用原版的 SDCC 和 改进后的 SDCC 版本编译 10 个文件,主函数为:

#include "config.h"
#include "delay.h"
#include "soft_uart.h"

#define LED_Toggle() P34 = !P34

void main(void)
{
    while (1)
    {
        LOG("Hello, STC15F104W !");
        LED_Toggle();
        delay_ms(200);
    }
}

代码大小如下:

image.png

可以看到效果达到预期,而且由于它使用了 ld 因此生成的 .map 文件更容易阅读,这比 SDCC 的 linker 生成的 map 清晰多了

image.png

测试套件也全部通过了,证明应该没什么大问题,应该可以正常使用

image.png

用法

1.使用Makefile

基本用法跟 sdcc 差不多,这里有一个示例的 Makefile 片段

需要注意的是 --stack-auto --nooverlay 这两个选项是必选的,而且现在仅支持 --smalllarge model

main.hex: main.o delay.o foo.o
  @echo "link $@"
  $(CC) -mmcs51 --model-small --stack-auto --nooverlay --out-fmt-ihx -Wl,--print-memory-usage -o $@ $^

%.o: %.c | Makefile
  @echo "CC $<"
  @$(CC) -c -mmcs51 --model-small --stack-auto --nooverlay -o $@ $<

2.使用VSCode插件

使用最新的 EIDE 插件可以无缝切换到该工具链

此处还提供了一个项目模板以便快速启动一个 STC8 项目

EIDE Project Templates

image.png

image.png

与原版SDCC不兼容的地方

由于链接器的不同,因此某些功能可能与 sdcc 不太一样

  • 不支持 overlay:所有的局部变量保存到栈,因此必须启用 --stack-auto --nooverlay 参数,否则将编译失败
  • 不支持 medium, huge 模型:目前仅支持 smalllarge 模型
  • 不支持大于 64K 的地址:不支持引用大于的 0xFFFF 的地址,因此也不支持 SFR32
  • 不支持 xstack: 栈只能位于 iram
  • 绝对地址定位:不能使用 __at(xxx)data idata xdata code 进行绝对地址定位,SFR寄存器除外,因为 ld 使用 linker script 进行地址分配。要使用该功能参考下面的 使用方法 小节,或者使用 -Wl,--defsym= 直接定义符号绝对位置
  • 栈空间使用:由于不支持 overlay 功能,因此所有的局部变量和函数参数存储于栈中,这对于 mcs51 是一个挑战,因为即使使用 large 模型,stack 最大剩余大小为 256 - 32 = 224 bytes,因此对于函数调用,不要使用太多的函数参数和嵌套调用,这会加速栈的溢出。
1 喜欢他/她就送朵鲜花吧,赠人玫瑰,手有余香!
回复

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:469
  • 最近打卡:2025-09-02 06:57:11

8

主题

289

回帖

1780

积分

金牌会员

积分
1780
发表于 前天 07:11 | 显示全部楼层
为你的“折腾”点赞谢谢分享
回复

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-9-3 05:19 , Processed in 0.117276 second(s), 59 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表