如何在NASM中实现字符串反转输出?
解决NASM 16位汇编字符串反转输出乱码问题
你遇到的这个问题很典型——尝试用16位NASM汇编实现字符串反转输出时,因为没精准控制读取的字符范围,导致输出了内存里的垃圾数据。咱们一步步拆解问题,看看怎么修正。
初始代码与问题分析
先看你最初的实现代码:
BITS 16 org 0x7C00 _start: xor ax,ax ; set ax register to 0 mov ds,ax ; set data segment(ds) to 0 mov es,ax ; set extra segment(es) to 0 mov bx,0x8000 mov si,string call reverse_print jmp $ reverse_print: mov ah,0Eh .rep_pre: inc si cmp al,0 je .rep_init jmp .rep_pre .rep_init: dec si jmp .rep .rep: std lodsb cmp al,0 je .done int 10h jmp .rep .done: cld ret string db "ABC",0 times 510-($-$$) db 0 ; Pad remainder of boot sector with 0s dw 0xAA55 ; The standard PC boot signature
这段代码的核心问题在于:
.rep_pre循环里用cmp al,0判断是否到达字符串末尾,但al寄存器初始没有被赋值,这个判断完全无效,循环会一直执行直到越界,读取到内存里的随机数据- 后续
.rep循环从错误的位置开始反向读取,直到遇到0才停止,自然会输出一堆乱码(你看到的A鈹溾伩 鈱∥樷瘓=鈾就是越界读取的垃圾数据)
修正思路与最终代码
你通过引入CX寄存器作为计数器的思路完全正确——用CX记录字符串的长度,就能精准控制反向读取的字符数量,避免越界。修正后的代码如下:
BITS 16 org 0x7C00 _start: xor ax,ax ; set ax register to 0 mov ds,ax ; set data segment(ds) to 0 mov es,ax ; set extra segment(es) to 0 mov bx,0x8000 mov si,string call reverse_print jmp $ reverse_print: mov ah,0Eh mov cx,1 ; 初始化计数器,初始值对应字符串起始位置 .rep_pre: inc si inc cx ; 每移动一个字符,计数器加1 cmp al,0 je .rep_init jmp .rep_pre .rep_init: inc si inc cx jmp .rep .rep: std lodsb ; 反向读取字符 dec cx ; 计数器减1 cmp al,0 je .done cmp cx,0 jl .done ; 计数器小于0时停止,避免读取多余数据 int 10h ; 调用BIOS中断输出字符 jmp .rep .done: cld ; 恢复方向标志位 ret string db "ABC",0 times 510-($-$$) db 0 ; Pad remainder of boot sector with 0s dw 0xAA55 ; The standard PC boot signature
关键修改点说明:
- 添加CX计数器:用CX记录字符串的总长度(包括终止空字符),确保我们只读取有效字符
- 同步计数器与SI指针:
.rep_pre循环里每次移动SI指针时,同步递增CX,准确统计字符总数 - 终止条件优化:在
.rep循环里,除了判断是否读取到终止符0,还通过cmp cx,0判断计数器是否耗尽,避免越界读取垃圾数据 - 调整指针定位:
.rep_init里的调整确保SI刚好指向字符串末尾的前一个有效字符,保证反向读取从最后一个有效字符"C"开始
修正后结果
现在执行代码,就能得到你期望的输出:
CBA
内容的提问来源于stack exchange,提问作者Dorian Niemiec
相关产品推荐
相关产品推荐

