You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 17:01:08