News:

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

Main Menu

JamieJean's many questions ^^'

Started by JamieJean, February 08, 2021, 03:45:55 AM

Previous topic - Next topic

JamieJean

Still going through Lczelion's tutorial, and I imagine I'll have many more questions to come, so I'll just add them to this topic when that happens instead of making a new topic for each question.

Right now, I've found this bit:

.while true
invoke GetMessage,addr msg,NULL,0,0
.break .if (!eax)
invoke TranslateMessage,addr msg
invoke DispatchMessage,addr msg
.endw

Most of this makes at least moderate sense to me after reading the tutorial, but I'm not sure what exactly the .break line does.

When is (!eax) true? Is it when eax is null/all zeroes (i.e. a function has just returned null)?
For that matter, what even is eax in terms of what it can store? Is it a single value or an array or something else, and what size is it?

Does .break just break the loop, or does it exit the program? (I think the former, but the wording is ambiguous in the tutorial)
is the code after .break executed a final time after the loop is broken, or is the loop aborted entirely? (the latter makes more sense, but I want to make sure)

Sorry for the total noob questions, but nothing I've seen really goes into all this. I'm really having fun learning Assembly, and I'd rather avoid having such glaring holes in my knowledge.

HSE

Hi JamieJean!

Exactly.

! mean not. !eax mean eax == 0.

eax is a processor register with 32 bits.

.break terminate loop. After that program follow until "invoke ExitProcess, 0" .

HSE
Equations in Assembly: SmplMath

JamieJean

Hi HSE,

Thanks! So far I've gotten a window with text on it!


To anyone:

Here's my current understanding of registers and pointers... is there anything I should add?
---------------------------------------
EAX:00000000|00000000|00000000|00000000 \
AX:         |        |00000000|00000000  |_Stores return values from functions
AH:         |        |00000000|          |
AL:         |        |        |00000000 /
---------------------------------------
EBX:00000000|00000000|00000000|00000000 \
BX:         |        |00000000|00000000  |_Points to data... not sure what that means
BH:         |        |00000000|          |
BL:         |        |        |00000000 /
---------------------------------------
ECX:00000000|00000000|00000000|00000000 \
CX:         |        |00000000|00000000  |_Used for loops... a counter for the number of loops passed?
CH:         |        |00000000|          | Includes the type of loop???
CL:         |        |        |00000000 /
---------------------------------------
EDX:00000000|00000000|00000000|00000000 \
DX:         |        |00000000|00000000  |_Spare?
DH:         |        |00000000|          |
DL:         |        |        |00000000 /
---------------------------------------
---------------------------------------
ESP:0000000000000000 | 0000000000000000 \_Points to the top of the stack
SP:                  | 0000000000000000 /
---------------------------------------
EBP:0000000000000000 | 0000000000000000 \_Points to the base of the stack (don't know if/why this would change)
BP:                  | 0000000000000000 /
---------------------------------------
ESI:0000000000000000 | 0000000000000000 \_Dunno
SI:                  | 0000000000000000 /
--------------------------------------
EDI:0000000000000000 | 0000000000000000 \_Dunno
DI:                  | 0000000000000000 /
---------------------------------------

jj2007

That's all correct, Jamie, but you cannot expect that the members of this forum play the private teacher for you. Spoon feeding doesn't work, you need to read a book. Go to Tips, tricks & traps, recommended reading. The Art of Assembly link, for example, is a must read.

In parallel start experimenting with code. The \Masm32\Examples folder is full of good stuff. When you are stuck, come here, ask questions, and you will get help :thup:

hutch--

Hi Jamie,

Here is a message loop done mainly with mnemonics (Intel instructions).

MsgLoop proc

    LOCAL msg:MSG

    push esi
    push edi
    xor edi, edi                        ; clear EDI
    lea esi, msg                        ; Structure address in ESI
    jmp jumpin

    StartLoop:
      invoke TranslateMessage, esi
    ; ----------------------------------------
    ; perform any required key processing here
    ; ----------------------------------------
      invoke DispatchMessage,  esi
    jumpin:
      invoke GetMessage,esi,edi,edi,edi
      test eax, eax
      jnz StartLoop

    mov eax, msg.wParam
    pop edi
    pop esi

    ret

MsgLoop endp

JamieJean

Hi jj2007,

I am already following a tutorial. I'm not expecting to be spoonfed, sorry if it came off that way, I just like a second opinion from people that are both experienced (as opposed to me) and interactive (as opposed to tutorials), because interacting is how I learn best.

I got side-tracked by Iczelion's tutorials before I could get to the Art of Assembly, but I'll be sure to read it before coming here from now on. Thanks for the help!

mineiro

Some assembly instructions depends of specific register usage, while others instructions you have more freedom.
The pseudo names for that 4 main registers are Acumulator, Base, Counter, Data (eAx,eBx,eCx,eDx). We have too Source and Destination data registers (eSi, eDi).

A register holds a number, nothing more. The number stored in a register can be data, address pointer, code!? We, programers define that.

If you look to instruction loop, lodsb, stosb, div, mul, ..., these instructions use specific registers to do that job, while others like mov can do their job with most registers.

Instructions are categorized, we have arithmetic functions, flow (jumps), compare, move, logic operations, ... .

Remember that we can add a Base memory address with some offset/displacement. Some instructions use these address mode thing. So we can have a static address to be hold and a volatile/dynamic address to be added/modified. Like a finger pointing to start of a string and other finger walking in that string. That's the reason of a Base register.

You forgot eIp (instruction pointer) register. That means what code should be processed by processor. Data at that address will be executed.
You forgot FLAG register. Arithmetic, flow, logic instructions depends of BIT values in that register.
In windows/linux 32/64 bits we don't use much segment registers, so, that's okay for a while.
I'd rather be this ambulant metamorphosis than to have that old opinion about everything

hutch--

Now, with you table of integer registers, you don't have to be limited to the usage description with most of the registers. Win32 does not have the restrictions of 16 bit MS-DOS real mode. In some contexts, specific registers are required, eax for return values, some of the old instructions exclusively use ESI EDI and ECX and stack frames are constructed with EBP and ESP.

You may as well learn this now, you can in a procedure freely use EAX ECX and EDX but all of the rest must remain unchanged when a procedure returns. If you don't use any of the rest you don't have to do anything with them but if you need more registers in your procedures, you push the register at the top of the procedure and pop it back before the return to the caller. Also note that the order of the pops are in reverse to the pushes.

push ebx
push esi
; your code
pop esi
pop ebx

JamieJean

Quote from: hutch-- on February 08, 2021, 09:03:10 AM
Now, with you table of integer registers, you don't have to be limited to the usage description with most of the registers. Win32 does not have the restrictions of 16 bit MS-DOS real mode. In some contexts, specific registers are required, eax for return values, some of the old instructions exclusively use ESI EDI and ECX and stack frames are constructed with EBP and ESP.

You may as well learn this now, you can in a procedure freely use EAX ECX and EDX but all of the rest must remain unchanged when a procedure returns. If you don't use any of the rest you don't have to do anything with them but if you need more registers in your procedures, you push the register at the top of the procedure and pop it back before the return to the caller. Also note that the order of the pops are in reverse to the pushes.

push ebx
push esi
; your code
pop esi
pop ebx


Hi Hutch,

So you can use these registers as much as you want in a procedure, you just need to stack its value and pop it back into place before the end? That's neat.



Finished the tutorial for TextOut yesterday, and I decided to mess with my color macro a bit so I can use one hex value as input.
Color is the original, Color2 is my version.:
Color macro r,g,b
xor eax,eax
mov ah,b
shl eax,8
mov ah,g
mov al,r
endm

Color2 macro rgb
xor eax,eax
mov eax,rgb
ror ax,8
ror eax,8
ror ax,8
rol eax,8
ror ax,8
endm

Yes this is technically less useful than the original since I can't input variables as easily, but it did teach me a lot about how to use registers ^^'
Originally I stacked red and green, but I realised I could just rotate them around each other.

Not sure how each macro would compare in speed; Color uses fewer calculations but it also moves entire variables around instead of bits... I imagine Color2 is still slower.

Are macro arguments dynamically-sized? I noticed that I didn't have to define rgb's size in Color2, despite it holding all the data of r,g,b in Color.

hutch--

You basically think of a macro as its real task, a PRE-processor. When written correctly they modify code BEFORE it is assembled. Simple ones are OK to write but complex macros are hard work. When you use a macro, it is modifying or expanding code before the assembler converts the code to binary code. Its probably better to learn your basic mnemonics first then what is called the "complex addressing mode". Once you get both, reading code will be a lot easier.

Dan-TheStarman

#10
Quote from: JamieJean on February 08, 2021, 07:41:43 AM
To anyone:

Here's my current understanding of registers and pointers... is there anything I should add?
---------------------------------------
EAX:00000000|00000000|00000000|00000000 \
AX:         |        |00000000|00000000  |_Stores return values from functions
AH:         |        |00000000|          |
AL:         |        |        |00000000 /
---------------------------------------

ETC. ETC.

Hi Jamie, First, lovely displays using only ASCII characters!

Regarding the 32-, 16- and 8-bit part register names and bit sizes, you've got that down. But as pointed out above, sometimes you really do need to know exactly what is in the FLAGS register! (There are 32-bit and 16-bit parts for that as well.) I did a brief page on the 16-bit registers a long time ago, but the section on the FLAGS can still be useful for masm32: https://thestarman.pcministry.com/asm/debug/8086REGs.htm#FLAGS

I'm simply adding more and in different ways than what others already provided here.

Although there are some generalities that can often be said about the main registers, exactly what they get used for is entirely up to the code; with the exception of the ESP (SP) which always points to the 'top' of the "Stack" and the EIP (IP) which always points to where the next instruction to be executed is supposed to be (which might not even point to a 'proper' ASM instruction; IOW, might not be where you expect or want it to be! Hahaha... if something goes wrong.)

To expand: You might decide to use EAX and EBX to hold some numbers you want to do some math or logical manipulations on... which is just fine... or even involve some other registers (not ESP or EIP of course!), but if you decide to call/invoke a pre-defined FUNCTION on some values you've been working with, that's when you very much need to know all of the registers that function will use, and exactly which ones for what purposes!

That's why I always do some research on any function I'm about to use for the first time. There are lots of good helps in masm32, as you've already found, BUT you might want to go to the source of all the Windows API Functions and check there as well (I try to use MULTIPLE sources for anything I do). For example, here's where you can read about the "GetMessage" function; although you need to understand Microsoft will almost always be discussing .CPP (C++) or some other high level language on their site (rare to find any up-to-date MASM discussions there now): https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getmessage.  You can (and should) also do this for any individual x86 Assembly instruction you're not sure about (or especially if it acted differently than you expected it to!).

   If you use the "invoke" directive in masm32, then all the parameters a function requires will be in the same order you see in the Microsoft documentation there. For another example, go to: https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-messageboxa, and what you see for the order in that C++ "int" function, is the same order as this masm32 INVOKE directive:
invoke MessageBoxA, 0, addr windowText, addr windowCaption, MB_OK
where "addr windowText" is a pointer to the "windowText" message you'd put in the .data section using:
windowText  db  "actual text", 0
and "MB_OK" stands for a "0". The details there will tell you what the first "0" is for and why, and what else you could use. And, BTW, the "A" in the function name here basically means it's sort of the ASCII version of "MessageBox" whereas "MessageBoxW" means you need to use UTF (Unicode; at least 2-bytes for each) characters; gets much more complicated!

   If you don't have one (or them) yet, get a copy of the OPCODE manuals directly from INTEL (free download of PDF files; AMD has some literature as well; maybe other sites). You can certainly begin with the "Opcodes help" in the HELP menu of hutch's "MASM32 Editor" (IDE, assembler, linker, etc. etc.) program (if you installed masm32), and many other HELP items there.


Dan, TheStarman.

JamieJean

Hi all,

Thanks for all the info! I don't think I'm experienced enough for the majority of it to make sense yet, but I'll keep coming back to it until it slots into place.

For now... I'm having a lot of trouble with Lczelion's tutorial 09, for dialog boxes. Here's my code for the resource file:

#include "resource.h"

#define dboxEdit 3000
#define dboxButton 3001
#define dboxExit 3002

#define menuGetText 32000
#define menuClear 32001
#define menuExit 32002


firstMenu menu
begin
popup "Test Controls"
begin
menuitem "Get Text",menuGetText
popup "Clear Text"
begin
menuitem "Really?",menuClear
end
menuitem separator
menuitem "Exit",menuExit
end
end

dbox dialog 10,10,205,60
STYLE 0x0004|DS_CENTER|WS_CAPTION|WS_MINIMISEBOX|WS_SYSMENU|
WS_VISIBLE|WS_OVERLAPPED|DS_MODALFRAME|DS_3DLOOK
caption "First Dialog Box"
class "dlgClass"
begin
editText dboxEdit,15,17,111,13,ES_AUTOHSCROLL|ES_LEFT
defPushButton "E&xit",dlgExit,141,26,52,13,WS_GROUP
end


I've copied it pretty much line-for-line from the tutorial.

When I try to compile it with the asm file, I get the message: "dbox.rc(1) : fatal error RC1015: cannot open include file 'resource.h'."

When I create resource.h as an empty file in the directory or remove the inclusion, I get the message: "dbox.rc (26): error RC2104 : undefined keyword or key name: DS_CENTER". This changes to reflect the earliest style argument on line 26, so I can only assume that resource.h should define styles or link somewhere that does.

The links to all Lczelion's examples are dead, so I can't just check what they used, and they don't mention it in the tutorial itself.

I've looked up Win32 API to try and define the styles myself, but it only includes values for the window styles (and anyway I don't know what syntax resource.h should use; I tried just defining them but it broke). I've looked up the problem, but it just links me to C++ stuff even if I specify masm32 or Lczelion.

I've tried everything I can think of. Does anyone have an idea of the problem?

Vortex

Hi Jamie,

#include "resource.h"

to be replaced by :

#include "\masm32\include\resource.h"

Another replacement : WS_MINIMISEBOX -> WS_MINIMIZEBOX

And this one :

defPushButton "E&xit",dlgExit,141,26,52,13,WS_GROUP

dlgExit is not defined in your resource script.

To download Iczelion's tutorials :

http://masm32.com/website/

JamieJean

Hey Vortex,

Thanks!

It's odd that Iczelion's tutorial just uses '#include "resource.h"'. Is that a product of the time?

For the other things, I tend to miss small issues like that, usually I just let them scream at me in compiling and sort them out there. Unfortunately I couldn't do that this time until the include problem was fixed.

Thanks very much for the download link! I didn't know that page existed until now ^^' Seems like there's more useful stuff beyond just the tutorial, too.

I can't help but notice how many years of experience everyone here seems to have. It's humbling.

Vortex

#14
Hi Jamie,

You can download the examples accompaigning the tutorials :

https://www.masm32.com/icz.htm

https://www.masm32.com/download/icztutes.exe

As an example, the folder TUTE10-1 provides Resource.h