flat assembler
Message board for the users of flat assembler.

Index > Windows > An example of adding multiple strings using HeapReAlloc

Author
Thread Post new topic Reply to topic
bdo1964



Joined: 18 Sep 2011
Posts: 7
bdo1964
I did not see any relatively simple examples of dynamically allocating strings...

so..

Code:
include 'win32a.inc'
format PE console 4.0
entry start
;***********************************************
section '.data' data readable writeable
;***********************************************
_s db '%s',13,0
_i db '%i',13,0
;***********************************************
hheap               dd 0
hbuffer         dd 0
s1              db 'this is line 1',13,0
s2                db 'this is line 2',13,0
s3                db 'this is line 3',0
;***********************************************
section '.text' code readable executable
;***********************************************
start:             ;fasm_add_strings.fasm
invoke                HeapCreate,0,4096,0
mov              dword[hheap],eax
invoke              HeapAlloc,[hheap],$8,1 ;<<< ONE BYTE!!!
mov         dword[hbuffer],eax
xor               ebx,ebx
;-----------------------------------------------
stdcall          len,s1
inc           eax
add              ebx,eax
invoke               HeapReAlloc,[hheap],0,[hbuffer],ebx
stdcall          addstr,[hbuffer],[hbuffer],s1
mov            dword[hbuffer],eax
;-----------------------------------------------
stdcall               len,s2
inc           eax
add              ebx,eax
invoke               HeapReAlloc,[hheap],0,[hbuffer],ebx
stdcall          addstr,[hbuffer],[hbuffer],s2
mov            dword[hbuffer],eax
;-----------------------------------------------
stdcall               len,s3
inc           eax
add              ebx,eax
invoke               HeapReAlloc,[hheap],0,[hbuffer],ebx
stdcall          addstr,[hbuffer],[hbuffer],s3
mov            dword[hbuffer],eax
;-----------------------------------------------
cinvoke               printf,_s,[hbuffer]
invoke           HeapDestroy,[hheap]
invoke           ExitProcess,0
;***********************************************
proc addstr stdcall uses esi edi ecx,hbuffer,s1,s2
locals
   len_s1  dd ?
endl
mov     esi,[s1]
mov edi,dword[hbuffer]
xor       eax,eax
xor  ecx,ecx
@@:
mov       al,byte[esi+ecx]
mov byte[edi+ecx],al
inc ecx
cmp      al,0
jnz     @b
dec       ecx
mov      dword[len_s1],ecx
;-----------------------------------------------
mov    esi,[s2]
add edi,dword[len_s1]
xor        eax,eax
xor  ecx,ecx
@@:
mov       al,byte[esi+ecx]
mov byte[edi+ecx],al
inc ecx
cmp      al,0
jnz     @b
dec       ecx
mov      eax,dword[hbuffer]
ret
endp
;***********************************************
proc len stdcall uses ecx edi,String
xor    eax,eax
xor  ecx,ecx
mov  edi,[String]
@@:
mov  al,byte[edi+ecx]
inc ecx
cmp      al,0
jne     @b
dec       ecx
mov      eax,ecx
ret
endp
;***********************************************
section '.idata' data import readable writeable
  library kernel32,'kernel32.dll',\
          msvcrt,'msvcrt.dll'
  include 'api\kernel32.inc'
  import msvcrt,\
         printf,'printf'
;***********************************************
    

_________________
briano
Post 12 Dec 2011, 22:22
View user's profile Send private message Reply with quote
JohnFound



Joined: 16 Jun 2003
Posts: 3502
Location: Bulgaria
JohnFound
If you need extensive string processing, you can see StrLib from the package FreshLib
Besides the big set of functions for dynamic string processing, it also provides portability among different OSes (in this moment Win32 and Linux).
Post 13 Dec 2011, 07:08
View user's profile Send private message Visit poster's website ICQ Number Reply with quote
bdo1964



Joined: 18 Sep 2011
Posts: 7
bdo1964
but this example is for folks who were interested in writing
their own programming language with strings of unlimited
length... in this case {s1,s2,s3} would represent:

Code:
myStr$ = ""
myStr$ + "this is line 1" + chr(13)
myStr$ + "this is line 2" + chr(13)
myStr$ + "this is line 3" + chr(13)    

_________________
briano
Post 13 Dec 2011, 19:47
View user's profile Send private message Reply with quote
JohnFound



Joined: 16 Jun 2003
Posts: 3502
Location: Bulgaria
JohnFound
Yes, I understand it. But building everything from scratch is not the best thing, if you want to build some complex system.
For example, with StrLib, your example will look like:
Code:
stdcall StrNew  ; create the string
stdcall StrCat, eax, s1 ; add line1
stdcall StrCat, eax, s2 ; add line2
stdcall StrCat, eax, s3 ; add line3
    
Post 13 Dec 2011, 19:56
View user's profile Send private message Visit poster's website ICQ Number Reply with quote
bdo1964



Joined: 18 Sep 2011
Posts: 7
bdo1964
you make a good point...

if i were writing a compiler... with fasm as the backend...

the fact that FreshLib is a portable library would come in handy...

and i thank you for your post!!!

since i was providing the example for the benefit of others...
your comments about the existence of FreshLib... will provide folks with additional information...

it looks like you have done a lot of work!

_________________
briano
Post 15 Dec 2011, 06:04
View user's profile Send private message Reply with quote
f0dder



Joined: 19 Feb 2004
Posts: 3170
Location: Denmark
f0dder
1) keep in mind that HeapReAlloc might not always be able to reallocate in place - your code doesn't handle this.
2) memory (re)allocation is expensive, it's much better to over-allocate and avoid calls to the heap manager.
3) NUL terminated strings are, for a lot of use cases, pretty darn slow.
Post 15 Dec 2011, 17:19
View user's profile Send private message Visit poster's website Reply with quote
AsmGuru62



Joined: 28 Jan 2004
Posts: 1412
Location: Toronto, Canada
AsmGuru62
The good way is a string pool, where there is a vector of string pointers and every string is a small structure where the room for string buffer and its real length are stored. Also, as f0dder mentioned reallocate string by chunks of say, 32 characlers in size or even double the room in each reallocation. This will save a lot of CPU cycles during concatenation. Put all the allocations into one heap, so when destroying that whole pool - no need to call HeapFree thousands of times, just call HeapDestroy once. Very fast! I used it for my code parser in IDE. The fact that each string has a length allows for quick searching of needed string, because code skips all strings which are not of the specified length.
Post 15 Dec 2011, 17:33
View user's profile Send private message Send e-mail Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 17450
Location: In your JS exploiting you and your system
revolution
f0dder wrote:
2) memory (re)allocation is expensive, it's much better to over-allocate and avoid calls to the heap manager.
Well, "better" is not well defined. Your idea of better probably doesn't match the OPs idea of better.
f0dder wrote:
3) NUL terminated strings are, for a lot of use cases, pretty darn slow.
Fortunately the OP didn't state any requirement for speed or efficiency, merely for it to be simple. Being simple is good when your application is very light (does not involve expending huge computing resources over large periods of time) and when getting it working correctly with little fuss is desired over more involved code that has more potential to hide bugs.
f0dder wrote:
1) keep in mind that HeapReAlloc might not always be able to reallocate in place - your code doesn't handle this.
Indeed. Error handling is of utmost importance (unless OP can guarantee some sort of memory availability by earlier startup queries for system state and has 100% control over all potentially competing tasks that might request RAM).
Post 15 Dec 2011, 17:38
View user's profile Send private message Visit poster's website Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 17450
Location: In your JS exploiting you and your system
revolution
AsmGuru62 wrote:
The good way is a string pool, ...
Well, another way at least. "Good"? Maybe. It depends upon what you need to achieve.
AsmGuru62 wrote:
... where there is a vector of string pointers and every string is a small structure where the room for string buffer and its real length are stored. Also, as f0dder mentioned reallocate string by chunks of say, 32 characlers in size or even double the room in each reallocation. This will save a lot of CPU cycles during concatenation. Put all the allocations into one heap, so when destroying that whole pool - no need to call HeapFree thousands of times, just call HeapDestroy once.
Whoa, not exactly simple!
AsmGuru62 wrote:
Very fast!
But I suspect irrelevant.


Last edited by revolution on 15 Dec 2011, 17:56; edited 1 time in total
Post 15 Dec 2011, 17:43
View user's profile Send private message Visit poster's website Reply with quote
AsmGuru62



Joined: 28 Jan 2004
Posts: 1412
Location: Toronto, Canada
AsmGuru62
For me speed was the most important.
Post 15 Dec 2011, 17:52
View user's profile Send private message Send e-mail Reply with quote
f0dder



Joined: 19 Feb 2004
Posts: 3170
Location: Denmark
f0dder
revolution: very valid points - the first post does mention simplicity, but the OP's next post also mentions "writing their own programming language", so... Smile

Btw, dynamically reallocating strings isn't always the best solution, either - consider situations with multithreaded code where strings are used from multiple threads... you'll end up needing copy-on-write and performance-killing mutexing. Immutable strings are interesting in those scenarios, but you pretty much need garbage collection for that to work well enough, and that brings in it's own set of problems.

There's no silver bullet Smile
Post 15 Dec 2011, 18:05
View user's profile Send private message Visit poster's website Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 17450
Location: In your JS exploiting you and your system
revolution
f0dder wrote:
Btw, dynamically reallocating strings isn't always the best solution, either ...
No one here said it was.
f0dder wrote:
... - consider situations with multithreaded code where strings are used from multiple threads... you'll end up needing copy-on-write and performance-killing mutexing.
But performance was never mentioned. Simplicity was mentioned.
Post 15 Dec 2011, 18:33
View user's profile Send private message Visit poster's website Reply with quote
bdo1964



Joined: 18 Sep 2011
Posts: 7
bdo1964
i am absolutely blown away by these responses!

thank you all very much!

in the case that the parser was to encounter:

Code:
myStr$ = ""
myStr$ + "this is line 1" + chr(13)
myStr$ + "this is line 2" + chr(13)
myStr$ + "this is line 3" + chr(13)
    


dynamically reallocating strings would not be necessary...

Code:
s_myStr:
db       "this is line 1" ,13
db    "this is line 2" ,13
db    "this is line 3" ,13
db    0
e_myStr:
    


nor would NULL terminated strings be required...

Code:
        mov     ecx,e_myStr-s_myStr
 dec     ecx
    


obviously we have no exception handling...

STATUS_NO_MEMORY
The allocation attempt failed because of a lackof available memory or heap corruption.

STATUS_ACCESS_VIOLATION
The allocation attempt failed because of heap corruptionor improper function parameters.

so how about some input regarding:

passing strings in and out of MS COFF object files assembled via fasm????
Post 16 Dec 2011, 03:12
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< 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 YouTube, Twitter.

Website powered by rwasa.