Problem when reversing a string, it does not output the full reversed string

Viewed 72

I have been trying to reverse a string in x86 64 bit assembly code and the point of the code is to return the length of the reversed string while also reversing the string

My code is :

reverse_string_asm:
        #rdi ->str
        #rsi -> i
        #rdx -> start index
        #r8 -> end index
        #rcx ->temp
        #rax -> count

        test %rdi, %rdi #check if str is null
        jz ret_null
        xor %rsi, %rsi
        xor %r8, %r8
        xor %r9, %r9
count_length:
        mov (%rdi, %rsi, 1), %r9 # str[i] -> r9
        cmp $0, %r9 #check if str[i] != 0
        je pre_while
        inc %rsi # i++
        jmp count_length

pre_while:
        subq $1, %rsi #i - 1
        mov %rsi, %r8 # end index = i - 1
        addq $1, %rsi #restore i
        mov $0, %rdx
        mov $0, %r9
        xor %rcx, %rcx
        jmp while

while:
        cmp %r8, %rdx # start index < end index
        jge done
        mov (%rdi, %rdx, 1), %rcx #temp = str[start index]
        mov (%rdi, %r8, 1), %r9
        mov %r9, (%rdi, %rdx, 1) #str[start index] = str[end index]
        mov %rcx,  (%rdi, %r8, 1)  #str[end index] = temp
        inc %rdx #start++
        dec %r8 #end--
        jmp while

done:
        movq %rsi, %rax #want to return the length of the reversed str which is equal to the length of original, count = i
        ret

ret_null:
        xor %rax, %rax
        ret

The code I use to test is:

printf("Testing reverse_string_asm\n");
    char *s = (char *) malloc (100); 
    memset(s, 0, 100); 
    strcpy(s, "Hello World!"); 
    puts(s); 
    unsigned long l = reverse_string_asm(s); 
    printf("Size of rev str: %lu\n", l); 
    puts(s);
    printf("\n");

Although when I run my code I get the correct length outputted but the reversed word outputted is: !dl

when it should be : !dlroW elloH

I cannot find where the code creates this problem or what I am doing that is incorrect. I am new to assembly language and would be grateful for any help in solving this problem. Thank you.

1 Answers

The problem is that you're reading and writing 8 bytes at a time but you're acting like it's only 1 byte at a time. For example, given char *str, the equivalent of C's str[end_index] = temp; is mov %cl, (%rdi, %r8, 1), but you instead wrote mov %rcx, (%rdi, %r8, 1), which in C would be *(long *)(str + end_index) = temp;. To fix it, when you mov in and out of memory, use 1-byte registers instead of 8-byte ones. Replacing all occurrences of %rcx with %cl and %r9 with %r9b should fix your program.

Related