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
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
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).
it ran fine here
here is a 16-bit assembly batch file, as well as goto16.asm and exe
The .exe really works. The code is same.
How do I work with the .bat file?
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)
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.
make sure that the 16-bit linker exe filename in the batch file matches the one you have in the masm32\bin folder
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
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.
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?
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
. . .
.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?
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
Well, I got Link563.exe and link16.exe. Tried working with both - always the same emptiness of the .exe.
here is a new batch file for you
i have written it to use Link16.exe in the D:\masm32\bin folder...
Same problem.
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
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.
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
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
WOW.
Thanks so much for everything!
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
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?
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
Oh. You are correct. Thanks!
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?
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.
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.
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?
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.
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.)
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
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.
Thanks all of you!
I'll play a bit and come back if I got more questions.
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
Really? Then why in books they put the minimum with the mov's and the int?
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.
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!
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.
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.
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
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)?
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
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
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
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 ?
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
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.
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.
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?
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
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
Another question!
How can I dynamically allocate memory? For example: dynamic array's size.
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
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?
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
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.
.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
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.
i have to ask - why is using an include file not a good idea ?
it is simply an expansion of text
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.
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
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?
when you type in a reply, at the bottom is a place for Additional Options...
it has to be a ZIP file
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!
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) ?
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?
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
Until I research the BIOS I'd prefer to work with DOS functions which I already know how to use.
Edit: Nevermind, solved.
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
Wow. I understood almost everything there (though I used the interrupt table many times). Learned few nice tricks from it.
Thanks again!
here is a better version
same program, only it outputs the values in hex
a little easier to see the extended keys
Nevermind - solved myself :)