x86 NASM汇编移除字符串第n个字符函数异常排查
x86 NASM汇编移除字符串每第n个字符函数异常原因分析
我用x86 NASM汇编实现了一个移除字符串中每第n个字符的函数,处理输入字符串"abcabcabc"(n=3)时,预期输出ababab,但实际得到abacb,以下是相关代码及问题分析:
相关代码
main.c
#include <stdio.h> char *rem(char *s, int n); int main(int argc, char *argv[]) { char s[] = "abcabcabc"; int n = 3; printf("%s\n", rem(s, n)); }
rem.s
section .text global rem rem: push ebp mov ebp, esp push esi push edi push ebx mov eax, [ebp+8] ; read pointer mov ecx, [ebp+8] ; write pointer mov edx, [ebp+12] ; n mov esi, 1 ; counter loop: cmp BYTE [eax], 0 jz fin cmp edx, esi jz remove dont_remove: ; move current character to position ; pointed by the write pointer mov edi, [eax] mov [ecx], edi inc ecx ; increase write pointer inc eax ; increase read pointer inc esi ; counter++ jmp loop remove: mov esi, 1 ; reset the counter inc eax ; increase only read pointer jmp loop fin: mov edi, [eax] mov [ecx], edi mov eax, [ebp+8] pop ebx pop edi pop esi pop ebp ret
Makefile
EXEFILE = main OBJECTS = main.o rem.o CCFMT = -m32 NASMFMT = -f elf32 CCOPT = -m32 -c NASMOPT = -w+all .c.o: cc -g $(CCFMT) $(CCOPT) $< .s.o: nasm $(NASMFMT) $(NASMOPT) $< $(EXEFILE): $(OBJECTS) cc $(CCFMT) -o $(EXEFILE) $(OBJECTS) clean: rm *.o $(EXEFILE)
问题核心原因
代码的致命错误在于字符拷贝操作是按双字(4字节)而非单字节执行:
- 在
dont_remove和fin段中,mov edi, [eax]和mov [ecx], edi这两组指令,在32位x86模式下默认访问双字(4字节)数据。 - 原字符串是单字节ASCII字符序列,每次双字拷贝会一次性覆盖4个字节的内存,导致后续未处理的字符被提前破坏,最终输出乱码。
- 例如第一次执行拷贝时,
eax指向第一个字符'a',[eax]会读取从'a'开始的4个字符('a'、'b'、'c'、'a'),并写入ecx指向的位置,直接篡改了后续的'b'、'c'字符,导致后续逻辑处理完全偏离预期。
修复方案
将拷贝操作改为单字节访问即可,修改dont_remove和fin段的代码:
dont_remove: ; 单字节拷贝当前字符 mov al, BYTE [eax] mov BYTE [ecx], al inc ecx ; 移动写指针 inc eax ; 移动读指针 inc esi ; 计数器+1 jmp loop fin: ; 写入字符串结束符(单字节) mov BYTE [ecx], 0
内容的提问来源于stack exchange,提问作者szachneq
相关产品推荐
相关产品推荐

