2

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

我正在使用 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=====
4

2 回答 2

7

通过交换字符来反转字符串的方法是交换第一个和最后一个,然后是第二个和最后一个,等等。在 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
于 2012-11-27T15:41:14.467 回答
0

当我为面试做这个时,我想出了这个......它有点微软特有,但它与@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
    }
}
于 2015-03-30T13:54:09.870 回答