Hi folks,

Okay, I'm back from errands, on with the questions. First, thanks again to everyone.

1. I just peeked at some disassembly of my code, and saw this garble:



77E36F56 movsx edx,dl
77E36F59 lea ecx,[ecx+ecx*4]
77E36F5C inc eax
77E36F5D lea ecx,[edx+ecx*2-30h]


Two things strike me about the LEA's in there. Firstoff, it's not entirely clear to me what's being done. I saw a page somewhere a few days ago (but can't find it again, I'm still hoping someone will point out the link, it was a list of common assembly idioms, like saying "xor eax, eax" instead of "mov eax, 0", etc.) that mentioned that lea is faster for some forms of addition, so that could make sense. So that second line could be something like,

"multiply whatever's in ecx by 5, look into the contents of that address, now store the address of those contents in ecx." Or, in other words, multiply ecx by 5, storing the value in ecx.

1a. Is that what's really happening here?
1b. How the heck can the machine, at runtime, embed a *4 in an opcode?!?

2. Is there a common idiom for allocating and freeing memory? I know to use the heap functions; I'm just curious to know what the common idiom is--function allocates, caller frees, caller allocates and frees, etc. I would like to write a function that returns a dynamically allocated array of string pointers, which in turn point to a dynamically allocated buffer containing the strings. (It's my get_cl algorithm. It munges the whitespace, quotes, etc, into a list of arguments each with null-terminated strings.) If I allocate this memory on the heap, the caller must then figure out how to deallocate it, which is certain to be a pain. Right now the best solution I've come up with is to write it as a pair of procedures, GetCommandLineArgsBuffer and ReleaseCommandLineArgsBuffer. This type of memory problem reeks (to me, anyway) of "trying to write C code in assembler".

3. Consider the following code:


.data
Msg db "Here is the command line:", 0dh, 0ah, 0

.data?
CommandLine LPSTR ?

.code
start:
invoke GetCommandLine
mov CommandLine, eax

invoke StdOut, addr Msg
invoke StdOut, CommandLine
invoke ExitProcess,0
end start


Specifically, consider the StdOut calls. Msg needs the addr prefix, CommandLine does not. Yet they are both addresses. What's up with that? (I'm getting really tired of debugging with nothing more than SWH* in my toolbox.)

* SWH = "See What Happens" See also: DBS (Debugging By Superstition) and Programming With NFC (No Freaking Clue)

Hmm, in reconsidering this, Msg *isn't* a pointer, is it? If I pass Msg to that function, I'm passing the value 65726548h ('ereH'), right? Ah-ha! No wonder it's AVing on me.

4. I can't remember question 4.

Thanks all!

-Chalain
Posted on 2002-04-21 20:00:00 by Chalain
If I allocate this memory on the heap, the caller must then figure out how to deallocate it, which is certain to be a pain. Right now the best solution I've come up with is to write it as a pair of procedures, GetCommandLineArgsBuffer and ReleaseCommandLineArgsBuffer.
When an API passes an array, it usually requires the caller to allocate the memory first, then pass a pointer to the buffer as a parameter, and also pass the length of the buffer as another parameter. The API then calculates how much space it needs, compares that to how much the caller gave it, if the caller did not allocate enough buffer then the API returns with an error, but it also fills a third 'out' parameter with the size required. This way Windoze avoids being responsible for memory leaks by making the caller allocate/deallocate the buffer. This is why sometimes you will see an API called twice: the first time with a zero length buffer, the API will error and calculate how much it needs, and then the caller will allocate a buffer of the correct size and call the API again.


Msg needs the addr prefix, CommandLine does not. Yet they are both addresses.
Nope. Msg is merely a label for a range of bytes, that is why you need to add the 'addr' during the call.


4. I can't remember question 4.
And i can't remember the answer, so we are all square :grin:
Posted on 2002-04-21 21:03:34 by sluggy
1a)

lea ecx,

basically, it multiplies ecx by 5... mov ecx,(ecx+(ecx*4))

as for ecx,,
it moves into ecx the value of edx + ecx*2 - 30h...

you can multiply by a power of 2 to scale a register, add a base, and add an immediate all in one cycle. i saw a multiplication table for leas somewhere before (but i'm sure you can figure it out by yourself) up to like 100.

so, yes, you are correct about its function.

1b) leave it to intel and their cool ALU :)

2) i'll leave that to someone else... that seems right... allocate, store pointer. use it. free pointer.

or, using Global/LocalAllocs, allocate, get handle, cvt handle to pointer, store pointer. use it. free handle.

3) you solved your own problem :) also, don't forget about the OFFSET prefix (similar to ADDR). most functions, i find, in Win32, return a pointer to null-terminated strings/a structure, or to a handle. make sure you know what each API's expected return is.
Posted on 2002-04-21 21:07:46 by jademtech

1. I just peeked at some disassembly of my code, and saw this garble:
77E36F56   movsx       edx,dl

77E36F59 lea ecx,[ecx+ecx*4]
77E36F5C inc eax
77E36F5D lea ecx,[edx+ecx*2-30h]
1a. Is that what's really happening here?
1b. How the heck can the machine, at runtime, embed a *4 in an opcode?!?
This looks like Svin's code for converting an ASCII number.

1a. ECX = ECX*10 + (DL - "0"); this is what is happening

1b. The addressing modes of the x86 allow a constant multiplier of 1,2,4,8 - this is part of the effective address calculation. Look at the Intel manuals for a greater explantion.
Posted on 2002-04-21 21:11:05 by bitRAKE
Hi Chalain,


1a. No, lea ecx, says first add together edx and ecx, multiply the result by two, then subtract 48, and store the result in ecx. It doesn't resolve any addresses, rather its used for indexing.

1b. The machine isn't embedding the 4 at run time. It was in there right after compile time.


2. There's really no fancy way to allocate memory in Win32 aside from what functions you already have to use. The OS manages memory. If you want to implement your own memory manager in Win32, then I would advise building it on top of the API.

3. There's 2 major differences between Commandline and Msg in your example. Commandline is a variable that holds a pointer to a string, while MSG is a label that identifies the start of a string.

A little example to help you visualize better:
.data

Msg db "Here is the command line:", 0dh, 0ah, 0
; [b]0012FDEC[/b]: 48 65 72 65 20 69 73 20 74 68 65 20
; 63 6f 6d 6d 61 6e 64 20 6c 69 6e 65
; 3a 0d 0a 00
;
.data?
CommandLine LPSTR ?
; [b]0012FE08[/b]: 00 00 00 00
.code
invoke GetCommandLine
; call GetCommandLine

mov CommandLine, eax
; mov dword ptr [[b]0012FE08[/b]], eax
; (put value of eax into memory at address 0012FE08)

invoke StdOut, addr Msg
; push [b]0012FDEC[/b]
; (push address of the first byte in the character array at 0012FDEC)
; call StdOut

invoke StdOut, Commandline
; mov eax, dword ptr [[b]0012FE08[/b]]
; (move the dword variable at address 0012FE08 into eax)
; (eax now contains the pointer to the command line string
; that was previously put in there by GetCommandLine)
; push eax
; call StdOut
Hope that helps. Good luck.
Posted on 2002-04-21 21:14:20 by iblis
Well I am still confused as to exactly what Lea is used for . I think i understand the first sample.. just not sure exactly to why:?

Is it just a nother mutliplication feature that is supposed to be faster or what?

anyways if somebody could help post a few no brainer samples and explain how they work and what they do i would appreciate it
Posted on 2002-04-22 10:08:08 by Volcano_88101
lea .... load effective address ...
it computes the effective address of the given memory location and stores it in to the given regiter ... since caculating the effective address inculdes addition and multiplication, this instruction is used also to compute the the sum of the content of the registers (and if you want you can also multiply them by 2, 4 or 8) in one single instruction ....
Posted on 2002-04-22 10:52:28 by code1101
it performs the equivilent of shl, not mul.
Posted on 2002-04-22 17:28:29 by jademtech
Hi all

I decided to go back to your ASCII table program, and rewrote
it to show some uses for LEA.
It uses a line buffer that has all the drawing characters predefined and i fill in the info for each line and then output to console.

Note that I use .686 that enables instructions for PII and forward because i am using the conditional move instruction that is not supported if i use .386.


;===========================================
; File: ascii.asm
; Desc: Prints the ASCII chart as a 16x16 grid with hex labels. My
; first (original) assembly program.
; Auth: Chalain
; Date: 04/17/2002
;
; Modified by Towers Date 04/23/2002
;
;-----------------------------------------------------------------------
; Notes:
; Win32 Assembly *console* project. To compile and link with masm32,
; use BLDALLC.BAT, or compile by hand like so:
;
; ml /c /coff ascii.asm
; link /SUBSYSTEM:CONSOLE ascii.obj
;
;=================================================

;-----------------------------------------------------------------------
; DIRECTIVES
;-----------------------------------------------------------------------
.686
.model flat, stdcall
option casemap:none

;-----------------------------------------------------------------------
; INCLUDES
;-----------------------------------------------------------------------
.nolist
include \masm32\include\Windows.inc
include \masm32\include\masm32.inc
include \masm32\include\kernel32.inc
include \masm32\include\user32.inc

includelib \masm32\lib\user32.lib
includelib \masm32\lib\masm32.lib
includelib \masm32\lib\kernel32.lib
.list
;-----------------------------------------------------------------------
; .DATA
;-----------------------------------------------------------------------
.data

; ascii-art caption text
AsciiArtTopBars db " ",218, 33 dup(196),191,13,10
AsciiArtTopCaption db " ",179
db " 0 1 2 3 4 5 6 7 8 9 A B C D E F "
db 179, 13, 10
AsciiArtTopBar2 db 218,196,197, 33 dup(196),180,13,10,0

AsciiArtBottomBar db 192,196,193, 33 dup(196), 217, 13, 10, 0
linebuf db 179,32,179,32, 32 dup (32),179,13,10,0

;----------------------------------------------------------------------
; .DATA?
;----------------------------------------------------------------------
.data?
y dd ?

;----------------------------------------------------------------------
; .CODE
;----------------------------------------------------------------------
.code
start:
invoke StdOut, addr AsciiArtTopBars ; first 3 header lines

mov y,0
.WHILE y<16
mov edx,0
mov ecx,y
shl ecx,4 ; y*16 is a constant for 16 x
morex:
lea eax, ; x + y*16

mov ebx,20h

cmp eax,0
cmovz eax,ebx ; if 0,7,8,9,10,13
cmp eax,7 ; load blank
cmovz eax,ebx
cmp eax,8
cmovz eax,ebx
cmp eax,9
cmovz eax,ebx
cmp eax,10
cmovz eax,ebx
cmp eax,13
cmovz eax,ebx

; first char place in line buffer
lea ebx, ; and index by x*2
mov ,al ; put the ascii char into buffer

inc edx
cmp edx,16 ; loop until x (edx) =16
jb morex

mov eax,y ; calculate ASCII value of y
add eax,030h ; if number add 30h
cmp eax,03Ah
jb @F
add eax,07h ; if A-F add 30h+7
@@:
mov ,al ; put y into place in line buffer
invoke StdOut, addr linebuf ; print the line
inc y
.ENDW

invoke StdOut, addr AsciiArtBottomBar
invoke ExitProcess, 0
end start
Posted on 2002-04-23 14:13:46 by towers