The MASM Forum Archive 2004 to 2012

Miscellaneous Forums => 16 bit DOS Programming => Topic started by: Rogare on September 30, 2009, 08:45:56 PM

Title: Hello and a question
Post by: Rogare on September 30, 2009, 08:45:56 PM
Hey all,

I am pretty new to ASM. I am originally a higher-level programmer (PHP, .NET etc.) but as I was forced to learn C in one of the computers' science courses I decided to try going even lower.
I got few books on online tutorials, but when I tried assembling the programs I found and wrote I found out it is more complicated than I thought.
I posted some topic on the general forum and then I found out about the huge difference between 16-bit and 32-bit.
I am now trying to run my programs with 16-bit. I downloaded and installed Masm32 (earlier) and was told that link16 might help me.

This is GOTO.ASM:
.MODEL SMALL
.STACK 100h
.data
x DB 2Ah
.CODE

start:
mov ax,@data
mov ds,ax

mov ah,02h
mov dl,x
int 21h

mov ah,08h
int 21h
mov x,al

mov ax,4C00h
int 21h
END start


This is command line output:
D:\masm32\bin>ml /Bl link16.exe D:\GOTO.ASM
Microsoft (R) Macro Assembler Version 6.14.8444
Copyright (C) Microsoft Corp 1981-1997.  All rights reserved.

Assembling: D:\GOTO.ASM

Microsoft (R) Segmented Executable Linker  Version 5.60.339 Dec  5 1994
Copyright (C) Microsoft Corp 1984-1993.  All rights reserved.

Object Modules [.obj]: GOTO.obj
Run File [GOTO.exe]: "GOTO.exe"
List File [nul.map]: NUL
Libraries [.lib]:
Definitions File [nul.def]:


When double-clicking on the GOTO.exe the black command line windows appears and disappears without waiting for anything.

Thanks in advance,
Rogare
Title: Re: Hello and a question
Post by: dedndave on September 30, 2009, 08:51:59 PM
it probably works fine
you can either open a console window and run it from the command line
or
put a "press any key" at the end of the program so it does not exit until you press a key
Title: Re: Hello and a question
Post by: Rogare on September 30, 2009, 08:58:43 PM
Ran it via command line - the asterisk isn't there and it isn't waiting for my key (as far as I know 21h-02 is print and 21h-08 is read key).
Title: Re: Hello and a question
Post by: dedndave on September 30, 2009, 09:05:46 PM
it ran fine here
here is a 16-bit assembly batch file, as well as goto16.asm and exe
Title: Re: Hello and a question
Post by: Rogare on September 30, 2009, 09:12:09 PM
The .exe really works. The code is same.
How do I work with the .bat file?
Title: Re: Hello and a question
Post by: dedndave on September 30, 2009, 10:42:42 PM
place a16.bat in the masm32\bin folder
(that folder should be listed in the PATH environment variable)
then, at the command prompt type:
a16 goto16

if the x:\masm32\bin folder is not in the PATH
open My Computer - Properties - Advanced tab - Environment Variables button
and add it to the system environment PATH list (with a semicolon)
Title: Re: Hello and a question
Post by: Rogare on October 01, 2009, 08:03:17 AM
Did all that (even changed the script to work with d:\masm32\bin instead of c:\...).
That is command line output:
D:\>a16 goto
Microsoft (R) Macro Assembler Version 6.14.8444
Copyright (C) Microsoft Corp 1981-1997.  All rights reserved.

Assembling: goto.asm

PKSFX (R)   FAST!   Self Extract Utility   Version 2.04g  02-01-93
Copr. 1989-1993 PKWARE Inc. All Rights Reserved. Shareware version
PKSFX Reg. U.S. Pat. and Tm. Off.

Searching EXE: D:/MASM32/BIN/LINK563.EXE
Volume in drive D has no label.
Volume Serial Number is 00B2-CF12

Directory of D:\

09/30/2009  10:32 PM               200 GOTO.ASM
               1 File(s)            200 bytes
               0 Dir(s)  58,181,939,200 bytes free


I didn't see any thing in there (except the interesting fact that when it lists files in D:\ it shows only GOTO.ASM and not other files (there are other .ASM files in there).
I looked in D:\ and in D:\masm32\bin but the goto.exe isn't there.
Title: Re: Hello and a question
Post by: dedndave on October 01, 2009, 09:16:50 AM
make sure that the 16-bit linker exe filename in the batch file matches the one you have in the masm32\bin folder
Title: Re: Hello and a question
Post by: Rogare on October 01, 2009, 10:11:23 AM
Same. I tried removing from the batch the line that deletes the .obj file and seen it is there.

Here is the batch file I have:
@echo off
if "x%1"=="x" goto ascusage
if exist %1.asm goto ascasm
:ascusage
echo Usage: asc asmfile
echo "asmfile" = asmfile.asm
goto batchexit
:ascasm
if exist %1.obj del %1.obj
d:\masm32\bin\ml /c %1.asm >d:\masm32\bin\asmbl.txt
if errorlevel 1 goto showtxt
if exist %1.exe del %1.exe
d:\masm32\bin\Link563 %1.obj; >>d:\masm32\bin\asmbl.txt
:showtxt
if exist %1.obj del %1.obj
type d:\masm32\bin\asmbl.txt
:batchexit
dir %1.*


Here is the result of dir function in masm32/bin:
D:\masm32\bin>dir
Volume in drive D has no label.
Volume Serial Number is 00B2-CF12

Directory of D:\masm32\bin

10/01/2009  10:06 AM    <DIR>          .
10/01/2009  10:06 AM    <DIR>          ..
10/01/2009  12:09 PM               444 a16.bat
10/01/2009  12:08 PM               240 asmbl.txt
08/01/2007  10:49 AM               193 assmbl.bat
01/01/2007  02:01 PM               643 bldall.bat
01/01/2007  02:01 PM               643 bldallc.bat
01/01/2007  02:01 PM                88 bres.bat
01/01/2007  02:01 PM               542 build.bat
01/01/2007  02:01 PM               530 buildc.bat
01/20/1998  09:15 PM            15,632 cvtres.exe
01/01/2007  02:01 PM               408 dasm.bat
01/01/2007  02:01 PM               408 dasmd.bat
09/15/2002  11:58 PM            13,312 dbgwin.exe
03/29/2002  05:43 PM             2,048 dumpbin.exe
02/07/1999  08:24 AM           163,840 dumppe.exe
02/07/1999  08:24 AM             9,510 dumppe.txt
03/29/2002  05:43 PM             2,048 editbin.exe
09/27/2006  04:17 PM            44,984 imagedit.exe
10/17/1994  03:29 PM            82,134 imagedit.hlp
03/29/2002  05:43 PM             2,048 lib.exe
03/19/1998  08:28 AM           462,899 link.exe
01/13/1995  06:10 AM           364,544 link16.exe
09/30/2009  11:29 PM           281,082 Link563.exe
08/01/2007  10:50 AM               341 lnk.bat
08/01/2007  10:50 AM               341 lnkc.bat
07/21/2001  09:31 PM             9,687 ml.err
03/29/1999  09:45 AM           372,736 ml.exe
09/19/1998  01:30 PM           117,520 msdis100.dll
03/19/1998  05:50 PM           164,112 msdis109.dll
06/09/1998  10:50 PM           157,456 mspdb50.dll
06/12/2007  04:01 AM             4,633 pelle.txt
05/31/2008  01:09 AM           653,488 poasm.exe
03/24/2008  05:30 PM            88,240 polib.exe
03/24/2008  05:30 PM           164,528 polink.exe
03/24/2008  06:41 PM           146,096 porc.dll
03/24/2008  06:41 PM            30,208 porc.exe
06/09/1998  10:50 PM             4,880 rc.exe
06/27/1995  08:03 AM           136,161 rc.hlp
06/09/1998  10:50 PM           105,744 rcdll.dll
09/27/2006  04:18 PM            19,188 zoomin.exe
              39 File(s)      3,623,579 bytes
               2 Dir(s)  58,189,529,088 bytes free
Title: Re: Hello and a question
Post by: MichaelW on October 01, 2009, 10:49:32 AM
I'm guessing here, but the file LNK563.EXE, from the MASM32 Forum Web Site under Microsoft Tools \ 16-bit Microsoft Linker, is not a 16-bit linker, it is a self-extracting archive that contains the files CVPACK.EXE, LINK.EXE, and README.TXT. When it is executed it displays this header:
Quote
PKSFX (R) FAST! Self Extract Utility Version 2.04g 02-01-93
Copr. 1989-1993 PKWARE Inc. All Rights Reserved. Shareware version
PKSFX Reg. U.S. Pat. and Tm. Off.

The LINK.EXE from the archive (364544 bytes, modified Thursday, January 12, 1995, 10:10:00 PM) is the 16-bit linker, and since it has the same name as the 32-bit linker, to allow it to coexist with the 32-bit linker and to prevent confusion it is frequently renamed to LINK16.EXE. For MASM32 v10, the LINK16.EXE in the \bin directory is this file.

Title: Re: Hello and a question
Post by: Rogare on October 01, 2009, 11:10:05 AM
Great guess!
Now I got the real Link563.
Here is the output of the batch:
D:\>a16 goto
Microsoft (R) Macro Assembler Version 6.14.8444
Copyright (C) Microsoft Corp 1981-1997.  All rights reserved.

Assembling: goto.asm

Microsoft (R) Segmented Executable Linker  Version 5.60.339 Dec  5 1994
Copyright (C) Microsoft Corp 1984-1993.  All rights reserved.

Volume in drive D has no label.
Volume Serial Number is 00B2-CF12

Directory of D:\

09/30/2009  10:32 PM               200 GOTO.ASM
10/01/2009  12:56 PM               539 goto.exe
               2 File(s)            739 bytes
               0 Dir(s)  58,188,984,320 bytes free

D:\>goto

D:\>


I tried also double-clicking goto.exe - just disappears. I also noticed it is the same size as the EXE you made (yours works).
Got another great guess?
Title: Re: Hello and a question
Post by: MichaelW on October 01, 2009, 11:55:52 AM
The EXE disappears because it is coded to run and exit. To see the output you can run it from a command prompt, or do what I normally do and add a call to the BIOS Get Keystroke function. When the function is called it will wait for a keystroke to be placed in the keyboard buffer before it returns to the caller.

. . .
mov ah,08h
int 21h
mov x,al

mov ah,0
int 16h

mov ax,4C00h
int 21h
. . .

Title: Re: Hello and a question
Post by: Rogare on October 01, 2009, 12:09:36 PM
.MODEL SMALL
.STACK 100h
.data
x DB 2Ah
.CODE

start:
mov ax,@data
mov ds,ax

mov ah,02h
mov dl,x
int 21h

mov ah,08h
int 21h
mov x,al

mov ax,4C00h
int 21h
END start


int 21h-08 reads a character.
And I did open via command line (you can see at my last post in command line output) and nothing was seen.
Could you upload a .zip file with the real Link563, maybe I did something wrong?
Title: Re: Hello and a question
Post by: dedndave on October 01, 2009, 01:12:47 PM
can't believe you caught Michael off-guard - hard to do - lol
find out which of these files you have in the masm32\bin folder:
link16.exe
lnk563.exe
link563.exe
edit the a16.bat file to match that linker name and it should work for you
Title: Re: Hello and a question
Post by: Rogare on October 01, 2009, 01:41:45 PM
Well, I got Link563.exe and link16.exe. Tried working with both - always the same emptiness of the .exe.
Title: Re: Hello and a question
Post by: dedndave on October 01, 2009, 02:41:05 PM
here is a new batch file for you
i have written it to use Link16.exe in the D:\masm32\bin folder...
Title: Re: Hello and a question
Post by: Rogare on October 01, 2009, 02:47:59 PM
Same problem.
Title: Re: Hello and a question
Post by: dedndave on October 01, 2009, 03:04:53 PM
ok
this isn't hard - lol
what happens when you run that batch file ?
there should be some kind of output
you should change your current directory to the same location as the file you want to assemble
let's say it's MyFolder.....
then run:
D:\MyFolder>a16 goto

it should tell you that the file (goto.asm) is not found
or - it can't find ML.EXE
or - it can't find LINK16.EXE
Title: Re: Hello and a question
Post by: Rogare on October 01, 2009, 03:09:55 PM
GOTO.ASM is in D:\ root.
Here is output:
D:\>a16 goto
Microsoft (R) Macro Assembler Version 6.14.8444
Copyright (C) Microsoft Corp 1981-1997.  All rights reserved.

Assembling: goto.asm

Microsoft (R) Segmented Executable Linker  Version 5.60.339 Dec  5 1994
Copyright (C) Microsoft Corp 1984-1993.  All rights reserved.

Volume in drive D has no label.
Volume Serial Number is 00B2-CF12

Directory of D:\

09/30/2009  10:32 PM               200 GOTO.ASM
10/01/2009  05:09 PM               539 goto.exe
               2 File(s)            739 bytes
               0 Dir(s)  58,187,956,224 bytes free

D:\>goto

D:\>

Including a test run for goto.exe - which does nothing.
Title: Re: Hello and a question
Post by: dedndave on October 01, 2009, 03:26:26 PM
ok
something is not right - lol
the exe is 539 bytes - that is the correct size
let's try a different asm file....

while you are doing that, i will look at this goto.exe file
Title: Re: Hello and a question
Post by: dedndave on October 01, 2009, 03:39:01 PM
ok
i found the problem
lol
you are going to laugh
"goto" is a DOS batch command
it is "internal" - i.e. it is inside command.com - and takes precedence over externals
so, when you type "goto" at the prompt it executes the batch command - not the exe
i just renamed the exe to gotoA.exe and it worked
Title: Re: Hello and a question
Post by: Rogare on October 01, 2009, 03:41:47 PM
WOW.
Thanks so much for everything!
Title: Re: Hello and a question
Post by: dedndave on October 01, 2009, 03:45:25 PM
my pleasure
that was a different kind of problem than what we are used to seeing in here
usually, there is something wrong with their program or their setup
it was a nice change of pace - lol
Title: Re: Hello and a question
Post by: Rogare on October 01, 2009, 05:18:22 PM
Well, I started playing and I wrote this piece of code:
.MODEL SMALL
.STACK 100h
.DATA
x DB ?
.CODE

initProg PROC
mov ax,@DATA
mov ds,ax
ret
initProg ENDP

endProg PROC
mov ax,4C00h
int 21h
ret
endProg ENDP

printDot PROC
mov ah,02h
mov dl,2Ah
int 21h
ret
printDot ENDP

printC PROC
pop dx
mov ah,02h
int 21h
ret
printC ENDP

readC PROC
mov ah,01h
int 21h
xor ah,ah
push ax
ret
readC ENDP

start:
call initProg
mov ah,02h
mov dl,2Ah
int 21h
mov ah,08h
int 21h
;until here
call printDot
mov dx,0048h
call printC
mov dx,0069h
call printC
call readC
call endProg
END start

It starts well, prints the asterisk and reads a character. That's all (doesn't get to the procedures).
Ideas why?
Title: Re: Hello and a question
Post by: FORTRANS on October 01, 2009, 06:29:54 PM
Hi,

   There Is a POP DX In printC that destroys the return address.
Also a PUSH AX in readC that will put an incorrect address on the
stack.

Steve
Title: Re: Hello and a question
Post by: Rogare on October 01, 2009, 06:41:43 PM
Oh. You are correct. Thanks!
Title: Re: Hello and a question
Post by: Rogare on October 01, 2009, 06:54:41 PM
I got another 2 question, this time there aren't problems :wink.
1. I heard there are registers like EAX and EBX - can they be used with 16-bit ASM?
2. At what times should I use which register? I know that CX is used for loops and CBW works only for AX - is there a complete lists of what registers are used for each thing, and for general uses what I should use?

Edit: Another question :)
In my book it says there are 5 sizes of variables: DB,DW,DD,DQ,DT. I know what to do with the first, as they match the registers (al is DB and ax is DW). What is the use of the last three?
Title: Re: Hello and a question
Post by: Rogare on October 01, 2009, 09:12:33 PM
Thanks!
About the last part.
I know what they ARE, the question is how can they be used? I can't move them into registers (which are too small) and all the instructions require using registers. For example I got a DQ and I want to add 7 to its value - how would that be done? Stuff like that.
Title: Re: Hello and a question
Post by: FORTRANS on October 01, 2009, 10:05:11 PM
Hi,

   The 32-bit registers can be used  in 16-bit mode, but you
have to be careful in setting up your code segment.  I usually
assemble using two blocks of code, but there are ways to
set things up all at once.  Check the MASM documentation.

   Here is a sample showing code using ECX and CX in sequence.


    2849 0DCA  66| 59                C          POP     ECX             ;
    2850 0DCC  66| 83 E9 01          C          SUB     ECX,1           ;
    2851 0DD0  77 86                 C          JA      RB_1b
    2852                             C
♀◘Microsoft (R) Macro Assembler Version 5.00                  10/1/9Color


    2853 0DD2  8B 0E C87A R          C          MOV     CX,[Padding]
    2854 0DD6  E3 05                 C          JCXZ    RB_3b


Steve N.
Title: Re: Hello and a question
Post by: Rogare on October 02, 2009, 09:23:11 AM
I am afraid I can't read that code :)
Could you scroll and see how I work (few posts higher)?
What do you mean by 2 blocks of code and "to set things up"?
P.S.: For curiosity - what is the code you posted? Output of something? Different assembler's syntax?

Edit: Another question:
When should I use a macro and when should I use a procedure? I know the difference, but could you give examples where one of the options is better than the other?
Title: Re: Hello and a question
Post by: MichaelW on October 02, 2009, 10:59:50 AM
Here is your code with the (2) necessary corrections and some changes to demonstrate how you can use 32-bit instructions in 16-bit code, and two macro examples.

.MODEL SMALL
.386              ; enable 386 instructions
.STACK 100h
.DATA
    x DB ?
.CODE

;initProg PROC
;    mov ax,@DATA
;    mov ds,ax
;    ret
;initProg ENDP

startup MACRO
    mov ax,@DATA
    mov ds,ax
ENDM

;endProg PROC
;    mov ax,4C00h
;    int 21h
;    ret
;endProg ENDP

exit MACRO
    mov ax,4C00h
    int 21h
ENDM

printDot PROC
    mov ah,02h
    mov dl,2Ah
    int 21h
    ret
printDot ENDP

printC PROC
    ;pop dx       ; error
    mov ah,02h
    int 21h
    ret
printC ENDP

readC PROC
    mov ah,01h
    int 21h
    xor ah,ah
    ;push ax      ; error
    ret
readC ENDP

start:

    startup

    mov ah,02h
    mov dl,2Ah
    int 21h
    mov ah,08h
    int 21h

    call printDot

    ;mov dx,0048h
    mov edx,48h
    call printC

    mov ecx, 100000000
  @@:
    loopd @B

    ;mov dx,0069h
    mov edx,69h
    call printC

    call readC

    exit

END start


For parameters that are passed in registers, there are no stack operations involved. For the printC procedure the ASCII character code to be printed is in DX where the DOS Write Character function expects it.

For returning a value from a procedure, there are no stack operations involved. For the readC procedure to return a 16-bit integer you leave the value in the AX register and execute a RET instruction.

For both of the procedures, the misplaced push will "imbalance" the stack and prevent the procedure from returning to the caller. This happens because the RET instruction expects the return address to be at the "top" of the stack, and after the misplaced push whatever was pushed is at the "top" of the stack.
Title: Re: Hello and a question
Post by: Rogare on October 02, 2009, 11:10:41 AM
Thanks!
Just for clarification, but I think I got the idea.
If I put .386 I can use bigger registers. Stack size is still 16-bit.
3 questions:
1. You used somewhere a label called @@ and loopb'ed to @B - what is that?
2. Can I access the higher 16-bit of EAX by themselves? The lower part is divided into 8-bits and each can be accessed, what about higher part?
3. Let's say I do want to pass the whole EAX via stack. In theory I could push the higher 16-bit and the the lower 16-bit. How can it be done? (Almost like Q2, but I want to make sure I don't miss a thing.)
Title: Re: Hello and a question
Post by: sinsi on October 02, 2009, 11:24:39 AM
If you put .386 after .model then things go better in real (16-bit) mode.
1. @@ - search for 'anonymous labels'
2. You can't directly access the top 16 bits, it usually takes a shift or rotate by 16
3. 'push eax'



startup MACRO
    mov ax,@DATA
    mov ds,ax
ENDM

exit MACRO
    mov ax,4C00h
    int 21h
ENDM

Since we're going all dotty with .model, why not use .startup and .exit  :lol
Title: Re: Hello and a question
Post by: MichaelW on October 02, 2009, 11:51:05 AM
1) The @@: is an anonymous label. @B specifies the previous anonymous label, and @F specifies the next.

2) You cannot independently access the upper 16 bits of a 32-bit register, but you can use shifts and rotates to access them indirectly.

3) Pushing or popping a 32-bit value with a 16-bit stack is no problem - MASM will encode the instruction with the correct operand size. If you look in the code that FORTRANS posted at the POP ECX instruction, you will see that MASM encoded it with a 66h operand-size prefix. This prefix overrides the default operand size (16 bits for 16-bit code) so the instruction acts on a 32-bit operand.

And to enlarge on sinsi's comment regarding the position of the processor directive, if you place a .386 or higher processor directive above the model directive, then MASM generates 32-bit code where the default address and operand sizes are 32 bits. If you place a .386 or higher processor directive below the model directive, then MASM generates 16-bit code where the default address and operand sizes are 16 bits.

QuoteSince we're going all dotty with .model, why not use .startup and .exit

They were just quick examples. I use the .startup and .exit directives, and can't really understand why in 16-bit code with a model directive anyone would do otherwise, more than once.

Title: Re: Hello and a question
Post by: Rogare on October 02, 2009, 12:03:43 PM
Thanks all of you!
I'll play a bit and come back if I got more questions.
Title: Re: Hello and a question
Post by: sinsi on October 02, 2009, 12:13:13 PM
Quote from: MichaelW on October 02, 2009, 11:51:05 AM
They were just quick examples. I use the .startup and .exit directives, and can't really understand why in 16-bit code with a model directive anyone would do otherwise, more than once.
Yeah, just joshing  :bdg

Minimum 16-bit exe?

.model small
.code
.startup
.exit
end

Title: Re: Hello and a question
Post by: Rogare on October 02, 2009, 12:36:36 PM
Really? Then why in books they put the minimum with the mov's and the int?
Title: Re: Hello and a question
Post by: MichaelW on October 02, 2009, 12:49:42 PM
QuoteThen why in books they put the minimum with the mov's and the int?

Probably because they want you to understand how to do it without the aid of these directives, the same reason behind starting with full segment definitions instead of the simplified segment definitions.
Title: Re: Hello and a question
Post by: Rogare on October 02, 2009, 01:57:11 PM
Hi again.
I assembled this program:
.MODEL SMALL
.STACK 100h
dotValue EQU 2Ah
.DATA
task DB 1
welcomeMsg DB "Enter task number: $"
endMsg DB "That's the task you asked for.$"
.CODE

; --- Macros from here

dot MACRO
mov ah,02h
mov dl,dotValue
int 21h
ENDM

newLine MACRO
mov ah,02h
mov dl,0Dh
int 21h
mov dl,0Ah
int 21h
ENDM

loadTaskId MACRO
mov ah,09h
mov dx,offset welcomeMsg
int 21h
mov ah,01h
int 21h
sub al,30h
mov task,al
newLine
ENDM

; --- Procedures

procA PROC
mov cx,05h
again:
mov bx,cx
doA:dot
dec bx
cmp bx,0000h
jne doA
loop again
procA ENDP

procB PROC
dot
newLine
procB ENDP

startTask MACRO
LOCAL end_macro
mov bl,task
cmp bl,01h
jne @f
call procA
jmp end_macro
@@: cmp bl,02h
jne @f
call procB
jmp end_macro
;@@: cmp bl,03h
; jne @f
; call procC
; jmp end_macro
@@:
end_macro:
ENDM

goodBye MACRO
mov ah,09h
mov dx,offset endMsg
int 21h
mov ah,08h
int 21h
ENDM

; --- Program Starts Here ---

start:
.startup

loadTaskId

startTask

goodBye

.exit

END


When running it and giving as input not 1 and not 2 - all is working. If I give 1 or 2 it does the work and asks again for task number.
Ideas?

Edit: Worse than that. When giving it input 1, it also does procB!
Title: Re: Hello and a question
Post by: FORTRANS on October 02, 2009, 02:11:00 PM
Quote from: Rogare on October 02, 2009, 09:23:11 AM
I am afraid I can't read that code :)

  It is from a listing.  The code is to the right, the hex numbers
on the left is the address and machine code generated by the
assembler.

Quote
What do you mean by 2 blocks of code and "to set things up"?

  Ignore that, use what MichaelW showed you.  I set things up
with out documentation, so it is a bit contrived.

Quote
P.S.: For curiosity - what is the code you posted? Output of something? Different assembler's syntax?

  Listing file from MASM 5.0.  Here is the code that generated
the listing.


       POP     ECX             ;; 11 January 2008, break out columns
       SUB     ECX,1           ;; 3 => 1, bytes to pixels
       JA      RB_1b

       MOV     CX,[Padding]
       JCXZ    RB_3b


Quote
Edit: Another question:
When should I use a macro and when should I use a procedure? I know the difference, but could you give examples where one of the options is better than the other?

  That is a matter of taste.  They are similar.  Use what you like.
My preference is to use macros for small code snippets that are
used often.  And procedures for larger routines.  My main use of
macros is to use a mnemonic rather than a number to call DOS
functions.


; - - - - - - - - - - - - - - - - - - - - - - - - -
CRLF:   PUSH    AX      ; Save affected registers
       PUSH    DX
       MOV     DL,13   ; CR
       SCALL CONOUT
       MOV     DL,10   ; LF
       SCALL CONOUT
       POP     DX      ; Restore registers
       POP     AX
       RET

And the listing showing the macro expansion.  Note that
CONOUT becomes 2 to call the Console Output function.

    128                                ; - - - - - - - - - - - - - - - - - - -
    129 0051  50                       CRLF:   PUSH    AX      ; Save affected
    130 0052  52                               PUSH    DX
    131 0053  B2 0D                            MOV     DL,13   ; CR
    132                                        SCALL CONOUT
    133 0055  B4 02                 1          MOV     AH,DOSF_CONOUT
    134 0057  CD 21                 1          INT     21H
    135 0059  B2 0A                            MOV     DL,10   ; LF
    136                                        SCALL CONOUT
    137 005B  B4 02                 1          MOV     AH,DOSF_CONOUT
    138 005D  CD 21                 1          INT     21H
    139 005F  5A                               POP     DX      ; Restore regis
    140 0060  58                               POP     AX
    141 0061  C3                               RET


Regards,

Steve N.
Title: Re: Hello and a question
Post by: Rogare on October 02, 2009, 02:14:21 PM
Thanks for that - cleared some stuff.
Maybe you could also help me with the last problem I posted? Another thing I just found out - it never gets to the end_macro label when input is 1 or 2...

Edit: Bah... Forgot to write "ret" at the end of the procedures...
Edit 2: Is there a way to put the macros and procedures after the code itself? In .NET languages it just works and in C there is an empty definition earlier.
Edit 3: Question from Edit 2 still stands, but I got a bigger one.
I wrote this code:
dot MACRO
mov ah,02h
mov dl,dotValue
int 21h
ENDM

newLine MACRO
mov ah,02h
mov dl,0Dh
int 21h
mov dl,0Ah
int 21h
ENDM

procC PROC
mov bp,sp
xor cx,cx
mov up,ch
mov cx,0005h
again:
mov bx,cx
;-
mov ah,08h
int 21h
;-
doA:dot
dec bx
jnz doA
cmp cx,0001h
jne @f
mov al,01h
mov up,al
@@: mov al,01h
cmp up,al
jne nl
add cx,2
cmp cx,07h
jne nl
mov cx,01h
nl: mov dl,up
add dl,30h
mov ah,02h
int 21h
newLine
dec cx
jnz again
ret
procC ENDP


This code works fine, (up is DB, by the way) but when I tried replacing up with [bp-1] for some reason it was always reset to 98... It happened only after calling "dot" or "newLine". I tried putting the macro code inside the proc myself, still same problem.
Ideas?

Edit 4: Sorry for mass-editing. Solved problem 3, just said push cx at the beginning and changed to [bp-2] (and used ax instead of al when comparing). Still wants to know if I can put proc's and macros after the main.
Title: Re: Hello and a question
Post by: dedndave on October 02, 2009, 09:28:03 PM
macros like to be declared prior to use - similar to equates
many times, we will put the macros in an include file, then reference that file at the beginning of the source
proc's can be moved to the bottom
Title: Re: Hello and a question
Post by: Rogare on October 02, 2009, 09:37:38 PM
Oh, oh!
A great question you raised!
How do I include files? How can I put proces and macros outside the main program? How can I make a set of proces and use them later (like stdio.h in C and such things)?
Title: Re: Hello and a question
Post by: dedndave on October 02, 2009, 09:51:12 PM
well - you can just put them in include files
or assemble them and create a library (with the obj files), if you like
include is easy
create the file - we usually put them in the masm32\include folder or in a specific project folder
then - at the beginning of the assembly file...

        include \masm32\include\MyIncFile.inc

whatever is in the inc file will be expanded in place of the "include" line
it is a good idea to put the .model, etc, first - then the includes - then the data and code segments
Title: Re: Hello and a question
Post by: FORTRANS on October 02, 2009, 09:54:04 PM
Hi,

QuoteHow do I include files?

   That's easy, see the following code.


; - - - - - - - - - - - - - - - - - - - - - - - -
        .XCREF
        .XLIST
INCLUDE  DEFMS.ASM ; MACROs and MS-DOS definitions
        .LIST
        .CREF


   That turns off the cross reference and listing, include the
macros and equates, and then turns the listing and cross
references back on.

QuoteHow can I put proces and macros outside the main program?

   Just put them in a file and include it.


        RET     ; END FINDNAM4

CODE    ENDS
        INCLUDE PIXEL.ASM
        INCLUDE BMP2.ASM
        END     START


   At the end of this program I "INCLUDE" two more sets of
code.  Different versions of the program can use common
routines that way.  If I improve the shared code all versions
are "updated" without any edits.

Regards,

Steve N.

P.S.
I see Dave beat me to it.  Hope this adds something.

SRN
Title: Re: Hello and a question
Post by: dedndave on October 02, 2009, 09:59:11 PM
always good to have more than one approach, Steve
i didn't think to mention turning off the listings
i use .nolist - must be a newer syntax
Title: Re: Hello and a question
Post by: Rogare on October 02, 2009, 10:15:45 PM
Okay, let's see if I got it.
I create a normal ASM file with proces and macros.
I create an ASM file for my program and writes "include" (with xlist and all) with the path of the first ASM after model and stack before data and code?
Can I put the included file also somewhere in My Documents and such (for ex.: where the program's ASM file is), or only in masm32/includes ?
Title: Re: Hello and a question
Post by: dedndave on October 03, 2009, 01:40:19 AM
you can put it where you like, as you are going to specify where it is located in the include directive
choose someplace that makes sense
that file has to be in place whenever you want to assemble the program
if you look in the masm32\include folder, there are several examples to look at
as a side-note, there is an environment variable named INCLUDE for masm
if you specify c:\masm32\include in the INCLUDE path, masm will look there for inc files that do not have a specific path
then, all you need to have in the program file is

        include MyIncFile.inc

masm will look for it in the INCLUDE path
Title: Re: Hello and a question
Post by: MichaelW on October 03, 2009, 03:52:32 AM
IIRC procedures must be defined or declared above the point at which they are called only if they are called with invoke. The MASM equivalent of a declaration is a prototype done with the PROTO directive.
Title: Re: Hello and a question
Post by: Rogare on October 03, 2009, 05:18:37 PM
I tried creating a program that gets a number and return its ASCII match (65 -> A, 99 -> c).
It returns wrong values, any ideas why?
Code:
---
Just after I left the house I found the first problem with my code. If it won't work after that, I'll ask again.
Title: Re: Hello and a question
Post by: Rogare on October 08, 2009, 10:12:46 AM
Here is a new problem.
I tried working with structures (did work for a while), but then I wanted to give a structure as an argument for a procedure. The following example should print on the screen "1" or "0" (I suspect that I switched the 1 and 0 there...) and then wait for use input. It doesn't do that.
Here is the code:
.MODEL SMALL
.386
.STACK 100h
myNOP EQU 20h
book STRUC
the_name DB 50 DUP(20h)
author DB 50 DUP (20h)
noPages DW 0000h
book ENDS
.DATA
myBook book <"1984$","George Orwell$",250d>
.CODE
.startup
mov bx,21h
mov [myBook.noPages],bx
lea bx,myBook
push bx
mov bx,myNOP
push bx
call book_canbe
pop dx
add dl,30h
mov ah,02h
int 21h
mov ah,08h
int 21h
.exit

book_canbe PROC
mov bp,sp
mov di,[bp+4] ;book address
mov cx,[bp+2] ;page number
mov bx,[di+book.noPages]
pop ax
pop ax
cmp bx,cx
jb return_false
push 0001h
jmp the_end
return_false:
push 0000h
jmp the_end
the_end:
ret
book_canbe ENDP

END

Ideas?
Title: Re: Hello and a question
Post by: dedndave on October 08, 2009, 02:52:47 PM
first of all, the END directive should name the entry point

start:
.startup
.
.
.
end start

the next thing i see is the book_canbe procedure makes a real mess out of the stack
when you call a procedure, the return address is pushed onto the stack
if you expect the procedure to return, the RET instruction needs to POP off a valid code address
you have popped that return address into AX and not restored it

the other thing i see is the use of the stack frame
it is good practice to save the BP value so that other procedures may call this one without destroying their stack frame
in this case, it is probably ok, but it is just a good habit to push the BP value prior to setting the frame
once the frame has been established, the pushed parameters may be accessed by using bp

SomeProc PROC
        push    bp
        mov     bp,sp
.
        mov     ax,[bp+4]   ;pushed parm into AX
.
        leave               ;same as mov sp,bp then pop bp
        ret
SomeProc ENDP

one final note
if you are going to push a parameter onto the stack prior to a call, the stack needs to be cleaned up afterward
you can do this one of 3 ways:

        push    SomeParameter
        call    SomeProc
        pop     ToSomeplace

or

        push    SomeParameter
        call    SomeProc
        add     sp,2            ;discard the stack parm

the third way is to let the RET instruction clean up for you

        ret     2               ;return, then discard 2 stack bytes

EDIT - the LEAVE instruction above may be replaced with POP BP if the procedure has a balanced stack
in some cases, it is faster and more convenient to let the LEAVE instruction balance the stack for you
Title: Re: Hello and a question
Post by: Rogare on October 08, 2009, 04:05:35 PM
Puff... I always forget about the return address things in stack...

I also found out that .startup is instead of start: and END start. Tried to add this and got errors saying it is ignored because of .startup.
If anyone is interested, here is the code (and it works! - returns 1 just as I wanted it to):
.MODEL SMALL
.386
.STACK 100h
myNOP EQU 20h
book STRUC
the_name DB 50 DUP(20h)
author DB 50 DUP (20h)
noPages DW 0000h
book ENDS
.DATA
myBook book <"1984$","George Orwell$",250d>
.CODE

.startup
mov bx,21h
mov [myBook.noPages],bx
lea bx,myBook
push bx
mov bx,myNOP
push bx
call book_canbe
pop dx
add dl,30h
mov ah,02h
int 21h
mov ah,08h
int 21h
.exit

book_canbe PROC
mov bp,sp
mov di,[bp+4] ;book address
mov cx,[bp+2] ;page number
mov bx,[di+book.noPages]
pop dx
pop ax
pop ax
cmp bx,cx
jb return_false
push 0001h
jmp the_end
return_false:
push 0000h
the_end:
push dx
ret
book_canbe ENDP

END
Title: Re: Hello and a question
Post by: Rogare on October 08, 2009, 06:31:22 PM
Another question!
How can I dynamically allocate memory? For example: dynamic array's size.
Title: Re: Hello and a question
Post by: dedndave on October 08, 2009, 06:52:31 PM
there are a few ways to do it
perhaps the simplest way is to use the heap functions

GetProcessHeap
http://msdn.microsoft.com/en-us/library/aa366569(VS.85).aspx

HeapAlloc
http://msdn.microsoft.com/en-us/library/aa366597(VS.85).aspx

HeapFree
http://msdn.microsoft.com/en-us/library/aa366701(VS.85).aspx

oops - those are 32 bit - lol

for 16-bit, there is an INT 21h function call to allocate memory
what you need is a good reference for INT 21h
if you google around for Ralf Brown's Interrupt List, it will tell you many things
it is a 6-part zip

here you go...
http://www.cs.cmu.edu/~ralf/files.html
Title: Re: Hello and a question
Post by: Rogare on October 08, 2009, 06:57:48 PM
Thanks, I'll google in a sec. But first I got another problem.
I got an include file with a structure and a procedure. Where should I put the include statement? I tried just before the .DATA, got this error (several times):
error A2034: must be in segment block
Where should it be?
Title: Re: Hello and a question
Post by: dedndave on October 08, 2009, 07:02:25 PM
the procedure needs to be in the .text segment (in the include)
the structure definition should not matter
but, the structure declaration needs to be in .data or .data?

i usually list all includes after my model/processor directives
Title: Re: Hello and a question
Post by: Rogare on October 08, 2009, 07:06:43 PM
I didn't understand what you wrote, but you gave me the idea just to put .CODE before the procedure.
It works, but it'll be nice to understand what you meant.
Title: Re: Hello and a question
Post by: Ossa on October 08, 2009, 08:41:04 PM
.text is an alias for .code (it is the usual name of the code segment in the PE header under 32 bit).

The procedure has to go in the code segment because it is code - also, the structure definition should (I'm not sure it has to) go before the first use of it. For this reason it is not usual (in the greater world outside this board) for include files to contain code. The convention is that includes (.inc in ASM, .h in C/C++, etc) to contain definitions/prototypes/externs/etc but do not include code or declarations. If you want to split your code up, you then put it in several different files and assemble each one into a separate object file and link them together. Despite this, a disturbing number of people in the ASM community have code in INC files that they include - mainly because it is easier to do - and this is great for smaller projects but once you start on a large project it really becomes quite a bad way to do it.

Hope that actually makes sense,
Robert
Title: Re: Hello and a question
Post by: FORTRANS on October 09, 2009, 01:36:06 PM
Hi,

   As you can see in the example I posted, you can include a file
outside of a segment.  I ended the code segment and then
included the two files just before the end statement.  The
files have their own segment definitions for code and data.

  The first include in that post was for macros and symbol
definitions.  It was included before any segment definitions
as it contains no code or data.

   As Robert noted, including files that contain code (and/or
data?) is probably not the best method if you have a big
project.  In that case a "makefile" assembling and linking
together separate files is probably better.  If you have a
set of commonly used routines, a library may be useful.

Regards,

Steve N.
Title: Re: Hello and a question
Post by: dedndave on October 09, 2009, 02:36:38 PM
i have to ask - why is using an include file not a good idea ?
it is simply an expansion of text
Title: Re: Hello and a question
Post by: FORTRANS on October 09, 2009, 02:49:04 PM
Quote from: dedndave on October 09, 2009, 02:36:38 PM
i have to ask - why is using an include file not a good idea ?
it is simply an expansion of text

Hi,

   I think it's fine.  I use it.  But it reassembles the code and data
each time, so for a larger project it might seem inefficient?

$0.02,

Steve N.
Title: Re: Hello and a question
Post by: dedndave on October 09, 2009, 03:14:01 PM
ah yes - i agree Steve
i have not yet had a project in 32-bit large enough to mess with multiple files
i have, however, written a few procedures for distribution
i figure the programmer can either stick the proc in their program, or create an obj and lib it, if they like
Title: Re: Hello and a question
Post by: Rogare on October 09, 2009, 04:45:51 PM
I am working on a little thing right now. is there a place where I could post it when it is partially done (or completely) and get some suggestions about better programming habits for ASM and optimizations?
Title: Re: Hello and a question
Post by: dedndave on October 09, 2009, 04:51:45 PM
when you type in a reply, at the bottom is a place for Additional Options...
it has to be a ZIP file
Title: Re: Hello and a question
Post by: Rogare on October 10, 2009, 05:14:30 PM
I got a little request.
Could you write a little program that:
reads a character
if escape was pushed it exits
if F1 was pushed it prints "1"
if F2 was pushed it prints "a"
and jumps back to "reads a character"
?
I think that if I got the idea of this, I could finish the first little program.
Thanks!
Title: Re: Hello and a question
Post by: dedndave on October 10, 2009, 05:37:14 PM
i normally use INT 16h, functions 0 and 1 (BIOS calls) for keyboard stuff like that
is that ok ? - or did you want to use INT 21h (DOS calls) ?
Title: Re: Hello and a question
Post by: Rogare on October 10, 2009, 05:49:32 PM
I prefer the 21h.
Just for curiosity - what is the difference for me? I know what is BIOS and what is DOS, why should it matter for the programmer?
Title: Re: Hello and a question
Post by: dedndave on October 10, 2009, 06:20:00 PM
well - INT 16h is a simpler interface
but, INT 21h allows redirection, which BIOS does not
for example, you can create a "response file" that has all the text "answers" in it
then, at the DOS prompt, type "MyFile <response.txt"
all the input for MyFile can come from a pre-made text file
another example is piping through filters, which is very similar
MyFile|SomePipe.exe
SomePipe can filter and/or alter the input to MyFile
the selection of BIOS vs DOS also affects things like ANSI.SYS and codepages
DOS input can use alternate or re-defined character sets - BIOS cannot

it is easier to identify function keys, arrow keys, etc using BIOS
Title: Re: Hello and a question
Post by: Rogare on October 10, 2009, 06:41:40 PM
Until I research the BIOS I'd prefer to work with DOS functions which I already know how to use.

Edit: Nevermind, solved.
Title: Re: Hello and a question
Post by: dedndave on October 10, 2009, 11:43:49 PM
this is not exaclty what you wanted
it reads any key and displays the character and code for it
if it is an extended key (like function keys or arrow keys), it displays the key code X 256
this program "polls" the keyboard, rather than just waiting for a key
if you wanted to, you could easily adapt it to do other things while there is no keyboard input
Title: Re: Hello and a question
Post by: Rogare on October 11, 2009, 07:20:22 AM
Wow. I understood almost everything there (though I used the interrupt table many times). Learned few nice tricks from it.
Thanks again!
Title: Re: Hello and a question
Post by: dedndave on October 12, 2009, 09:10:34 AM
here is a better version
same program, only it outputs the values in hex
a little easier to see the extended keys
Title: Re: Hello and a question
Post by: Rogare on October 12, 2009, 12:37:23 PM
Nevermind - solved myself :)