flat assembler
Message board for the users of flat assembler.
Index
> Main > MASM to FASM reverse string Goto page 1, 2 Next |
Author |
|
JohnFound 06 Jul 2011, 12:08
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 |
|||
06 Jul 2011, 12:08 |
|
edfed 06 Jul 2011, 12:10
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. |
|||
06 Jul 2011, 12:10 |
|
AsmGuru62 06 Jul 2011, 14:00
Seems to me its too much code to just reverse a string.
|
|||
06 Jul 2011, 14:00 |
|
Synaps3 06 Jul 2011, 17:03
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 |
|||
06 Jul 2011, 17:03 |
|
LocoDelAssembly 06 Jul 2011, 17:36
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.
|
|||
06 Jul 2011, 17:36 |
|
Synaps3 06 Jul 2011, 18:10
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. |
|||
06 Jul 2011, 18:10 |
|
ctl3d32 06 Jul 2011, 18:41
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 |
|||
06 Jul 2011, 18:41 |
|
ctl3d32 07 Jul 2011, 03:19
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' |
|||
07 Jul 2011, 03:19 |
|
AsmGuru62 07 Jul 2011, 10:58
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: |
|||
07 Jul 2011, 10:58 |
|
JoeCoder1 07 Jul 2011, 11:10
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!)
|
|||
07 Jul 2011, 11:10 |
|
revolution 07 Jul 2011, 11:17
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 |
|||
07 Jul 2011, 11:17 |
|
JoeCoder1 07 Jul 2011, 12:28
Well I was speaking to AsmGuru62 and if he doesn't want to answer me, he doesn't have to.
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. |
|||
07 Jul 2011, 12:28 |
|
revolution 07 Jul 2011, 12:47
JoeCoder1 wrote: I have another question. What is the difference between @b and @r? The doc says they're equivalent. So why have both? |
|||
07 Jul 2011, 12:47 |
|
AsmGuru62 07 Jul 2011, 14:06
@@: 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 @@, 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. |
|||
07 Jul 2011, 14:06 |
|
edfed 07 Jul 2011, 20:56
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. |
|||
07 Jul 2011, 20:56 |
|
typedef 07 Jul 2011, 22:57
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); } } |
|||
07 Jul 2011, 22:57 |
|
LocoDelAssembly 08 Jul 2011, 01:13
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 |
|||
08 Jul 2011, 01:13 |
|
typedef 08 Jul 2011, 02:42
Is he even here ? ...
|
|||
08 Jul 2011, 02:42 |
|
Picnic 08 Jul 2011, 06:09
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 |
|||
08 Jul 2011, 06:09 |
|
Goto page 1, 2 Next < Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.