I am trying to reverse a string in assembly. However my code does not seem to work correctly. I added a newline string for better readability.
I am using linux and n
The way to reverse a string by swapping characters is to swap the first and last, then the second and next to last, etc. In C, you would write:
for (i = 0; i < len/2; ++i)
{
c = s[i];
s[i] = s[len-i-1];
s[len-i-1] = c;
}
In assembly language, the easiest way is to set up the ESI and EDI registers to point to the start and end of the string, then loop. At each iteration, you increment ESI and decrement EDI. The result looks something like this:
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
When I did this for an interview, I came up with this... It is a bit Microsoft specific, but it's roughly the same as what @Jim Mischel wrote, except this calculates the length of the string rather than being passed it etc.
This function is naked, so since there's no prolog or epilog you do have to be careful about what registers you can use. (Unless you push and pop if you use them. In this example, I'm not using any registers that need to be preserved)
#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
}
}