交换字符串的第一个和最后一个字符会导致seg错误

问题描述

我的目标是将some_str中字符串x86-assembly的第一个字符与最后一个字符交换。

这是我的尝试:

; assemble and link with:
; nasm -f elf32 -g test.asm && ld -melf_i386 test.asm.o -o test


section .text
global  _start
extern printf

_start:
    mov eax,some_str

    _loop:
    mov  di,[eax + 4]  ; ptr to end char
    mov  si,[eax]  ; ptr to start char

    mov  dl,[di]      ; DL = end char
    mov  al,[si]      ; AL = start char

    mov  [si],dl      ; start char = end char 
    mov  [di],al      ; end char = char 1 


    mov edx,len
    mov ecx,eax
    mov ebx,1
    mov eax,4
    int 0x80

    ret

    mov eax,1
    int 0x80

section  .data
    some_str     db `abcd`,0xa
    len     equ $ - some_str

出于某种原因,我没有注意以下内容

    mov  dl,[si]      ; AL = start char

使程序导致分段错误

预期的标准输出是:

dbca

实际标准输出

Segmentation fault (core dumped)`

有什么我想念的吗?如何更正此代码以正确交换some_str的第一个和最后一个字符。

解决方法

您的代码似乎在做比必要的事情复杂得多的事情。在mov eax,some_str之后,我们有eax指向要交换的字节之一,而eax+4指向另一个字节。因此,只需将它们加载到两个8位寄存器中,然后以另一种方式将它们存储回去。

mov eax,some_str
mov cl,[eax]
mov dl,[eax + 4]
mov [eax + 4],cl
mov [eax],dl

您已经完成,可以继续写出结果。

请注意,没有必要先将指针加载到eax中;你也可以做

mov cl,[some_str]
mov dl,[some_str + 4]
mov [some_str + 4],cl
mov [some_str],dl

如果您确实希望有两个不同的寄存器来指向两个不同的字节:首先,它们必须是32位寄存器。尝试使用16位寄存器si,di在32位模式下寻址内存几乎是行不通的。其次,mov edi,[eax]将在位置edi处向eax加载内存的内容,该内容是字符串的某些字节,而不是指针。您只需要mov edi,eax。对于第二个,您可以使用lea进行有效地址计算的算法,但保留结果指针而不是进行加载。因此,我认为将您的代码转变为原始(低效)精神但正确的方法是

mov edi,eax
lea esi,[eax+4]
mov dl,[edi]
mov al,[esi]
mov [esi],dl
mov [edi],al