String 如何在nasm中反转字符串中的每个单词?

String 如何在nasm中反转字符串中的每个单词?,string,assembly,nasm,reverse,String,Assembly,Nasm,Reverse,我必须写一个程序,读取25个字符的字符串,并返回相同的字符串,每个单词的字母在asm语言中颠倒 例如: Input >> Hello world. How are you? Output >> olleH .dlrow woH era ?uoy 这就是我所做的: %include "asm_io.inc" segment .data prompt1 db "Insert the strin: ", 0 ; don't forget nul termi

我必须写一个程序,读取25个字符的字符串,并返回相同的字符串,每个单词的字母在asm语言中颠倒

例如:

Input >> Hello world. How are you?
Output >> olleH .dlrow woH era ?uoy
这就是我所做的:

%include "asm_io.inc"
segment .data

prompt1 db    "Insert the strin: ", 0       ; don't forget nul terminator
prompt2 db    "The string is: ", 0
prompt3 db    "The reverse string is: ", 0

segment .bss

vector  resb 25
vectorInvert resb 25   
aux resb 1 
aux2 resb 1                                          

segment .text
        global  asm_main
asm_main:


        mov     eax, prompt1      ; print out prompt
            call    print_string


        mov edi, vector ;vetor e do tipo byte
        mov ecx, 25
        read:
            call read_char  
            stosb       
        loop read

        mov eax, 0
        mov edx, 0
        mov esi, vector
        mov ecx, 25
        stack:
            mov al, [esi]
            cmp al, " "
            jz stack2
            movzx eax, al
            push eax
            add eax, 1  
            add esi, 1
        loop stack

        stack2:
            mov [aux], ecx
            mov [aux2], eax         
            mov ecx, 25
            sub ecx, eax
            mov edi, vectorInvert           
            lp:
                pop eax
                add edx, 1
                mov [edi], eax
                add edi, 1
            loop lp
            add eax, 1
            add edx, 1
            add esi, 1
            add edi, 1
            mov ecx, [aux]
            mov eax, [aux2]
            cmp eax, 25
            jz out
            jnz stack


        out:

            mov     eax, prompt3
            call    print_string

            mov edi, vectorInvert
            mov ecx, 25
            print:
                lodsb
                call print_char 
            loop print
            call print_nl

            leave                     
            ret
我被困在那里,我不知道如何继续前进。我真的非常感谢您对这段代码的帮助。
我在这里使用这个库:drpaulcarter.com/pcasm/linux-ex.zip
(请注意,我在汇编方面完全是新手。)

使用堆栈反转字符串:

  • 复制堆栈指针
  • 推送0字节(如果使用DOS,则推送“$”)
  • 推送字符串的每个字符
  • 将stackpointer作为字符串地址
  • 打印它(或复制它或任何应该用它做的事情)
  • 还原堆栈指针

  • 可能需要注意的事项:如果堆栈指针变为奇数,可能会导致问题,因此在这种情况下,可能会先推送额外的0字节以保持堆栈对齐。

    好吧。。。我看到发布的代码有一些小问题。除了拼写“strin”rong,变量
    aux
    aux2
    太小。如果要在它们中放入32位寄存器,则它们必须是32位-4字节-
    resd1
    resb4
    (两者都可以)。我想你可能不需要这些变量,但要使它们的大小合适

    然后,如果要在
    asm_main
    末尾使用
    leave
    ,则需要从
    开始,输入0,0
    。我认为卡特博士所有的例子都是这样的

    您的输入例程看起来可以正常工作,但强制用户准确输入25个字符,即使它们的“strin”较短。这样做的好处是你知道你有多少个字符,但不是很灵活。卡特博士的库提供了一个
    读取字符串
    ,它返回一个以零结尾的字符串。我们可以在这上面做一个
    stringlen
    ,但是因为我们无论如何都要检查每个字符,我们可以只看零

    然后,通过
    推送eax
    ,您似乎做得很好。然后添加eax,1。嗯?看起来您希望
    eax
    既是字符又是计数器。这行不通

    我想把每个角色按一下,数一数,然后检查一下是什么。这会使“Hello”变成“olleH”(当我们弹出时)。还不算太糟,但是当我们到达末尾时(如果我们使用的是以零结尾的字符串),它会导致一个问题。我决定先检查字符,只推(和计数)非空格(和非零)字符

    mov esi, string
    mov edi, reverse
    
    nextword:
    xor ecx, ecx ; counter - per word
    pushloop:
    lodsb
    cmp al, ' '
    jz poploop
    cmp al, 0
    jz cleanuploop
    push eax ; if not, save it (plus garbage)
    inc ecx
    jmp pushloop
    
    poploop:
    pop eax ; including garbage
    stosb ; store al only, ignoring garbage
    loop poploop
    mov al, ' '
    stosb
    jmp nextword
    
    cleanuploop:
    pop eax
    stosb
    loop cleanuploop
    mov al, 0 ; zero-terminate our string for "print_string"
    stosb
    
    这“有效”。你看到缺陷了吗?如果讨厌的用户输入一个空格作为第一个字符(或最后一个,或什么也不输入),我们将进入
    poploop
    (等),而
    ecx
    已经为零。
    循环
    指令递减
    ecx
    ,如果非零则跳转。如果
    ecx
    已经为零,它将递减到0ffffffh。这循环了很多次。在火焰中坠毁

    我是这样解决的

    mov esi, string
    mov edi, reverse
    
    nextword:
    xor ecx, ecx
    pushloop:
    lodsb
    cmp al, ' '
    jz poploop
    cmp al, 0
    jz cleanuploop
    push eax
    inc ecx
    jmp pushloop
    
    poploop:
    jecxz skippop ; bail out if ecx is zero
    pop eax
    stosb
    loop poploop
    skippop:
    mov al, ' '
    stosb
    jmp nextword
    
    cleanuploop:
    jecxz skippop2
    pop eax
    stosb
    loop cleanuploop
    skippop2:
    mov al, 0
    stosb
    
    显示它,当然要干净地退出。如果你在后面加一条新线,看起来会更好

    在按下
    eax
    之前,请执行
    movzx-eax,al
    。没有问题,但是我们可以
    推送eax
    上面字节中的任何内容。只要在弹出后忽略所有内容,除了
    al
    。正如您所知道的那样,您不能只推al

    我希望这不太像“为你做”——我想不出更好的解释。有不同的方法可以做到这一点。希望这将给你一些想法如何继续

    编辑:他们不允许我添加评论(?)。请尝试以下方法:
    输入0,0
    的操作与
    推ebp
    /
    移动ebp,esp的操作相同。如果第一个参数非零,它将从
    esp
    -中减去该值,为局部变量留出空间<代码>离开
    与移动esp、ebp/
    弹出ebp
    的操作相同。从
    driver.c
    调用的
    asm\u main
    函数的序言和结束语。查看示例中的
    skel.asm

    这是什么处理器?处理器是IntelI?我正在从这里使用库:可能是重复的,你不能推送一个字节<代码>推送r16可在所有模式下使用(包括64位),因此您可以在推送之前加载一个字并将其交换(使用
    rol ax,8
    )。或者展开加载并检查循环,在寄存器中用移位建立2或4B,这样您就可以
    推送该值。或者根本不使用实际的
    push
    指令。在运行时向下调整堆栈指针是一个很好的建议,可以在不首先遍历输入的情况下动态分配堆栈内存(
    strlen
    )。