Swapping first and last characters of string results in seg fault

Viewed 242

My goal is to swap the first character with the last character of the string some_str in x86-assembly.

Here is my attempt:

; 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

For some reason I am oblivious to the lines:

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

Causes the program to result in a segmentation fault.

The expected stdout is:

dbca

Actual stdout:

Segmentation fault (core dumped)`

Is there something I am missing? How do I correct this code to correctly swap the first and last character of some_str.

1 Answers

Your code seems to be doing something much more complicated than necessary. After mov eax, some_str, we have that eax points to one of the bytes that wants to be swapped, and eax+4 points to the other. So just load them into two 8-bit registers and then store them back the other way around.

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

And you're done and can proceed to write out the result.

Note it isn't necessary to load the pointer into eax first; you could also do

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

If you really wanted to have two different registers to point to the two different bytes: first of all, they need to be 32-bit registers. Trying to address memory in 32-bit mode using 16-bit registers si, di is practically never going to work. Second, mov edi, [eax] would load edi with the contents of the memory at location eax, which is some bytes of your string, not a pointer. You'd want simply mov edi, eax. For the second one, you can use lea to do the arithmetic of an effective address calculation but keep the resulting pointer instead of doing a load. So I think the way to turn your code into something in the original (inefficient) spirit, but correct, would be

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