拆分SuperH汇编代码至多文件时遇分支/PC相对寻址错误求助
SuperH汇编分支位移溢出问题解决
问题根源
SuperH的bra/bsr属于12位PC相对短分支指令,仅能覆盖±4096字节的地址范围(指令4字节对齐,12位有符号位移×4)。当跨文件调用子程序时,汇编阶段无法确定目标符号的最终地址,无法保证其落在短分支范围内,因此直接触发“displacement overflows 12-bit field”错误;而单文件.include合并大代码后,部分子程序距离调用点超出短分支范围,就会出现“pcrel too far”错误。
具体修正方法
替换短分支为长分支指令
跨文件或远距离调用时,直接使用长分支指令代替短分支:- 用
jsr替代bsr:jsr是24位PC相对长调用指令,支持全地址空间范围的调用,无需担心位移溢出。 - 用
jmp替代bra:如果是无返回的跳转,jmp长跳转指令同样支持全地址范围。
- 用
正确使用寄存器间接分支
若需通过寄存器加载地址调用,不要用bsrf(它仍是PC相对短分支),改用寄存器间接调用/跳转指令:; 加载外部子程序地址到寄存器 mov.l #external_sub, r1 ; 调用寄存器指向的子程序 jsr @r1 ; 跳转(无返回) ; jmp @r1注意:子程序文件中必须用
.global external_sub声明符号为全局可见,main文件可通过.extern external_sub显式声明外部符号。采用多文件汇编+链接的正确流程
- 拆分每个子程序为独立文件,例如
sub.s:.global my_sub my_sub: ; 子程序代码 rts nop - 单独汇编每个文件为目标文件:
sh-elf-as -o main.o main.s sh-elf-as -o sub.o sub.s - 链接所有目标文件生成可执行程序:
sh-elf-ld -o my_program main.o sub.o
链接器会自动处理地址分配,长分支指令可适配任意距离的调用。
- 拆分每个子程序为独立文件,例如
错误点总结
- 用
bsr/bra调用外部子程序:汇编阶段无法确定目标地址范围,短分支指令直接报错,必须换长分支。 - 误用
bsrf:该指令为条件短分支,仍依赖PC相对位移,无法解决远距离调用问题,需改用寄存器间接的jsr @Rn/jmp @Rn。
内容的提问来源于stack exchange,提问作者gfdjjrtiejo
相关产品推荐
相关产品推荐

