News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Where is the memory function "Malloc" ?

Started by zjw, August 05, 2009, 02:02:45 AM

Previous topic - Next topic

zjw

Where is the memory function "Malloc", I can't find it.

dedndave


donkey

If you are looking for COM task memory implemented through IMalloc, you can use CoTaskMemAlloc.
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

MichaelW

If you are looking for the CRT malloc and related functions, they are accessible with the MASM32 libraries by prefixing the function names with "crt_".

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    include \masm32\include\masm32rt.inc
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    .data

    .code
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
start:
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    invoke crt_malloc, 1000000
    mov ebx, eax
    print uhex$(ebx),"h",13,10

    invoke crt__msize, ebx
    print ustr$(eax),13,10

    invoke crt_realloc, ebx, 2000000
    mov ebx, eax
    print uhex$(ebx),"h",13,10

    invoke crt__msize, ebx
    print ustr$(eax),13,10

    invoke crt__expand, ebx, 1000000
    print uhex$(eax),"h",13,10
    print uhex$(ebx),"h",13,10

    invoke crt__msize, ebx
    print ustr$(eax),13,10,13,10

    invoke crt_free, ebx

    inkey "Press any key to exit..."
    exit
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
end start

eschew obfuscation

zjw

I am sorry, I meant that I can't find it in "m32lib" folder, but it was in "masmlib.chm" help file.

MichaelW

I think the actual procedure is Alloc defined in \masm32\m32lib\alloc.asm, and the mating procedure to free the memory is Free defined in \masm32\m32lib\free.asm.

eschew obfuscation

zjw

I agree with you. But, it's fault in the help file???

zjw


jj2007

The Masm32 library offers two handy macros:

mov edi, alloc$(1024)
... do stuff ...
free$ edi

mov edi, halloc(1024)
... do stuff ...
hfree edi


Below Olly's disassembly. I would go for halloc/hfree rather than the OLE strings. By the way: Does anybody know what happens to OLE strings if a program exits abnormally? Heap allocated memory is no problem, it's cleared automatically...

0040101D       |.  68 00040000             push 400
00401022       |.  6A 00                   push 0
00401024       |.  E8 1D010000             call <jmp.&oleaut32.SysAllocStringByteLen>
00401029       |.  C600 00                 mov byte ptr [eax], 0
0040102C       |.  8BF8                    mov edi, eax
0040102E       |.  57                      push edi
0040102F       |.  E8 18010000             call <jmp.&oleaut32.SysFreeString>
00401034       |.  E8 E9000000             call <jmp.&kernel32.GetProcessHeap>          ; [GetProcessHeap
00401039       |.  68 00040000             push 400                                     ; /HeapSize = 400 (1024.)
0040103E       |.  6A 00                   push 0                                       ; |Flags = 0
00401040       |.  50                      push eax                                     ; |hHeap
00401041       |.  E8 E2000000             call <jmp.&kernel32.HeapAlloc>               ; \HeapAlloc
00401046       |.  8BF8                    mov edi, eax
00401048       |.  E8 D5000000             call <jmp.&kernel32.GetProcessHeap>          ; [GetProcessHeap
0040104D       |.  57                      push edi                                     ; /pMemory
0040104E       |.  6A 00                   push 0                                       ; |Flags = 0
00401050       |.  50                      push eax                                     ; |hHeap
00401051       |.  E8 D8000000             call <jmp.&kernel32.HeapFree>                ; \HeapFree

MichaelW

There is also the alloc and free macros that use GlobalAlloc and GlobalFree. This is a quick test of the alignment for the allocated memory. Of the 6 methods tested, only Alloc maintains an alignment > 8.

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    include \masm32\include\masm32rt.inc
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

    alignment MACRO ptr
      xor eax, eax
      mov ecx, ptr
      bsf ecx, ecx  ;; starting at bit0, find first set bit
      jz @F
      mov eax, 1
      shl eax, cl
    @@:
      EXITM <eax>
    ENDM

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    .data
    .code
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
start:
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

    print "alloc$:",13,10
    REPEAT 10
      mov ebx, alloc$(16384)
      print ustr$(alignment(ebx)),9
    ENDM
    print chr$(13,10)
    print "alloc:",13,10
    REPEAT 10
      mov ebx, alloc(16384)
      print ustr$(alignment(ebx)),9
    ENDM
    print chr$(13,10)
    print "halloc:",13,10
    REPEAT 10
      mov ebx, halloc(16384)
      print ustr$(alignment(ebx)),9
    ENDM
    print chr$(13,10)
    print "Alloc:",13,10
    REPEAT 10
      invoke Alloc, 16384
      mov ebx, eax
      print ustr$(alignment(ebx)),9
    ENDM
    print chr$(13,10)
    print "CoTaskMemAlloc:",13,10
    REPEAT 10
      invoke CoTaskMemAlloc, 16384
      mov ebx, eax
      print ustr$(alignment(ebx)),9
    ENDM
    print chr$(13,10)
    print "crt_malloc:",13,10
    REPEAT 10
      invoke crt_malloc, 16384
      mov ebx, eax
      print ustr$(alignment(ebx)),9
    ENDM
    print chr$(13,10)

    inkey "Press any key to exit..."
    exit
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
end start


Results under Windows 2000:

alloc$:
4       4       4       4       4       4       4       4       4       4

alloc:
16      8       32      8       16      8       128     8       16      8

halloc:
32      8       16      8       64      8       16      8       32      8

Alloc:
32      32      32      32      32      32      32      32      32      32

CoTaskMemAlloc:
16      8       256     8       16      8       32      8       16      8

crt_malloc:
32      8       8       16      8       32      8       16      8       128

eschew obfuscation

jj2007

Same under Win XP, SP2. Ever heard of "OLE Chicken"?

And I still like to know what happens if during testing of my apps they repeatedly crash with a hundred megs allocated... ::)

alloc$:
4       4       4       4       4       4       4       4       4       4

alloc:
8       16      8       32      8       16      8       64      8       16

halloc:
8       32      8       16      8       512     8       16      8       32

Alloc:
32      32      32      32      32      32      32      32      32      32

CoTaskMemAlloc:
8       16      8       64      8       16      8       32      8       16

crt_malloc:
32      8       8       16      8       32      8       16      8       128

jj2007

#11
For the SSE2 fans, here is a wrapper that uses HeapAlloc and aligns on a 16-byte boundary:

      mov ebx, Alloc16$(16384)
      ... do stuff ...
      Free16 ebx


Alloc16$ MACRO ct
push ct
call jallocP
  EXITM <eax>
ENDM

Free16 MACRO ptr
push ptr
call jallocP0
ENDM

.code
jallocP proc ; arg: bytecount
pop eax ; trash return address
xchg eax, [esp] ; exchange counter with return address
  add eax, 16 ; we need 8 or 16 extra bytes
  push eax ; the byte count
  LET_IT_CRASH = 0
  if LET_IT_CRASH
  push HEAP_GENERATE_EXCEPTIONS
else
push 0
endif
  invoke GetProcessHeap
  push eax
  call HeapAlloc ; mov eax, rv(HeapAlloc,rv(GetProcessHeap),0,bytecount)
  push 8
  pop ecx ; create some space for the alignment flag
test al, 15 ; original pointer aligned 16?
jne @F
add ecx, ecx ; yes: add 16, no: add 8
@@: add eax, ecx
mov [eax-4], ecx ; set the flag
ret 0 ; we popped one value, and there is no stack frame
jallocP endp

jallocP0 proc ; arg: pointer
pop eax ; trash return address
xchg eax, [esp] ; exchange ptr with return address
sub eax, [eax-4] ; subtract flag
push eax ; original pointer
push 0
invoke GetProcessHeap
push eax
call HeapFree ; invoke HeapFree,rv(GetProcessHeap),0,memory
ret 0 ; we popped one value, and there is no stack frame
jallocP0 endp
.const


EDIT: I shortened the proc a bit - now 64 bytes exactly :bg
EDIT(2): Down to 58 bytes for the proc, and 10+6 bytes for the alloc+free calls, as compared to 18+14 for a halloc/hfree pair. For comparison: BloatOS (XP, SP2) needs 1,500,000,000 bytes on disk, and apparently that was not enough to provide an API that takes account of the fact that SSE2 (on the market since 2001) needs 16-byte boundaries.

jj2007

What is really surprising is that invoke crt_malloc, 16384 returns 8-byte alignment only. I checked with Olly, it does call malloc. The latter, according to MSDN, "is required to return memory on a 16-byte boundary". The full MSDN malloc page says cryptically "The storage space pointed to by the return value is guaranteed to be suitably aligned for storage of any type of object". Well, any except memory needed for SSE2... :tdown

MichaelW

I think the "suitably aligned for storage of any type of object" statement far predates SSE2.
eschew obfuscation

dedndave

i was thinking that requests should always be page-sized, as well
i.e. if you need 1009 bytes, request 1024
that way, issued block sizes are always on 16-byte boundries
i don't know if that would cause them to start on 16-byte boundries, as well
in DOS, each heap allocation was aligned to 16-bytes and was preceeded in memory by a 16-byte "heap allocation header"
but i think that was done because of x86 real-mode segmented architecture