News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

MemBlocks and Managed Strings

Started by Biterider, January 19, 2024, 09:08:49 AM

Previous topic - Next topic

Biterider

Hi
For a while, I had been considering coding something that I called a StringManager.
I tried several times to write the code, but each time I gave up when I realised that it would require a considerable amount of code to cover all the formats and functions. Finally, I decided to give up.

Recently I have combined some old ideas from the COM development days with the alignment requirements that come mainly from the newer SSE and AVX instruction sets.

I came up with something I call MemBlocks, which is nothing more than a control structure followed by a payload. This construct is placed in memory (stack, .data, .const, Heap) in such a way that the payload is aligned with a predetermined value.
An important feature is the granularity of the payload in combination with the minimal capacity. Both are important to ensure correct access with SSE/AVX instructions.

A bit of pointer magic like that of BSTRs allows us to use existing string routines, with the great advantage that we know beforehand the capacity of the MemBlock and its current usage by simply looking into the control block.
A straightforward calculation determines whether the MemBlock needs to be enlarged or replaced, depending on the memory segment used.

The layout of a MemBlock looks like:

;                                                              MemBlock points here!
;        Offset BYTEs    WORD     WORD      DWORD         DWORD    v
;       ————————————————————————————————————————————————————————————————————————————————————
;  ... |  Padding     | Offset | Flags |  BYTE Size  | BYTE Usage  | BYTE Payload           | ...
;       ————————————————————————————————————————————————————————————————————————————————————
;      ^                                                           ^
;      Heap Alignment 8/16                                         Alignment 4/8/16/32/...
;
;                                                     <------------------------------------>
;                                                      BSTR if the payload is a WIDE string

The process involves many small details, but ultimately, I believe it is a nice solution that provides an effective solution to common programming issues.

The ObjAsm code base has now support for some, no all yet, macros and procs that support MemBlocks.

Note:  The macros and procedures that are specialized for string handling are grouped together with the prefix MStr (Managed String).

Biterider

HSE

Hi Biterider!

Quote from: Biterider on January 19, 2024, 09:08:49 AMThe ObjAsm code base has now support

That don't sound good.  :biggrin:

I don't know how many times I wrote "$Obj" yesterday, but perhaps I never will use namespaces :biggrin:  :biggrin:  :biggrin:

Regards, HSE.
Equations in Assembly: SmplMath

Biterider

Quote from: HSE on January 19, 2024, 11:00:50 AMThat don't sound good.  :biggrin:

I hope you meant it ironically...  :cool:

Biterider

HSE

Hi Biterider!

Quote from: Biterider on January 19, 2024, 06:14:13 PMI hope you meant it ironically...  :cool:

Not exactly. Probably I never will use AVX. If that make base code more complex, is for nothing.

I have a similar problem with SmplMath, and so far I don't added things that make more complex the base code in GitHub. I'm thinking in an "Advanced Full Version" and an "Essential Version" or something like that. I don't know.

HSE
Equations in Assembly: SmplMath

Biterider

Hi HSE
Quote from: HSE on January 19, 2024, 08:58:04 PMNot exactly. Probably I never will use AVX. If that make base code more complex, is for nothing.
I see your point now, and I can assure you that this is not the case. 
MemBlocks and MStr are features that have nothing to do with OOP and they do not change the syntax of anything that existed before.
You can use MemBlocks or the managed strings if you want to, or go the way you did before. It is entirely your choice  :biggrin:

In terms of namespaces, there is a very straightforward way to omit the use of $Obj().
Change these lines in Objects.inc (~line 80):

;Global object namespace
;OBJASM_NAMESPACE        textequ <OA>                    ;Default namespace
;??ObjPfxSep             textequ <_>                     ;Cosmetic separator
OBJASM_NAMESPACE        textequ <>                     ;Default namespace
??ObjPfxSep             textequ <>                     ;Cosmetic separator

Regards, Biterider

HSE

Hi Biterider,

Quote from: Biterider on January 19, 2024, 09:35:09 PMChange these lines in Objects.inc (~line 80):

Not to know that 2 days ago :eusa_snooty:

Anyway that make code incompatible  :biggrin:

HSE
Equations in Assembly: SmplMath

Biterider

Hi
I want to show the use of "MStr"ings allocated on segments.

In the first example shown, we put an MStr on the .data segment at compile time. The $OfsDMStr macro takes 2 parameters, the reservation size in bytes and a quoted text which is the initial payload of the MemBlock. The offset that is returned corresponds to the payload of the MemBlock, that is to say to the string.
Since the reserved 64 bytes of extra free space, we can use it to perform some operations in situ. This is what happens next when we append another MStr using the MStrCat proc. If the concatenated result does not fit into the total reserved space, a new MStr with enough capacity is created on the heap and the operation is performed on it. In the latter case, the address returned corresponds to the new heap MStr.

In the second example, we start from a constant MStr, which is immutable and has no extra space. If we want to perform an operation on it, an MStr is created on the heap, as shown in the first example.

Dynamic "MStr"ings allocated on the heap are automatically resized, but that will be explained in the next post.

It is a good practice to free a MStr using MStrFree regardless of its allocation type. The proc is smart enough to do the right thing.

  mov xcx, $OfsDMStr(64, "Hello ")
  DbgHex xcx
  invoke MStrCat_XT, xcx, $OfsCMStr("World")
  DbgHex xax
  DbgMStr xax
  MStrFree xax

  mov xcx, $OfsCMStr("Hello ")
  DbgHex xcx
  invoke MStrCat_XT, xcx, $OfsCMStr("World")
  DbgHex xax
  DbgMStr xax
  MStrFree xax

The result shown on DebugCenter (x64) looks like
xcx = 00007FF70BC1B780h
xax = 00007FF70BC1B780h
Offset=0000h, Flags=0001h, Size=00000020h, Used=00000018h, Payload=Hello World
xcx = 00007FF70BC12AF0h
xax = 000002CFD88E4950h
Offset=0004h, Flags=0003h, Size=00000040h, Used=00000018h, Payload=Hello World

In the first case we can clearly see that the MStr offset in the .data segment (xcx = xax) has not changed, whereas in the second case (xcx => xax) we see a new heap address!  :cool:

Regards, Biterider


Biterider

Hi
Managed strings can also be placed on the stack, and they do all the same magic as dynamically allocated MStrings.  :biggrin:

They require some space on the stack, which is reserved using a handy macro called $MStr.
It takes 2 arguments, the name of the string variable and the required capacity in characters.

Before it can be used it needs to be initialised and in some cases an initial value is required. This can be done by calling $MStrInit, which conveniently returns the address of the payload.
$MStrInit also takes 2 arguments. The first is the name we used to allocate space on the stack and the second is a vararg containing a sequence of numbers, quoted strings or a mixture of both to initialise the string.
An example might be:

local $MStr(StackStr, 100)

...
mov xcx, $MStrInit(StackStr, "Hello World", CRLF)
...


where CRLF = 13, 10

An advantage of this type of allocation is that it does not require deallocation, since the stack is freed when the procedure returns to the caller.

Biterider