【问题标题】:Trouble reversing a string in assembly在汇编中反转字符串时遇到问题
【发布时间】:2012-11-27 15:19:15
【问题描述】:

我正在尝试反转汇编中的字符串。 但是我的代码似乎无法正常工作。 我添加了一个换行符以提高可读性。

我使用 linux 和 nasm 作为编译器。

我想如果我把地址指针的值转换到正确的位置,字符串最终会被反转然后恢复正常。

这是我的代码:

section .data
    hello     db 'Hello world!'
    helloLen  equ $-hello
    derp db '=========',10
    derplen equ $-derp

section .text
    global main

main:
    mov eax,0
    mov ecx,helloLen

    reverse:
        ;move pointer
        mov ebx,hello
        add ebx,eax
        push eax

        ;move pointer
        mov eax,hello
        add eax,ecx
        push ecx

        ;switch bytes
        push ebx
        mov ebx,[ebx]
        mov [eax],ebx
        pop ebx
        mov eax,[eax]
        mov [ebx],eax

        ;print text
        mov eax,4
        mov ebx,1
        mov ecx,hello
        mov edx,helloLen
        int 80h

        ;Print newline
        mov eax,4
        mov ebx,1
        mov ecx,derp
        mov edx,derplen
        int 80h

        ;increment and decrement
        pop ecx
        dec ecx
        pop eax
        inc eax

        cmp eax,helloLen
    jne reverse

    end:
        mov eax,1
        mov ebx,0
        int 80h

这是我得到的输出:

Hello world!Hell=====
Hello worldellol=====
Hello worlllo ol=====
Hello worlo w ol=====
Hello woo wow ol=====
Hello wooooow ol=====
Hello wooooow ol=====
Helloooooooow ol=====
Helloooooooow ol=====
Helooowooooow ol=====
Heoow wooooow ol=====
How o wooooow ol=====

【问题讨论】:

  • 我马上注意到了一些事情:1) 当你交换字符时,你应该交换字节,而不是双字。 2) ecx 应该从 helloLen-1 开始。 3)算法的终止条件错误;你最终会交换每个字符两次。 (当 eax >= ecx 时停止)

标签: assembly x86


【解决方案1】:

通过交换字符来反转字符串的方法是交换第一个和最后一个,然后是第二个和最后一个,等等。在 C 中,你可以这样写:

for (i = 0; i < len/2; ++i)
{
    c = s[i];
    s[i] = s[len-i-1];
    s[len-i-1] = c;
}

在汇编语言中,最简单的方法是设置 ESI 和 EDI 寄存器指向字符串的开头和结尾,然后循环。在每次迭代中,您增加 ESI 并减少 EDI。结果如下所示:

mov ecx, helloLen
mov eax, hello
mov esi, eax  ; esi points to start of string
add eax, ecx
mov edi, eax
dec edi       ; edi points to end of string
shr ecx, 1    ; ecx is count (length/2)
jz done       ; if string is 0 or 1 characters long, done
reverseLoop:
mov al, [esi] ; load characters
mov bl, [edi]
mov [esi], bl ; and swap
mov [edi], al
inc esi       ; adjust pointers
dec edi
dec ecx       ; and loop
jnz reverseLoop

【讨论】:

  • @gandolf:是的。因为当长度为奇数时,中间字符不会移动。例如,当长度为 3 时,只执行一次循环迭代,交换项目 0 和 2。中间的项目不移动。
  • 您不需要单独的计数器或长度计算,只需 cmp esi, edi / jb 作为循环条件,就像 do{}while(++p_start &lt; --p_end); 是就地反转的惯用方式。
【解决方案2】:

当我为面试做这个时,我想出了这个......它有点微软特定的,但它与@Jim Mischel 写的大致相同,除了它计算字符串的长度而不是被传递它等等。

这个函数是裸函数,所以由于没有序言或结语,你必须小心你可以使用哪些寄存器。 (除非你使用它们时 push 和 pop。在这个例子中,我没有使用任何需要保留的寄存器)

#define USE_STRLEN 0                                    ; Use strlen to find string length?

__declspec(naked) uint8_t* string_rev(uint8_t* s)
{
    __asm
    {
              mov    eax, dword ptr[esp + 4]            ; Get the address of string
              test   eax, eax                           ; Been passed a null pointer?
              jz     lp_3
#if (USE_STRLEN)
              push   eax                                ; Push string address onto stack
              call   strlen
              pop    ecx                                ; Pop our string back off the stack
              xchg   ecx, eax                           ; String length in eax
#else
              or     ecx, 0ffffffffh                    ; Start ecx at -1
        lp_1:
              inc    ecx
              test   byte ptr[eax + ecx], 0ffh          ; Test string byte for zero
              jnz    lp_1                               ; ecx = string length

#endif
              lea    edx, dword ptr[eax + ecx - 1]      ; edx = last character in string
              and    ecx, -2                            ; Is string 1 character or less?
              jz     lp_3
        lp_2:
              mov    cl, byte ptr[edx]
              mov    ch, byte ptr[eax]
              mov    byte ptr[eax], cl
              mov    byte ptr[edx], ch
              inc    eax
              dec    edx
              cmp    edx, eax                           ; Loop whilst one pointer is less
              ja     lp_2                               ; than the other (equiv. len/2)
        lp_3:
              ret                                       ; Reversed string in eax
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-04-03
    • 1970-01-01
    • 1970-01-01
    • 2012-09-27
    • 1970-01-01
    • 2014-05-06
    • 1970-01-01
    相关资源
    最近更新 更多