解决m68k-elf-as的标签操作与字长寻址异常问题
Motorola 68000汇编移植到m68k-elf-gcc的标签问题解决方法
问题1:标签地址的链接期算术运算失效
原asm68k支持对标签地址直接进行除法、按位与、移位等链接期计算(如((((\src)/2)&0xFF00)<<8)),用于DMA硬件配置,但m68k-elf-as会报错提示操作数无效,运行时计算又会浪费68000算力。
复现代码
.section .data variable: .space 2 .section .text label: move.l #(variable/2), %d0 move.l #(variable&0xFF), %d0 move.l #(variable<<8), %d0
错误信息
testprg.s:6: Error: invalid operands (.data and *ABS* sections) for `/' testprg.s:7: Error: invalid operands (.data and *ABS* sections) for `&' testprg.s:8: Error: invalid operands (.data and *ABS* sections) for `<<'
解决方案
GNU汇编器(GAS)默认区分段内符号和绝对符号,跨段符号直接运算会被拦截。要复现asm68k的行为,需用ABSOLUTE()宏将符号转换为绝对地址后再运算:
.section .data variable: .space 2 .section .text label: move.l #(ABSOLUTE(variable)/2), %d0 move.l #(ABSOLUTE(variable)&0xFF), %d0 move.l #(ABSOLUTE(variable)<<8), %d0
ABSOLUTE()会强制将符号解析为绝对内存地址,让链接器可以正常执行算术运算,无需运行时计算。
问题2:label.w字长寻址的重定位错误
使用label.w语法时,链接器报relocation truncated to fit: R_68K_16错误,即使实际相对地址在16位范围内,且在asm68k中正常工作,直接写固定地址又无法适配标签地址变动,部分指令无法用label(%pc)替代。
复现代码
.section .text .org 0xFFE000 /* 假设RAM/地址映射在此位置 */ label: lea label.w, %a0
错误信息
(.text+0xe002): relocation truncated to fit: R_68K_16 against `.text'+e000
注:链接脚本中.text段定义在0xFF0000,故偏移为E000而非FFE000。
解决方案
GAS中lea label.w, %a0会生成针对绝对地址的16位重定位,而链接器会检查符号的绝对地址是否在16位范围内(0~65535),即使相对偏移符合也会报错。解决方法有两种:
- 强制PC相对16位重定位:
改用lea (label,%pc).w, %a0,明确指定使用PC相对寻址的16位偏移,链接器会基于当前指令地址计算相对偏移,只要偏移在-32768~32767范围内就会通过。 - 标记符号为段内局部:
在标签前加.local指令,让GAS将符号视为段内局部符号,自动生成正确的段内16位重定位:.section .text .org 0xFFE000 .local label label: lea label.w, %a0
内容的提问来源于stack exchange,提问作者Minater 247
相关产品推荐
相关产品推荐

