问题描述
我的目标是将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