【问题标题】:How to reverse of each word in a string in nasm?如何在nasm中反转字符串中的每个单词?
【发布时间】:2014-01-01 23:36:59
【问题描述】:

我必须编写一个程序,它读取一个 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 (请注意,我是组装的新手。)

【问题讨论】:

标签: string assembly nasm reverse


【解决方案1】:

使用堆栈反转字符串:

  1. 复制堆栈指针
  2. 推送一个 0 字节(或 '$',如果使用 DOS)
  3. 推送字符串的每个字符
  4. 将堆栈指针作为字符串地址
  5. 打印(或复制或任何应该用它做的事情)。
  6. 恢复堆栈指针

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

【讨论】:

  • 您不能推送单个字节。 push r16 适用于所有模式(包括 64 位),因此您可以在推送之前加载一个单词并交换它(使用 rol ax, 8)。或者展开您的加载和检查循环以在带有移位的寄存器中建立 2 或 4B,这样您就可以push。或者根本不使用实际的push 指令。以一种或另一种方式向下调整堆栈指针对于动态分配堆栈内存而不首先遍历输入是一个很好的建议 (strlen)。
【解决方案2】:

嗯...我看到发布的代码存在一些小问题。除了拼写“strin” rong,变量auxaux2 太小了。如果您要在它们中放置一个 32 位寄存器,它们需要是 32 位 - 4 个字节 - resd 1resb 4(两者都可以)。我认为您可能不需要这些变量,但要使它们的大小合适。

那么,如果您要在asm_main 的末尾使用leave,则需要以enter 0, 0 开头。我认为卡特博士的所有例子都是这样做的。

您的输入例程看起来可以正常工作,但会强制用户准确输入 25 个字符,即使他们想到的“字符串”更短。这样做的好处是你知道你有多少个字符,但不是很灵活。 Carter 博士的库提供了一个read_string,它返回一个以零结尾的字符串。我们可以对此进行stringlen,但由于无论如何我们都必须检查每个字符,所以我们可以只注意零。

那么通过push eax,您似乎做得很好。然后你add eax, 1。嗯?看起来您打算将 eax 既是角色又是计数器。这行不通!

我的想法是推动每个角色,数数,然后检查它是什么。这会使“Hello”变成“olleH”(当我们pop'em 时)。还不错,但是当我们到达结尾时会导致问题(如果我们使用以零结尾的字符串)。我决定先检查字符,只推(和计数)非空格(和非零)字符...

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 已经为零。 loop 指令递减 ecx 并在非零时跳转。如果ecx 已经为零,它会递减到 0FFFFFFFFh。这循环了很多次。在火焰中坠毁!

我是这样解决的……

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。没有坏处,但我们可以push eax 高字节中的任何内容。弹出后忽略除al 之外的所有内容。你不能只是push al,如你所知......

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

编辑:他们不会让我添加评论(?)。试试这个: enter 0, 0push ebp / mov ebp, esp 的作用相同。如果第一个参数不为零,它将从esp 中减去该数量 - 为局部变量腾出空间。 leavemov esp, ebp / pop ebp 的作用相同。从driver.c 调用的asm_main 函数的Prolog 和epilog。在示例中使用skel.asm

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-11-13
    • 2021-04-28
    • 1970-01-01
    • 2015-06-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多