News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

Taking care of the prerequisites to create my first program without VS

Started by RedSkeleton007, February 05, 2016, 06:45:02 PM

Previous topic - Next topic

hutch--


dedndave

inkey strDuke

the inkey macro wants an address
"strDuke" will likely try to use the first 4 bytes of the string as an address
the address is probably invalid, and that causes the crash

try this
inkey offset strDuke

dedndave

strDuke BYTE "Duke Nukem" ; should be 10 bytes, right?

it is 10 bytes, but you really don't care
and - strings should be null-terminated

strDuke BYTE "Duke Nukem",0 ;11 bytes total

it may be the lack of a null-terminator that causes it to crash
i am not sure how the macro interprets the label without "offset", because i've never used it that way - lol

RedSkeleton007

Quote from: hutch-- on February 09, 2016, 06:50:29 PM
Why the hell are you working in 16 bit ?
If you say that, my best guess is that you're talking about this part:

mov si,val1 ; SI = 1000h
    xchg si,val2 ; SI = 2000h, val2 = 1000h
    mov val1,si ; SI = 2000h
    ; NOTE: SI is from the extended source index register ESI

Since val1 and val2 are only 4 digits, I figured they're 16 bit, and thus could fit into the first 4 LSB portion of the ESI register (or at least, that's my assumption to why the code example in the book shows it that way).
Quote from: dedndave on February 09, 2016, 09:50:12 PM
strDuke BYTE "Duke Nukem" ; should be 10 bytes, right?

it is 10 bytes, but you really don't care
and - strings should be null-terminated

strDuke BYTE "Duke Nukem",0 ;11 bytes total

it may be the lack of a null-terminator that causes it to crash
i am not sure how the macro interprets the label without "offset", because i've never used it that way - lol
Thank you dedndave, that actually does make sense.

dedndave

in 32-bit code, using word registers is generally slower than using full registers
the opcodes for word register instructions include an extra prefix byte to indicate the "non-native" size

byte register instructions still have unique opcodes (just like 16-bit code), so do not require the override byte

many operations are best performed on full-size registers
and, when memory operands are concerned, it is helpful if they are DWORD-aligned
(i.e., the address for a DWORD operand is evenly divisable by 4)

RedSkeleton007

There are 8 general purpose registers:
EAX, EBX, ECX, EDX, ESI, EDI, ESP, and EBP.

Now, are they strictly designated to specific purposes, or does MASM allow me to each register for whatever I want?

Also, I have a few errors and a question in my code:


include \masm32\include\masm32rt.inc
.data
val1 WORD 1000h
val2 WORD 2000h
strDuke BYTE "Duke Nukem",0 ; 11 bytes

.code
start:

; First, lets find out what inkey can do:

    inkey OFFSET strDuke
    inkey "It's time to kick ass and chew bubble gum..."

; Next, lets figure out how to move the amount of bytes in
; our string into a register, so that we can use it to
; observe that information using the displayed registers
; in Olly:
     
    mov edi, SIZEOF strDuke   

; Finally, lets learn how to use the xchg opcode, so that
; val1 and val2 trade values:

    mov eax, val1 ;error: instruction operands must be the same size
    xchg eax, val2 ;error: instruction operands must be the same size
    mov val1, eax ;error: instruction operands must be the same size
   
  nop ; what is nop supposed to do?
 
  inkey "and I'm all out of gum."
  exit
end start


Note that the inkeys worked fine when I ran the program before attempting to add in the xchg stuff.

hutch--

Red,

have a look in the masm32 help files, the Intel ABI is explained there and its a lot easier to point you there than repeat it all as a post.

dedndave

the problem is...

the register operand EAX is a DWORD size
the memory operand val1 is a WORD size
they must be the same size (change val1 to a DWORD)

this is true for most instructions
there are a few exceptions, like MOVSX or MOVZX, which convert bytes or words to dwords

ESP is fairly dedicated to the stack
the other 7 can be used in many ways
but, each one has special characteristics
often, these characteristics are due to specific instruction usage
MOVS, MUL, DIV are a few good ones to study

historically:
AX - accumulator
BX - base index address
CX - count
DX - data
SI - source index address
DI - destination index address
BP - base pointer (stack)

RedSkeleton007

Quote from: dedndave on February 10, 2016, 10:02:48 PM
in 32-bit code, using word registers is generally slower than using full registers
the opcodes for word register instructions include an extra prefix byte to indicate the "non-native" size

byte register instructions still have unique opcodes (just like 16-bit code), so do not require the override byte
The override byte? Does the movzx instruction have anything to do with that?

Quote from: dedndave on February 10, 2016, 10:02:48 PM
many operations are best performed on full-size registers
and, when memory operands are concerned, it is helpful if they are DWORD-aligned
(i.e., the address for a DWORD operand is evenly divisable by 4)
It seems my code worked:

include \masm32\include\masm32rt.inc
.data
val1 DWORD 1000h
val2 DWORD 2000h

.code
start:

    mov eax, val1 ; would movzx be necessary here?
    xchg eax, val2
    mov val1, eax
   
  nop ; what is nop supposed to do?
 
  inkey "End of program."
  exit
end start

In Olly, as I hit F8, I saw the EAX register change to 00001000 and 00002000 ;)
I found it odd, though, that I didn't have to use movzx, or transfer 16-bit values into 32-bit registers. I guess something in modern 32-bit MASM puts in the first four unused higher bits for you?

One other thing. In Olly, once I've hit F8 enough times to get to the end of stepping through my program, I don't know how to go back. How do I go back to the first step instead of having to close and reopen Olly, and then reopen my program in Olly?

jj2007

Quote from: RedSkeleton007 on February 25, 2016, 06:54:19 PMThe override byte? Does the movzx instruction have anything to do with that?
No.

Quotemov eax, val1 ; would movzx be necessary here?
No. Both eax and val1 are DWORD size, i.e. 4 bytes long.

Quotenop ; what is nop supposed to do?
\Masm32\help\opcodes.chm

QuoteIn Olly, once I've hit F8 enough times to get to the end of stepping through my program, I don't know how to go back. How do I go back to the first step
Ctrl F2.

dedndave

in the original post, i think he had val1 defined as a WORD

so, MOVZX or MOVSX could be used

MOVZX zero-extends the value (all the upper bits are set to 0)
MOVSX sign-extends the value (the upper bits are a copy of bit 15 for words or bit 7 for bytes)

typically, we would just define val1 as a DWORD, though

RedSkeleton007

The book does a shitty job explaining how to exchange array elements :( The following code is untested:

include \masm32\include\masm32rt.inc
.data
val1 DWORD 1234h
val2 DWORD 5678h

temp DWORD ?
temp2 DWORD ?
arrayD DWORD 1000h, 2000h, 3000h, 4000h

.code
start:

    mov eax, [arrayD+8] ; move array element [2] into eax 
    xchg temp, eax ; hopefully, eax is empty for the next mov?
    mov eax, [arrayD+4] ; move array element [1] into eax
    xchg temp2, eax
    mov [arrayD+4], temp
    mov [arrayD+8], temp2

    ;arrayD should now be: 1000h, 3000h, 2000h, 4000h
   
  nop ; no operation to do here.
 
  inkey "End of program."
  exit
end start


Also, inkey has proven to work great for outputting hard-coded statements into the console, but what is the syntax for outputting a specific array element value into the console? Olly is cool, but at my current level, it's just giving me a headache. Is Olly really necessary right now, when I'm struggling to learn just the basic opcodes?

dedndave

i troubleshoot most programs without olly - but, it's nice when you need it

if you want to dislpay a value in hex, signed decimal, unsigned decimal...
    print   uhex$(dword ptr [ebx+4])
    print   str$(dwVariableName),13,10
    print   ustr$(eax)


notice i added a carriage return/line feed to one of them

hutch--

Red,

Olly is an OK debugger but you are better to learn the basics first, once you have that under your belt you can add whatever toys you like but the idea is to keep it simple at first or you get tangled in the sheer complexity of trying to do too many things. One of the tricks is to set yourself up a simple test piece and experiment with the instructions and learn how the "complex addressing mode" works, it looks messy but once you understand it, it becomes really easy to use.

Once you are up and going we will show you the FAST way to exchange memory operands, XCHG is both old and slow and can be done a lot quicker, the way its done in fast sort algos.

RedSkeleton007

Quote from: dedndave on February 26, 2016, 01:16:17 PM
notice i added a carriage return/line feed to one of them
Why? I understand the purpose of null-terminating a string, but what is the purpose of the so-called "carriage return/line feed" instruction?

Quote from: hutch-- on February 26, 2016, 01:21:03 PM
Once you are up and going we will show you the FAST way to exchange memory operands, XCHG is both old and slow and can be done a lot quicker, the way its done in fast sort algos.
So I should completely forget about exchanging values in memory or registers for now?

Also, is this what you mean by complex addressing mode:
http://masm32.com/board/index.php?action=post;quote=254;topic=87.0;last_msg=352