ARM模式下适配uint16_t无符号半字的Stupid Sort汇编代码问题排查
问题解答
1. LDRH后!符号的作用
!是ARM汇编的预索引回写标记,以你写的LDRH R2,[R0,#2]!为例,执行逻辑是:
- 先计算有效地址:
R0 + 2 - 从该地址加载16位半字到R2寄存器,自动零扩展到32位
- 最后把计算出的有效地址
R0 + 2写回R0寄存器,等价于额外执行了一次ADD R0,R0,#2
2. 现有代码的bug排查
你修改的代码存在两个核心错误导致排序异常:
(1)跳转指令不符合无符号数比较逻辑
原来针对int32_t的BLE跳转是有符号数小于等于跳转,不能用于uint16_t无符号数比较,大于0x7FFF的无符号数会被识别为负数,导致比较逻辑完全错误。需要替换为无符号小于等于跳转指令BLS。
(2)交换数据的地址计算错误
执行完带!的LDRH指令后,R0已经被更新为a[i+1]的地址,你现在写的STRH R2,[R0,#2]会把值写到a[i+2]的位置,直接破坏了后续元素的值。正确的交换逻辑应该是写入a[i](地址为R0 - 2)和a[i+1](地址为R0)。
3. 修正后的完整代码
sort: SUB R1,R1,#1 // n = n - 1 ADD R12,R0,#2 // 数组首地址+2,用于判断i是否为0 ADD R1,R0,R1,LSL#1 // 计算数组最后一个元素的地址,每个元素占2字节 L1: LDRH R3,[R0] // 加载a[i]到R3,自动零扩展 LDRH R2,[R0,#2]! // 加载a[i+1]到R2,R0自增2变为a[i+1]的地址 CMP R3,R2 // 比较a[i]和a[i+1] BLS L2 // 无符号小于等于则不需要交换,跳转到L2 STRH R2,[R0,#-2] // 交换:把R2(原a[i+1])写入a[i]的位置(R0-2) STRH R3,[R0] // 把R3(原a[i])写入a[i+1]的位置(R0) CMP R0,R12 // 判断i是否为0 SUBHI R0,R0,#4 // 若i>0,R0回退4字节回到a[i-1]的位置,等价于i-- L2: CMP R0,R1 // 判断是否到达数组末尾 BLT L1 // 未到末尾则继续循环 BX LR
4. 其他疑问解答
- R3、R2的加载顺序不需要交换:R3加载的是
a[i],R2加载的是a[i+1],比较R3 > R2时交换的逻辑完全正确,无需调整。 LDRH默认是零扩展加载,刚好符合uint16_t无符号半字的加载需求,不需要额外处理高位。
内容的提问来源于stack exchange,提问作者chaikataaaaa
相关产品推荐
相关产品推荐

