ARM macOS汇编程序w4寄存器结果输出异常排查
ARM64 macOS汇编:数组大于指定值元素之和输出错误修复
问题分析
你的程序输出4294967294是因为两个核心问题:
- 求和逻辑完全反转:你需要累加大于
crit的元素,但当前代码的条件判断是当crit <= 当前元素时跳过相加,实际只累加了小于crit的元素。 - 32位到64位的符号扩展错误:
w4是32位有符号寄存器,用mov x1, x4会把它零扩展成64位无符号数,导致负数-2被转换成4294967294(0xFFFFFFFE)。
修复步骤
1. 修正求和逻辑
把cmp w1, w5后的ble skipsum改成bge skipsum:
- 原逻辑:
ble skipsum→ 当crit <= 当前元素时跳过相加(只加小于crit的) - 修正后:
bge skipsum→ 当crit >= 当前元素时跳过相加(只加大于crit的)
数组中大于3的元素是4和9,总和为4+9=13,这才是预期结果。
2. 修复符号扩展问题
把mov x1, x4改成sxtw x1, w4,这样32位有符号数会正确扩展成64位有符号数,避免负数被错误转换。
3. 优化字符串输出长度(可选)
当前write调用固定写20字节,会把buffer里的垃圾数据也输出(比如末尾的%)。可以在int_to_str函数返回字符串起始地址后,计算有效长度再输出,避免冗余内容。
完整修复后的代码
.data crit: .word 3 numsl: .word 6 nums: .word 1, 1, 1, 4, -5, 9 buffer: .space 20 // Буфер для хранения строки числа .text .global _start _start: // Загрузить значение crit adrp x0, crit@PAGE add x0, x0, crit@PAGEOFF ldr w1, [x0] // Загрузить значение numsl adrp x2, numsl@PAGE add x2, x2, numsl@PAGEOFF ldr w2, [x2] // Загрузить адрес nums adrp x3, nums@PAGE add x3, x3, nums@PAGEOFF // Инициализировать сумму (w4) нулем mov w4, 0 sumiteration: ldr w5, [x3], 4 // Загрузить значение из nums и увеличить x3 на 4 cmp w1, w5 // Сравнить crit с текущим элементом nums bge skipsum // 修正:Если crit >= текущий элемент, перейти к skipsum (只加大于crit的) add w4, w4, w5 // Добавить текущий элемент к сумме skipsum: subs w2, w2, 1 // Уменьшить счетчик элементов (w2) на 1 bne sumiteration // Если счетчик не равен нулю, повторить цикл // Преобразование числа в строку adrp x0, buffer@PAGE add x0, x0, buffer@PAGEOFF sxtw x1, w4 // 修正:符号扩展32位w4到64位x1 bl int_to_str // Вывод числа - 计算有效长度 mov x3, x0 // x3 = 字符串起始地址 adrp x4, buffer@PAGE add x4, x4, buffer@PAGEOFF add x4, x4, #20 // x4 = buffer末尾地址 sub x2, x4, x3 // x2 = 有效字符串长度 mov x0, #1 // File descriptor 1 (stdout) mov x1, x3 // 字符串起始地址 mov x16, #4 // Номер системного вызова для write в macOS svc 0 // Вызвать системный вызов // Завершение программы mov x0, #0 // Return code 0 mov x16, #1 // Номер системного вызова для exit в macOS svc 0 // Вызвать системный вызов // Простой алгоритм преобразования числа в строку int_to_str: // x0 - адрес буфера // x1 - число для преобразования mov x2, x1 // Копировать число в x2 mov x3, #10 // Делитель add x0, x0, #19 // Начать с конца буфера mov w4, #'0' // ASCII '0' mov w5, 0 // Флаг для отрицательных чисел cmp x1, 0 bge convert_loop // Если число неотрицательное, пропустить обработку neg x2, x1 // Взять абсолютное значение числа mov w5, 1 // Установить флаг для отрицательных чисел convert_loop: udiv x6, x2, x3 // x6 = x2 / 10 msub x7, x6, x3, x2 // x7 = x2 - x6 * 10 (остаток) add x7, x7, x4 // Преобразовать остаток в символ strb w7, [x0], #-1 // Сохранить символ и перейти назад в буфере mov x2, x6 // x2 = x6 cbz x2, end_conversion // Если x2 == 0, закончить b convert_loop end_conversion: cbz w5, skip_minus // Если число не было отрицательным, пропустить mov w6, #'-' // ASCII '-' strb w6, [x0], #-1 // Сохранить знак минус skip_minus: add x0, x0, #1 // Переместить указатель на начало строки ret
验证结果
用原编译命令重新编译运行后,输出应为13,符合预期。
内容的提问来源于stack exchange,提问作者Andrey
相关产品推荐
相关产品推荐

