AArch64 GNU AS汇编计算器:输入转十进制与校验问题求助
AArch64汇编计算器:输入校验与转换修复
核心问题分析
你的代码存在几个关键错误,导致无法正确校验输入字符和转换数字:
- 错误地将内存地址当作输入字符值进行运算/比较
- 读取输入时的长度与分配的内存不匹配,导致数据溢出
- 未正确使用单字节加载指令读取字符类型数据
具体修复步骤
1. 修复运算符读取与校验
- 读取运算符时,只读取1字节(匹配
.skip 1的内存分配),然后读取换行符丢弃 - 使用
ldrb加载单字节字符,而非ldr(会读取4字节,导致错误数据) - 直接与运算符的ASCII值(如
'+')进行比较,而非错误的地址运算
2. 修复数字输入转换与校验
- 将输入的ASCII字符串转换为整数时,需遍历每个字符,校验是否在
'0'到'9'之间 - 转换逻辑:初始化结果为0,每个字符减
'0'后,结果 = 结果*10 + 该值
3. 修复输入处理逻辑
- 读取输入后,利用
exit_err分支处理非法输入的情况
修改后的完整代码
.global main .section .data op_plus: .byte '+' op_minus: .byte '-' op_mul: .byte '*' op_div: .byte '/' temp: .skip 1 debug_msg1: .asciz "True\n" debug_msg1_len = . - debug_msg1 message_0: .asciz "Hello, World!\n" message_0_len = . - message_0 message_1: .asciz "Enter mode +,-,*,/: " message_1_len = . - message_1 message_2: .asciz "enter the first num: " message_2_len = . - message_2 message_3: .asciz "enter the second num: " message_3_len = . - message_3 message_4: .asciz "result is " message_4_len = . - message_4 err_msg: .asciz "Invalid input!\n" err_msg_len = . - err_msg .section .bss .lcomm num1, 10 .lcomm num2, 10 operator: .skip 1 .section .text main: // 打印欢迎信息 ldr x1, =message_0 ldr x2, =message_0_len bl print // 提示输入运算符 ldr x1, =message_1 ldr x2, =message_1_len bl print // 读取运算符(仅1字节) ldr x1, =operator ldr x2, =1 bl input // 检查是否读取成功 cmp w0, 1 bne exit_err // 读取并丢弃换行符 ldr x1, =temp ldr x2, =1 bl input // 校验运算符 ldrb w0, [x1, -1] // 回到operator地址 cmp w0, '+' beq add_mode cmp w0, '-' beq sub_mode cmp w0, '*' beq mul_mode cmp w0, '/' beq div_mode // 非法运算符,报错退出 bl exit_err add_mode: // 提示输入第一个数字 ldr x1, =message_2 ldr x2, =message_2_len bl print ldr x1, =num1 bl read_and_convert_num mov w19, w0 // 保存第一个数字到w19 // 提示输入第二个数字 ldr x1, =message_3 ldr x2, =message_3_len bl print ldr x1, =num2 bl read_and_convert_num mov w20, w0 // 保存第二个数字到w20 // 计算加法 add w21, w19, w20 bl print_result bl exit // 其他运算模式可参照add_mode实现,此处省略sub/mul/div sub_mode: bl exit_err mul_mode: bl exit_err div_mode: bl exit_err // 读取数字字符串并转换为整数,同时校验输入 // x1: 输入缓冲区地址,返回w0: 转换后的整数 read_and_convert_num: mov w0, 0 // 初始化结果为0 mov x2, x1 // 保存缓冲区起始地址 read_loop: ldrb w3, [x1], 1 // 读取一个字符,地址自增 cmp w3, '\n' // 遇到换行符结束 beq convert_done // 校验是否为数字 cmp w3, '0' blt exit_err cmp w3, '9' bgt exit_err // 转换:result = result*10 + (char - '0') sub w3, w3, '0' mov w4, 10 mul w0, w0, w4 add w0, w0, w3 b read_loop convert_done: ret // 打印结果 print_result: ldr x1, =message_4 ldr x2, =message_4_len bl print // 将整数转换为字符串并打印(此处简化,可实现itoa函数) // 暂用debug输出,实际需实现整数转字符串 ldr x1, =debug_msg1 ldr x2, =debug_msg1_len bl print ret print: mov x0, 1 // STDOUT mov w8, 64 // sys_write svc #0 ret input: mov x0, 0 // STDIN mov w8, 63 // sys_read svc #0 ret exit_err: ldr x1, =err_msg ldr x2, =err_msg_len bl print mov w8, 93 mov x0, 1 // 错误退出码 svc #0 exit: mov w8, 93 mov x0, 0 // 正常退出码 svc #0
对之前尝试方法的解释
sub {register},{register}, '0'无效:你操作的是内存地址(如x1存的是operator的地址),而非输入的字符值,且用了ldr读取4字节而非ldrb读取单字节字符。cmp {register}, {value}无效:同样是把地址当作字符值比较,完全不匹配,需先读取字符到寄存器再比较。- 输入长度设为1无效:未校验read的返回值确认是否读取成功,且未正确处理后续的换行符,导致残留的换行符影响后续输入。
内容的提问来源于stack exchange,提问作者Atonix_
相关产品推荐
相关产品推荐

