flat assembler
Message board for the users of flat assembler.

Index > Main > MASM to FASM reverse string

Goto page 1, 2  Next
Author
Thread Post new topic Reply to topic
Synaps3



Joined: 06 Jul 2011
Posts: 6
Synaps3
Hi. I found some code to do quick string reverse. It is written in MASM. Can someone help me convert the code for FASM. I am a noob (to assembly, but not programming in general), so if there is a lot to change, I would appreciate extra explanation.

Thanks.

Code:
StrRev:
        mov     ecx, sizeof str1-1
  xor     eax,eax
     cmp     ecx, 4
      jl      Bytes3
      push    ebx
@@:
      mov     edx, dword ptr [str1+eax]
   add     eax, 4
      add     ecx, -8
     mov     ebx, dword ptr [str1+eax+ecx]
       bswap   edx
 mov     dword ptr [str2+eax +ecx], edx
      bswap   ebx
 mov     dword ptr [str2+eax-4], ebx
 jg      @b
  pop     ebx
 ret
Bytes3:
  movzx   edx, byte  ptr [str1]
       cmp     ecx, 1
      mov     byte ptr [str2+ecx-1], dl
   jle     End3
        mov     dl, byte  ptr [str1+1]
      cmp     ecx, 2
      mov     byte ptr [str2+ecx-2], dl
   jle     End3
        mov     dl, byte  ptr [str1+2]
      mov     byte ptr [str2+ecx-3], dl
End3:
      ret    
Post 06 Jul 2011, 11:52
View user's profile Send private message Reply with quote
JohnFound



Joined: 16 Jun 2003
Posts: 3502
Location: Bulgaria
JohnFound
I don't know how str1 and str2 are defined, but this should be something like this: (as you can see, the difference is not so big)
Code:
StrRev:
        mov     ecx, sizeof.str1-1
        xor     eax,eax
        cmp     ecx, 4
        jl      Bytes3
        push    ebx
@@:
        mov     edx, dword [str1+eax]
        add     eax, 4
        add     ecx, -8
        mov     ebx, dword [str1+eax+ecx]
        bswap   edx
        mov     dword [str2+eax +ecx], edx
        bswap   ebx
        mov     dword [str2+eax-4], ebx
        jg      @b
        pop     ebx
        ret
Bytes3:
        movzx   edx, [str1]
        cmp     ecx, 1
        mov     [str2+ecx-1], dl
        jle     End3
        mov     dl, [str1+1]
        cmp     ecx, 2
        mov     [str2+ecx-2], dl
        jle     End3
        mov     dl, [str1+2]
        mov     [str2+ecx-3], dl
End3:
        ret


sizeof.str1 = 256
str1 rb sizeof.str1


sizeof.str2 = 256
str2 rb sizeof.str2
    
Post 06 Jul 2011, 12:08
View user's profile Send private message Visit poster's website ICQ Number Reply with quote
edfed



Joined: 20 Feb 2006
Posts: 4242
Location: 2018
edfed
this code isn't good at all for just one reason, it uses a constant as file size.

to be really usefull, the filesize should be given by a data in memory, something like a byte count in a dword or else.

but when you mean reverse a string, do you mean, reverse all bytes of the string? the last becomes the first, and vice versa?
or reverse just the byte of every single word, eht tsal etyb fo yreve drow eb eht tsrif?

in all case, you need a data to tell the function what is the size of the string to convert.

first, it loads the string size count in ECX
it resets the EAX register
it compares the size with 4, and if lower, it will jump to the bytes3 routine that plays byte per byte instead of dword per dowrd, and can process string shorter than 4 bytes.

if the size is greater than 4 bytes, it will process the reverse string dword per dword, the eax reg is used as an index, and the ecx register as a pointer.


the code here apparentlly is optimized for string size multiple of 4 but it should do something that isn't in this code.

and apparentlly, this code is bugged, and will not work convenientlly for string size not multiple of 4.
the byte3 variation will play with the 3 first bytes in a very bloated way.
a loop can do the job with less instructions.
you should test for the non multiple of 4 cases in order to play the byte3 variation only one time if the string size is not multiple of 4

you can do the reverse on the string itself, no need to do it on str2. just str1 is needed.
the size should be divided by two before to launch the reverse, otherwise, it will reverse every bytes 2 times, and then, don't do anything in apparence.
there is the need to support the non multiple of 4 cases, because in the middle of the string, there will be a problem, inducing multiple reversing of theses bytes.



courage, it is not so hard to do, think how you do it by hand, report it as a diagram, and convert it in elementary operation before to write it in asm.

Smile
Post 06 Jul 2011, 12:10
View user's profile Send private message Visit poster's website Reply with quote
AsmGuru62



Joined: 28 Jan 2004
Posts: 1419
Location: Toronto, Canada
AsmGuru62
Seems to me its too much code to just reverse a string.
Post 06 Jul 2011, 14:00
View user's profile Send private message Send e-mail Reply with quote
Synaps3



Joined: 06 Jul 2011
Posts: 6
Synaps3
It works. I found some code that helped me fix the bugs. It uses a quick proc to get the length of the string and it works with a string of any size. It does use the stack, but not during a loop, so it is faster than most.

I found some code and adapted it from here: http://www.masm32.com/board/index.php?PHPSESSID=a03bd4d2a873fdcc4409d1676dd7fd47&topic=2869.0

Here is the full code:

Code:
include 'win32ax.inc'

.data
strbuff db "this is a string"

.code
start:
      invoke  MessageBox,HWND_DESKTOP,strbuff,"Original String",MB_OK
      stdcall StrLen,strbuff
      stdcall StrRev,strbuff,ecx
      invoke  MessageBox,HWND_DESKTOP,strbuff,"Reversed",MB_OK
      invoke  ExitProcess,0

proc StrRev strAddr,strSize
      push esi
      push edi
      mov esi,[strAddr]
      mov eax,[strSize]
      lea edi,[esi+eax] ; if you use SIZEOF => lea edi,[esi+eax-1]
      cmp eax,2 ; something to reverse ?
      jb Label4
      cmp eax,9 ; small string ?
      jb Label3
   Label2:
      sub edi,4 ; big string algo
      mov edx,dword [edi]
      mov eax,dword [esi]
      bswap eax
      bswap edx
      mov dword [esi],edx
      mov dword [edi],eax
      add esi,4
      cmp esi,[edi+8]
      jb Label2
   Label3:
      sub edi,1 ; small string algo
      mov dh,[edi]
      mov dl,[esi]
      mov [esi],dh
      mov [edi],dl
      add esi,1
      cmp esi,edi
      jb Label3
   Label4:
      pop edi
      pop esi
      ret
endp

proc StrLen, strInput
      mov ecx,-1
      mov al,0
      mov edi,[strInput]
      cld
      repne scasb
      not ecx
      dec ecx
      ret
endp

.end start
    


Last edited by Synaps3 on 06 Jul 2011, 18:09; edited 1 time in total
Post 06 Jul 2011, 17:03
View user's profile Send private message Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4633
Location: Argentina
LocoDelAssembly
Don't use ccall, use stdcall or put a "c" after the name of each proc (e.g. "proc StrRev c, ...") so the stack won't be messed up.
Post 06 Jul 2011, 17:36
View user's profile Send private message Reply with quote
Synaps3



Joined: 06 Jul 2011
Posts: 6
Synaps3
LocoDelAssembly wrote:
Don't use ccall, use stdcall or put a "c" after the name of each proc (e.g. "proc StrRev c, ...") so the stack won't be messed up.


Fixed.
Post 06 Jul 2011, 18:10
View user's profile Send private message Reply with quote
ctl3d32



Joined: 30 Dec 2009
Posts: 204
Location: Brazil
ctl3d32
I would just use this (it inverts char by char):
Code:
format PE GUI 4.0
entry start

include 'win32a.inc'

section '.text' code readable executable

  start:

        stdcall InvertString,szBuffer,szString
        invoke  MessageBox,0,szBuffer,szTitle,MB_OK

  exit:
        invoke  ExitProcess,0

proc GetStrLen uses ecx edi,szString
        xor     eax,eax
        mov     ecx,0xffffffff
        mov     edi,[szString]
        repne   scasb
        not     ecx
        mov     eax,ecx
        ret
endp

proc InvertString uses ebx ecx esi,szBuffer,szString
        mov     esi,[szString]
        stdcall GetStrLen,[szString]
        mov     ecx,eax
        mov     ebx,[szBuffer]
        mov     byte[ebx+ecx-1],0
        dec     ecx
  @@:
        lodsb
        mov     byte[ebx+ecx-1],al
        loop    @b
        ret
endp

section '.bss' readable writeable

  szBuffer rb 100h

section '.data' data readable writeable

  szString db 'This is my string.',0 ;19 chars
  szTitle  db 'String Inversion...',0

section '.idata' import data readable writeable

  library kernel32,'KERNEL32.DLL',\
          user32,'USER32.DLL'

  include 'api\kernel32.inc'
  include 'api\user32.inc'
    


Last edited by ctl3d32 on 07 Jul 2011, 03:19; edited 1 time in total
Post 06 Jul 2011, 18:41
View user's profile Send private message Reply with quote
ctl3d32



Joined: 30 Dec 2009
Posts: 204
Location: Brazil
ctl3d32
This one for long strings (it inverts 4 chars at once):
Code:
format PE GUI 4.0
entry start

include 'win32a.inc'

section '.text' code readable executable

  start:

        stdcall InvertString,szBuffer,szString
        invoke  MessageBox,0,szBuffer,szTitle,MB_OK

  exit:
        invoke  ExitProcess,0

proc GetStrLen uses ecx edi,szString
        xor     eax,eax
        mov     ecx,0xffffffff  ;Max number of chars to read
        mov     edi,[szString]
        repne   scasb           ;Repeat until byte at edi == al or ecx == 0, decreasing ecx in every iteration.
        not     ecx
        mov     eax,ecx
        ret
endp

proc InvertString uses ebx ecx edx esi edi ebp,szBuffer,szString
        mov     esi,[szString]
        stdcall GetStrLen,[szString]
        mov     ebx,[szBuffer]
        mov     byte[ebx+eax-1],0 ;Zero terminated string
        dec     eax
        mov     ecx,4
        cdq
        div     ecx
        mov     edi,eax ;EDI will hold the number of dwords the string is composed by, and EDX the left chars.
  @@:
        test    edi,edi
        je      @f
        lodsd           ;Load the first dwords of the string
        bswap   eax     ;Invert them
        lea     ebp,[ebx-4+edx]
        mov     [ebp+4*edi],eax  ;Move them to the buffer (backward to forward)
        dec     edi
        jmp     @b
  @@:
        test    edx,edx
        je      .end
        xchg    ecx,edx  ;Move to ecx the amount of chars left
  @@:
        lodsb
        mov     byte[ebx+ecx-1],al  ;Move the to the buffer byte by byte
        loop    @b
  .end:
        ret
endp

section '.bss' readable writeable

  szBuffer rb 100h

section '.data' data readable writeable

  szString db 'This is my super long string. Say Hello to it!',0 ;19 chars
  szTitle  db 'String Inversion...',0

section '.idata' import data readable writeable

  library kernel32,'KERNEL32.DLL',\
          user32,'USER32.DLL'

  include 'api\kernel32.inc'
  include 'api\user32.inc'
    
Post 07 Jul 2011, 03:19
View user's profile Send private message Reply with quote
AsmGuru62



Joined: 28 Jan 2004
Posts: 1419
Location: Toronto, Canada
AsmGuru62
Code:
     ;
   ; EDI = non-empty string to reverse
 ;
   xor     eax, eax        ; EAX = 0 (to find null)
    or      ecx, -1         ; ECX = -1 (shorter opcode than MOV)
        mov     esi, edi        ; ESI points to 1st character
       repne   scasb           ; EDI points AFTER null
     sub     edi, 2          ; EDI points to last character
      ;
   ; Reverse - if EDI > ESI only
    ;
@@:
        cmp     edi, esi
    jbe     .done

   lodsb                   ; AL = [ESI]; ++ESI;
        xchg    al, [edi]       ; Swap characters
   mov     [esi-1], al
 dec     edi             ; --EDI (to meet with ESI)
  jmp     @r              ; loop until pointers will meet

.done:
    
Post 07 Jul 2011, 10:58
View user's profile Send private message Send e-mail Reply with quote
JoeCoder1



Joined: 13 Jun 2011
Posts: 62
JoeCoder1
That's a nice looking piece of code there AsmGuru62. I like the way you lay things out. I'm still clueless in x86 land and even more clueless in fasm, would you mind explaining the @@ label and the jmp to @r? What does that do? (not that I understand the other stuff but at least I know where to look most of it up!)
Post 07 Jul 2011, 11:10
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 17715
Location: In your JS exploiting you and your system
revolution
JoeCoder1: I hope you have read the fasm manual. Because rather than asking others to explain things here, it would be faster and easier to read it from the source document. There is a link at the bottom of every page in these forums: "Documentation".

http://flatassembler.net/docs.php?article=manual#1.2.3
Post 07 Jul 2011, 11:17
View user's profile Send private message Visit poster's website Reply with quote
JoeCoder1



Joined: 13 Jun 2011
Posts: 62
JoeCoder1
Well I was speaking to AsmGuru62 and if he doesn't want to answer me, he doesn't have to. Wink

His code caught my eye because he lays everything out consistently. I have found a consistent style a big help in writing good code, so I suspect he knows what he is doing, if this snippet is any example.

You didn't have to answer me either, but I appreciate the help. No, I haven't read the doc cover to cover because I have a lot going on and don't often find time to focus on just one thing. I'm trying to learn x86 between meetings and writing code for my job. I realize you guys are also busy so if you ignore me I have no issue.

I have to admit, looking at the link you just posted, I have another question. What is the difference between @b and @r? The doc says they're equivalent. So why have both? Thank you.
Post 07 Jul 2011, 12:28
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 17715
Location: In your JS exploiting you and your system
revolution
JoeCoder1 wrote:
I have another question. What is the difference between @b and @r? The doc says they're equivalent. So why have both?
Backwards compatibility with some other, older, assemblers. Some people still have old code lying around and might want to copy/paste it without too much alteration.
Post 07 Jul 2011, 12:47
View user's profile Send private message Visit poster's website Reply with quote
AsmGuru62



Joined: 28 Jan 2004
Posts: 1419
Location: Toronto, Canada
AsmGuru62
@@: labels are great, but it is easy to get burned. Once, I had a small loop, so I can see all loop body on one page. After a year or so - I needed to add some code into the loop and it came longer, so it did not fit into a page. After some more coding - I added a small loop inside the first one (did not see the first @@Smile, using the same type of label @@: - of course, the whole contraption no longer worked! So, it is not for nested loops I believe.

Joe, I like to separate code blocks with empty lines or with some comments - when I get back into it after some time - it is an easy read! btw, FASM source goes like a straight pile of lines - tough to read.
Post 07 Jul 2011, 14:06
View user's profile Send private message Send e-mail Reply with quote
edfed



Joined: 20 Feb 2006
Posts: 4242
Location: 2018
edfed
if every loops are functions, then, there is no limit (just the stack) to the count of nested loops.
Code:
main:
call @f
ret
;;;;;;;;;;;;;
@@:
call @f
loop @b
ret
@@:
call @f
loop @b
ret
@@:
call @f
loop @b
ret
@@:
ret
    

but it needs a call and a ret per loop.

and to reverse a string, you can use this kind of function:
Code:
stringreverse:
;esi=string
;ecx=size
mov eax,0
dec ecx
jl .end
@@:
mov bl,[esi+eax]
mov bh,[esi+ecx]
mov [esi+eax],bh
mov [esi+ecx],bl
inc eax
dec ecx
cmp eax,ecx
jl @b
.end:
ret
    

something like that
as there is no loss of information, i don't see why it can be better to do the reverse in another buffer.
if you want a copy of the initial string, save it using a copymem function.
Post 07 Jul 2011, 20:56
View user's profile Send private message Visit poster's website Reply with quote
typedef



Joined: 25 Jul 2010
Posts: 2913
Location: 0x77760000
typedef
well you can do it it recursively. For example in C it would be
Code:

int reverse(char string1[],char string2[],int index,int size)
{
 if(size-index==size)
     string2[size+1]='\0';
   return 0;

string2[size-index]=string1[index];
return(reverse(string1,string2,index-1,size));
}

int main()
{

char s1[6] ="Hello";
char s2[6];

reverse( s1,s2,5,5);


}


}

    
Post 07 Jul 2011, 22:57
View user's profile Send private message Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4633
Location: Argentina
LocoDelAssembly
I think it would be better to just:
Code:
static char *_reverse(char *src, char *dst)
{
  char *p;

  if (*src == '\0')
    return dst;

  p = _reverse(src + 1, dst);
  *p = *src;

  return p++;
}
void reverse(char *src, char *dst)
{
  *(_reverse(src, dst)) = '\0';
  
  return;
}    
Code:
proc reverse c, src, dst
  mov  edx, [src]
  mov  eax, [dst]
  call .reverse
  mov  byte [eax], 0
  ret

.reverse:
  cmp  byte [edx], 0
  jne  @f
  retn

@@:
  inc  edx
  call .reverse
  dec  edx ; Cheating a bit to save stack :D
  mov  cl, [edx]
  mov  [eax], cl
  inc  eax
  retn
endp    
I haven't tested the C code, and the assembly code was only briefly tested.
Post 08 Jul 2011, 01:13
View user's profile Send private message Reply with quote
typedef



Joined: 25 Jul 2010
Posts: 2913
Location: 0x77760000
typedef
Is he even here ? Very Happy...
Post 08 Jul 2011, 02:42
View user's profile Send private message Reply with quote
Picnic



Joined: 05 May 2007
Posts: 1288
Location: Paradise Falls
Picnic
Simple solution to reverse a string. bitRAKE post in asmcommunity.net
Code:
        mov esi, string
        mov edi, esi

        xor eax, eax
        @@:push eax
        lodsb
        test al, al
        jne @B
        @@:pop eax
        stosb
        test eax, eax
        jne @B
       
    
Post 08 Jul 2011, 06:09
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  
Goto page 1, 2  Next

< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2020, Tomasz Grysztar. Also on GitHub, YouTube, Twitter.

Website powered by rwasa.