Hello there!
I'm new to the community. I'm a computer engineering III student (systems). I've already programmed on C++, Pascal, and some other languages for university projects and assignments, so I'm not new to programming. However, I'm having a really hard time trying to figure out how to work with MASM32 assembler (...in console mode :'( ). I've already understood the very basics, but still, there is a lot for me to learn.
I'm having problems with dynamic memory allocation. The following code seems to work properly, but I have many questions about it.
;This is my very first dynamic memory attempt!
;
;theta is declared as "theta dword ?". I thought it could work as a pointer to byte
;stheta is the length of theta in bytes.
;We calculate the size in bytes of the Theta vector.
;num is a value input by the user. Theta's length = num +2
mov eax,num
add eax,2
mov stheta,eax
;we allocate the memory (...this seems to work, but am i doing it right?) Is crt_malloc the appropriate function to do this?
invoke crt_malloc, stheta
mov theta,eax
;we tell the user what we just did
print " - allocated "
print uhex$(stheta), "h bytes for Theta, in adress "
print uhex$(theta), endl
; BIG QUESTION :
; How can i read/write on theta?!
; For example, how can i move 230 (or 'A') onto the position i-th of the array?. I know it's something basic, but i have no clue about how to do it.
invoke crt_free,theta
; How in the world does this work? i'm not giving "crt_free" any numerical value of the array's size, so either the array length is coded into the array (Pascal-like)
; and accessing certain positions could mess things up, or it's stored somewhere else in my program.
Thanks in advance!!
JRevor,
You are doing everything correctly. I modified your code to answer your questions.
.686p
.MODEL FLAT,STDCALL
OPTION CASEMAP:NONE
INCLUDE \masm32\include\Windows.inc
INCLUDE \masm32\include\Kernel32.inc
INCLUDE \masm32\include\MSVCRT.inc
INCLUDE \masm32\include\Masm32.inc
INCLUDELIB \masm32\lib\Kernel32.lib
INCLUDELIB \masm32\lib\MSVCRT.lib
INCLUDELIB \masm32\lib\Masm32.lib
INCLUDE \masm32\macros\macros.asm
WaitKeyExit PROTO
PTRBYTE TYPEDEF PTR BYTE
.DATA
num DWORD 42h
stheta DWORD 0
theta PTRBYTE 0 ; DWORD is OK too
endl BYTE 13,10,0
.CODE
start:
;This is my very first dynamic memory attempt!
;
;theta is declared as "theta dword ?". I thought it could work as a pointer to byte
;stheta is the length of theta in bytes.
;We calculate the size in bytes of the Theta vector.
;num is a value input by the user. Theta's length = num +2
mov eax, num
add eax, 2
mov stheta, eax
;we allocate the memory (...this seems to work, but am i doing it right?) Is crt_malloc the appropriate function to do this?
invoke crt_malloc, stheta
mov theta, eax
;we tell the user what we just did
INVOKE crt_printf, SADD(" - allocated %Xh bytes for theta, at address %Xh",13,10), stheta, theta
; BIG QUESTION :
; How can i read/write on theta?!
; For example, how can i move 230 (or 'A') onto the position i-th of the array?. I know it's something basic, but i have no clue about how to do it.
mov eax, theta
mov ebx, 0
mov BYTE PTR [eax+ebx], 65 ; mov 'A' to 1st byte
inc ebx
mov BYTE PTR [eax+ebx], 66 ; mov 'B' to 2nd byte
inc ebx
mov BYTE PTR [eax+ebx], 67 ; mov 'C' to 3rd byte
inc ebx
mov BYTE PTR [eax+ebx], 0 ; mov null to 4th byte
INVOKE crt_printf, SADD("theta contains: %s",13,10), theta
invoke crt_free, theta
; How in the world does this work? i'm not giving "crt_free" any numerical value of the array's size, so either the array length is coded into the array (Pascal-like)
; and accessing certain positions could mess things up, or it's stored somewhere else in my program.
INVOKE WaitKeyExit
xor eax, eax
INVOKE ExitProcess, eax
;------------------------------------
WaitKeyExit PROC
.DATA
szPrompt BYTE 13,10,"Press any key to exit ... ",0
szCrLf BYTE 13,10,0
.CODE
INVOKE StdOut, ADDR szPrompt
INVOKE crt__getch
.IF (eax == 0) || (eax == 0E0h)
INVOKE crt__getch
.ENDIF
INVOKE StdOut, ADDR szCrLf
xor eax, eax
ret
WaitKeyExit ENDP
;------------------------------------
END start
Ok, crt stands for C runtime, these functions work in the same way as malloc() and free() in C
For example
Buffer = malloc(Size);
free(Buffer);
The memory is allocated from a much larger pool, and the management of that pool keeps track of the size and location of the block of memory. You can only release that block by passing the original address, so you can't increase the address and release a portion of it.
The equivalent of Buffer[3] = 'A'; would look like
mov esi,Buffer
mov byte ptr [esi+3],041h
The equivalent of Buffer = 'B'; would look like
mov esi,Buffer
mov ebx,dword ptr i
mov byte ptr [esi + ebx],042h
-Clive
Clive,
The functions that are prefixed with crt_ actually are the C Run-Time Library functions. The prefix was added to avoid naming conflicts with the MASM32 library. msvcrt.lib is available on all versions of Windows from Windows 95B to Windows 7.
Quote from: clive on March 07, 2010, 02:04:54 AM
The equivalent of Buffer[3] = 'A'; would look like
mov esi,Buffer
mov byte ptr [esi+3],041h
This shorter variant is also valid, EDIT: if buffer is a location in the .data section:
.data?
Buffer db 1000 dup(?)
.code
mov Buffer[3], "A"
Use it if you want to move only one byte; otherwise, register+offset is a few bytes shorter.
JRevor,
Ther are in fact a number of memory allocation strategies available in Windows and they tend to be tailored to fit different tasks so your choice is a lot wider than the C runtime methods which are provided out of the Windows API function calls in any case.
HeapAlloc()
VirtualAlloc()
GlobalAlloc()
Thenn more specialised versions, OLE string memory for both ANSI and UNICODE, a number of COM specific methods and with the three APIs mentioned there are variations on those as well.
It may sound messy but its very flexible and you can pick your way through the strategies that best fit your task once you are used to them.
Thanks a lot for the reply, all of your responses have been really useful. Specially Greg Lyon's code, which cleared many of my doubts about dynamic memory.
Quote from: clive on March 07, 2010, 02:04:54 AM
The memory is allocated from a much larger pool, and the management of that pool keeps track of the size and location of the block of memory. You can only release that block by passing the original address, so you can't increase the address and release a portion of it.
Thanks for the explanation!
Quote from: hutch-- on March 07, 2010, 06:28:05 AM
JRevor,
Ther are in fact a number of memory allocation strategies available in Windows and they tend to be tailored to fit different tasks so your choice is a lot wider than the C runtime methods which are provided out of the Windows API function calls in any case.
HeapAlloc()
VirtualAlloc()
GlobalAlloc()
Thenn more specialised versions, OLE string memory for both ANSI and UNICODE, a number of COM specific methods and with the three APIs mentioned there are variations on those as well.
It may sound messy but its very flexible and you can pick your way through the strategies that best fit your task once you are used to them.
Definitely sounds interesting... maybe a bit too advanced for me. However, I won't forget to check them out, since those might be useful in the future.
I still have a couple more questions :
- Is there any macro to directly print a register/data as an unsigned decimal number ?
- Is there any macro/function to print certain bytes in a dynamic vector? (for instance, given the vector V = {A,B,C,D,E,F....} , print from 1 to 4, that is BCDE .
- Is there any "power" opcode? (for instance, to calculate a = 2^num)
(EDIT: Eventually I made my own natural power function, but i'm still curious to know if there's one already in the libraries)
- Is there any "memcpy"-like function? (to copy a certain ammount of bytes from one place to another)
- What if i do :
mov eax, theta
mov ebx, 0
mov BYTE PTR [eax+ebx], something ; something is a DWORD.
Am i copying only the first byte of "something" or the whole "something"?
- Is there any opcode to change the color of the text? (...it might sound stupid, but I want to mark relevant data in red)
Once again, thanks a lot!
QuoteIs there any macro to directly print a register/data as an unsigned decimal number ?
A combination of macros, yes. See the documentation for the print macro, and the string conversion macros str$, ustr$, hex$, uhex$, ubyte$, sbyte$, etc.
QuoteIs there any macro/function to print certain bytes in a dynamic vector? (for instance, given the vector V = {A,B,C,D,E,F....} , print from 1 to 4, that is BCDE .
For allocated memory you access the memory as an indirect memory operand and copy the value to a register, then display it. A simple example:
mov ebx, address
mov al, [ebx]
print xbyte$(al),13,10
Many variations are possible.
QuoteIs there any "power" opcode? (for instance, to calculate a = 2^num)
There is no "opcode" that I know of. For something easy you could call the crt pow function.
QuoteIs there any "memcpy"-like function? (to copy a certain ammount of bytes from one place to another)
There is the MASM32 MemCopy procedure, and various similar procedures that have been posted to the Laboratory, or the CRT memcpy or memmove functions.
Quote
What if i do :
mov eax, theta
mov ebx, 0
mov BYTE PTR [eax+ebx], something ; something is a DWORD.
Am i copying only the first byte of "something" or the whole "something"?
The MOV instruction, like most instructions, cannot take two memory operands, so something would need to be a register. The size of the transferred data would be the size of the register, and no ____ PTR would be necessary.
QuoteIs there any opcode to change the color of the text? (...it might sound stupid, but I want to mark relevant data in red)
No opcode, but for the console you should be able to change the color of existing text with the FillConsoleOutputAttribute function.
Fantastic answer, thanks a lot!!!
JRevor,
You can also use SetConsoleTextAttribute to change the color of any text written after the function call, here is a macro I wrote that uses it.
; ====================================
; Color Macro
; ====================================
; This macro uses the following equates
BLACK EQU 0
DARKBLUE EQU 1
DARKGREEN EQU 2
DARKCYAN EQU 3
DARKRED EQU 4
DARKMAGENTA EQU 5
DARKYELLOW EQU 6
GRAY EQU 7
DARKGRAY EQU 8
BLUE EQU 9
GREEN EQU 10
CYAN EQU 11
RED EQU 12
MAGENTA EQU 13
YELLOW EQU 14
WHITE EQU 15
Color MACRO fval:=<LIGHTGRAY>, bval:=<BLACK>
IFNDEF hStdOut
.DATA
hStdOut DWORD 0
.CODE
INVOKE GetStdHandle, STD_OUTPUT_HANDLE
mov hStdOut, eax
ENDIF
.CODE
mov eax, bval
shl eax, 4
or eax, fval
INVOKE SetConsoleTextAttribute, hStdOut, eax
ENDM
; ====================================
fval is foreground, bval is background.
For red text: Color RED, BLACK or just Color RED
JRevor,
One thing forgot to mention is that the memory allocated with crt_malloc is full of junk, so after allocating the memory, if you want to clear it out to zeroes add a line INVOKE RtlZeroMemory, theta, stheta.
JRevor,
As it looks like you are already using the masm32 macros, you can simplify memory allocation by using the "alloc" and "free" macros which work fine for general purpose memory allocation.
Hutch,
Yeah, since he was already using crt_malloc and crt_free and seemed to be somewhat familiar with them, I just continued on using them. Not that there is anything wrong with using them. I wonder which Windows API function crt_malloc actually calls.
Greg,
From a quick dis-assemble of the MSVCRT in my XP SP3 it all looks like the HeapAlloc() family of functions for "malloc".
Hutch,
That was quick!
There is also crt_calloc, but at least under Windows 2000 it is amazingly slow, much slower than the combination of crt_malloc and RtlZeroMemory.
if you use HeapAlloc or GlobalAlloc, you have the option of clearing the allocated memory block
VirtualAlloc always initializes the allocated block to 0
Quote from: dedndave on March 09, 2010, 10:45:24 AM
if you use HeapAlloc or GlobalAlloc, you have the option of clearing the allocated memory block
VirtualAlloc always initializes the allocated block to 0
No matter which method you use, pages on an NT system come back zeroed. The heap will 'preinitialize' several pages for you during the process startup, which it fills with "baadcode" or "baadfood" or something else ridiculous, but any additional pages that get allocated will be zeroed.
Thanks a lot for the answers, I'm definitely learning a lot of stuff (Although, it's not compulsory to "zero" the memory dynamically allocated, and I normally don't do it. It's not difficult to keep track of what is garbage and what is not).
Seeing that this thread is still active, I'll ask another question on the same subject.
Why this code doesn't work at all?
;dwordbuffer is a DWORD, and contains a pointer to a zone within certain dynamically allocated
; memory which was previously accessed as [eax + ebx].
mov dwordbuffer, eax
add dwordbuffer,ebx
; I want to copy the content of msg5( a byte array declared in the .data section of my code)
;to the memory pointed by dwordbuffer
invoke MemCopy,ADDR msg5,dwordbuffer,bytesRead ; CRASH!
EDIT: Also, this doesn't work either. Why?
invoke MemCopy,ADDR msg5,BYTE PTR[eax + ebx],bytesRead
if my memory serves me, MemCpy takes the destination first, and then the source.
The order is correct, src before dest. The byte ptr is the problem. Consider this code:
xor eax, eax
invoke MemCopy, dword ptr [eax + ebx], addr msg5, bytesRead
xor eax, eax
invoke MemCopy, byte ptr [eax + ebx], addr msg5, bytesRead
xor eax, eax
In Olly, you see it as follows:
0040102E |. 33C0 xor eax, eax
00401030 |. FF35 00204000 push dword ptr [402000]
00401036 |. 68 18204000 push 00402018 ; ASCII "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - OK?"
0040103B |. FF3403 push dword ptr [ebx+eax]
0040103E |. E8 2D000000 call 00401070
00401043 |. 33C0 xor eax, eax
00401045 |. FF35 00204000 push dword ptr [402000]
0040104B |. 68 18204000 push 00402018 ; ASCII "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - OK?"
00401050 |. 66:6A 00 push 0
00401053 |. 8A0403 mov al, [ebx+eax]
00401056 |. 66:0FB6C0 movzx ax, al
0040105A |. 66:50 push ax
0040105C |. E8 0F000000 call 00401070
Note the rather odd mov al, [] etc sequence? Masm tries to push the "address" in the byte at [eax+ebx]. 8 bits is a bit short, or rather: 24 bits short of a real 32-bit address ;-)
Here is the working example:
include \masm32\include\masm32rt.inc
.data?
.data
bytesRead dd SIZEOF AppName
AppAddress dd AppName
AppName db "Masm32 is great", 0
msg5 db 100 dup("x")
.code
start:
mov eax, offset AppAddress
xor ebx, ebx
invoke MemCopy, dword ptr [eax + ebx], addr msg5, bytesRead
print offset msg5, " - OK?"
exit
end start
EDIT: Thanks a lot for your responses!
I was really surprised that my code didn't work using BYTE PTR, because Greg used it in his code, and it worked perfectly. However, there was something wrong with my code. Somewhere in the procedure the adress eax was pointing to got changed (probably because a function returne a value in eax ), so i ended up accessing the wrong memory adress. That's why i had an error!.
By the way, is there any debugger for masm32 you'd recommend?
Most of us use OllyDbg (http://www.ollydbg.de/).
JRevor,
I used BYTE PTR in my code because I was working with BYTEs. With MemCopy you are working with DWORDs.
Quote from: Greg Lyon on March 11, 2010, 06:19:11 PM
JRevor,
I used BYTE PTR in my code because I was working with BYTEs. With MemCopy you are working with DWORDs.
Okay, thanks for the answer.
Anyways, I ended up making my own memcopy :lol
Quote from: JRevorAnyways, I ended up making my own memcopy
Good :U