NASM汇编终端参数获取异常:传入Aa无预期输出的排查与修复
问题分析与修复:NASM汇编命令行参数处理错误
问题描述
我编写的NASM汇编逻辑为:接收一个由两个ASCII字符组成的命令行参数(例如Aa),交换该参数的两个字符得到aA,将其与十六进制值0x6141(对应aA的ASCII编码)比较,若相等则打印预设的Hit信息。但执行./program Aa时无任何预期输出,求问题原因及修复方法。
原汇编代码
section .data NULL equ 0 EXIT_SUCCESS equ 0 SYS_exit equ 60 hit db "Hit! a etiqueta ja se encontra preenchida", 0xA hit_len equ $ - hit section .text global _start _start: mov rdi, [rsp] lea rsi, [rsp + 8] cmp rdi, 1 jle _done mov rbx, [rsi] mov rbx, [rsi + 8] xchg bl, bh cmp rbx, 0x6141 jne _done _print_Hit: xor rax, rax mov rax, 1 mov rdi, 1 mov rsi, hit mov rdx, hit_len syscall _done: ; Finalizar programa mov rax, SYS_exit mov rdi, EXIT_SUCCESS syscall
编译运行命令
┌──(mattandmello㉿MattandMello)-[~/Desktop] └─$ nasm -f elf64 -g -F dwarf program.asm ┌──(mattandmello㉿MattandMello)-[~/Desktop] └─$ gcc program.o biblioteca.o -o program -nostartfiles -fPIE -no-pie -lncurses /usr/bin/ld: warning: validationBitSiml.o: missing .note.GNU-stack section implies executable stack /usr/bin/ld: NOTE: This behaviour is deprecated and will be removed in a future version of the linker ┌──(mattandmello㉿MattandMello)-[~/Desktop] └─$ ./program Aa
问题原因
- 参数内容读取错误:原代码中
mov rbx, [rsi + 8]获取的是argv[1]的指针(字符串的内存地址),而非字符串的实际字符内容,后续交换和比较操作都是基于无效的地址值进行的。 - 冗余无效指令:
mov rbx, [rsi]指令被下一行立即覆盖,无任何实际作用,属于冗余代码。 - 字节序与比较值不匹配:x86_64架构采用小端序存储,输入
Aa的内存布局为低地址存0x41('A')、高地址存0x61('a'),交换后得到的aA对应的16位值为0x4161(小端序),但原代码错误地与大端序的0x6141比较,导致判断失败。
修复方案
- 通过
argv[1]的指针读取字符串的前两个字节到寄存器,而非直接使用指针地址。 - 移除冗余的
mov rbx, [rsi]指令。 - 将比较目标值改为小端序对应的
0x4161,匹配交换后的实际值。
修复后的代码
section .data NULL equ 0 EXIT_SUCCESS equ 0 SYS_exit equ 60 hit db "Hit! a etiqueta ja se encontra preenchida", 0xA hit_len equ $ - hit section .text global _start _start: ; 获取参数个数argc mov rdi, [rsp] ; 获取argv数组起始地址 lea rsi, [rsp + 8] ; 检查是否存在至少一个命令行参数(argc >= 2) cmp rdi, 2 jl _done ; 获取argv[1]的指针(输入参数的字符串地址) mov rbx, [rsi + 8] ; 读取字符串的前两个字节到bx(小端序) mov bx, [rbx] ; 交换两个字符的字节 xchg bl, bh ; 交换后"aA"对应的小端序16位值是0x4161 cmp bx, 0x4161 jne _done _print_Hit: mov rax, 1 ; sys_write系统调用号 mov rdi, 1 ; 标准输出文件描述符 mov rsi, hit ; 要打印的字符串地址 mov rdx, hit_len ; 字符串长度 syscall _done: ; 退出程序 mov rax, SYS_exit mov rdi, EXIT_SUCCESS syscall
验证
使用原编译命令重新编译运行,执行./program Aa即可正常输出预设的Hit信息。
内容的提问来源于stack exchange,提问作者MattandMello
相关产品推荐
相关产品推荐

