NASM 64位汇编:字符串字母转字母表序号输出乱码排查
问题排查:NASM 64位汇编字母转字母表序号功能实现错误
代码核心错误
- 寄存器滥用:将栈指针寄存器
esp作为临时变量存储字符值,直接破坏栈内存结构,引发读写异常。 - 转换逻辑完全错误:
- 没有按规则计算序号:小写字母转1-26序号的正确计算方式是
字符ASCII值 - 'a' + 1,原代码用xor 0x40属于无意义的位操作,结果完全不对。 - 没有做数值转ASCII字符的处理:序号是1-26的整数,不能直接当作ASCII字符写入输出缓冲区——比如序号13是数值,要输出成文本"13"必须拆成'1'(ASCII 0x31)和'3'(ASCII 0x33)两个字符,直接把数值当字符写必然输出乱码,这也是字符'm'转换后输出'-'的根本原因。
- 没有按规则计算序号:小写字母转1-26序号的正确计算方式是
- 标签重复定义:
.data段和.bss段定义了同名的string标签,汇编时会出现地址冲突,导致读写内存位置错误。 - 系统调用混用:64位程序错误使用32位
int 0x80中断和32位系统调用号,传参规则不匹配,会导致IO输出异常。 - 长度计算错误:原字符串32字节,但转换后单字母可能输出1-2位数字,总长度远大于32字节,固定按32字节输出会截断内容,预分配缓冲区长度不足也会引发内存越界。
- 空格处理错误:遇到空格时写入的是
esp寄存器的值(栈指针地址),不是空格的ASCII码0x20,导致空格位置输出乱码。
修正方案
统一遵循64位Linux系统调用规范,重新实现字符遍历、序号计算、数值转ASCII字符的完整逻辑,修正后的可运行代码如下:
SYS_EXIT equ 60 SYS_WRITE equ 1 STDOUT equ 1 global _start section .text _start: ; 打印提示行"e.\r\n" mov rax, SYS_WRITE mov rdi, STDOUT mov rsi, e_msg mov rdx, e_len syscall ; 打印原始字符串 mov rax, SYS_WRITE mov rdi, STDOUT mov rsi, raw_str mov rdx, raw_len syscall ; 打印换行 mov rax, SYS_WRITE mov rdi, STDOUT mov rsi, line_break mov rdx, 2 syscall ; 初始化转换指针:rsi指向原字符串,rdi指向输出缓冲区 mov rsi, raw_str mov rdi, out_buf xor r9, r9 ; 原字符串遍历计数 convert_loop: cmp r9, raw_len je print_result mov al, [rsi] ; 取当前字符 cmp al, ' ' je handle_space ; 处理字母:计算1-26序号 sub al, 'a' - 1 ; 等价于减96,得到a=1、b=2...z=26 mov bl, 10 xor ah, ah div bl ; al存商(十位数值),ah存余数(个位数值) cmp al, 0 ; 判断是否为两位数 je write_single_digit ; 两位数先写十位字符 add al, '0' mov [rdi], al inc rdi write_single_digit: ; 写个位字符 mov al, ah add al, '0' mov [rdi], al inc rdi ; 移动指针和计数 inc rsi inc r9 jmp convert_loop handle_space: mov byte [rdi], ' ' inc rdi inc rsi inc r9 jmp convert_loop print_result: ; 动态计算转换后字符串长度 mov rdx, rdi sub rdx, out_buf mov rax, SYS_WRITE mov rdi, STDOUT mov rsi, out_buf syscall ; 打印结尾换行 mov rax, SYS_WRITE mov rdi, STDOUT mov rsi, line_break mov rdx, 2 syscall ; 程序退出 mov rax, SYS_EXIT xor rdi, rdi syscall section .data e_msg: db "e.", 0xA,0xD e_len equ $ - e_msg raw_str: db "mostra os objetos e os morfismos" raw_len equ $ - raw_str line_break: db 0xA,0xD section .bss out_buf: resb 128 ; 分配足够缓冲区避免越界
编译运行验证
使用以下命令编译执行:
nasm -f elf64 convert.asm -o convert.o ld convert.o -o convert ./convert
运行输出与预期完全一致:
e. mostra os objetos e os morfismos 13151920181 1519 152105201519 5 1519 1315186919131519
内容的提问来源于stack exchange,提问作者Cesar Lopes
相关产品推荐
相关产品推荐

