Hi, I am trying to make a simple 16 bit .COM program which basically tries to see if a file exists or not. But it either freezes my command prompt or tells me it encountered some illegal instructions (double clicking the .com file).
Here is my code:
.model tiny
.code
ORG 100H
Start:
mov ah, 4EH ;prepares search first function
mov dx, offset STRING_LC ;offset
mov cx, 0 ;read only
int 21
JC NoFile
File:
mov ah, 9
mov dx, offset msg
int 21
jc Done
NoFile:
mov ah, 9
mov dx, offset msg2
int 21
Done:
mov ah, 9
mov dx, offset msg3
int 21
STRING_LC DB '*.txt',0 ;file/files looking for
msg3 db 'finish$'
msg db 'file found$'
msg2 db 'file not found$'
END Start
int 21
try int 21h
Also
jc Done
try jmp Done
thank you!!! Silly mistake using jc instead of jmp and I guess you can't leave out the hex :biggrin:
Hi Pokerice,
Apart from the errors, I can't see the part for going back to DOS. Something like:
mov ax, 4c00h
int 21h
Gunther
Quote from: Gunther on May 28, 2014, 05:12:44 PM
Hi Pokerice,
Apart from the errors, I can't see the part for going back to DOS. Something like:
mov ax, 4c00h
int 21h
Gunther
Ha! Well spotted. My excuse? Beer goggles...
Hi sinsi,
beer would be nice. :lol:
Gunther
haha thanks gunther 8)
By the way, using ret is the same right?
As long as the stack is balanced then RET will work, but only for a .com file.
From memory, the top of the stack is 0, so it RETs to CS:0000, which is an INT 20H.
Better to use the approved way as Gunther has.
i think the JC might be ok
but, there is a FindFirst function, and a FindNext function
i haven't used it for years - lol
RET is ok for a .COM, exactly as Sinsi mentioned
for .EXE's, they used to...
main PROC FAR
xor ax,ax ;zero AX
push ds ;initially, the DS register holds the PSP segment
push ax
;main code
ret
main ENDP
END main
because "main" is typed as FAR, the RET at the end will be a RETF
so, it branches to PSP:0
main should be typed as NEAR for a .COM program
INT 21h, AH=4Ch is prefered
Thanks.. but dedndave, you have completely lost me at the "...typed as FAR, the RET...." part. :lol:
Pokerice,
Quote from: Pokerice on May 28, 2014, 11:45:43 PM
Thanks.. but dedndave, you have completely lost me at the "...typed as FAR, the RET...." part. :lol:
Don't be afraid. In your COM file (limited to 64 KB) are all procedures by defintion near (same segment). Change the FAR to NEAR and the assembler generates the appropriate RET machine code.
But you'll do safe if you use INT 21h with AX = 4c00h. That works for COM and EXE files and - not to forget - for 16-bit Windows applications, too.
Gunther
here is what i use as a Small model EXE template
.MODEL Small
.STACK 4096
.DOSSEG
.386
OPTION CaseMap:None
;####################################################################################
.DATA
s$Msg db 'Hello World !',0Dh,0Ah,24h
;************************************************************************************
.DATA?
;####################################################################################
.CODE
;************************************************************************************
_main PROC FAR
mov dx,@data
mov ds,dx
mov dx,offset s$Msg
mov ah,9
int 21h
mov ax,4C00h
int 21h
_main ENDP
;####################################################################################
END _main
here is what i use as a Tiny model COM template
.MODEL Tiny
.386
OPTION CaseMap:None
;####################################################################################
.CODE
;************************************************************************************
ORG 100h
_main PROC NEAR
mov dx,offset s$Msg
mov ah,9
int 21h
mov ax,4C00h
int 21h
_main ENDP
;####################################################################################
s$Msg db 'Hello World !',0Dh,0Ah,24h
;####################################################################################
END _main
notice that the COM PROC is typed as NEAR
although - it's not needed, as NEAR is the default type
Quote from: Pokerice on May 28, 2014, 11:45:43 PM
Thanks.. but dedndave, you have completely lost me at the "...typed as FAR, the RET...." part. :lol:
Hi,
When you jump to, (or call) a routine in the same segment, it is
a NEAR jump, you use only an offset from the current position.
When the code is in a different segment, you need a FAR jump (or
call) specifying both a segment and an offset into that segment.
In a *.COM program, the PSP, code, data, and stack are all in the
same segment on program load. A *.EXE program has separate
segments for the PSP and code when the program loads. It should
(mostly) also have separate segments for the stack and data.
Regards,
Steve N.
try this one
.MODEL Tiny
.386
OPTION CaseMap:None
;####################################################################################
.CODE
;************************************************************************************
ORG 100h
_main PROC NEAR
xor cx,cx ;file attribute = 0
mov dx,offset szTxtExt
mov ax,4E00h ;Find First File
int 21h
mov dx,offset s$NotFound
jc ShowMessage
mov dx,offset s$Found
ShowMessage:
mov ah,9
int 21h
mov dx,offset s$Finish
mov ah,9
int 21h
mov ax,4C00h
int 21h
_main ENDP
;####################################################################################
szTxtExt db '*.txt',0
s$Found db 'File Found',13,10,24h
s$NotFound db 'File Not Found',13,10,24h
s$Finish db 'Finish',13,10,24h
;####################################################################################
END _main
Thank you all of you 8)! Esepcially FORTRANS for the clear explanation :biggrin:
With that being said, can you use PROC NEAR for some code and PROC FAR for others?
Also, regarding to the segments, do some memory block just get automatically allocated as a certain segment or is it always a specific memory block? Say for DOS, since only one segment,
does it just generate 64kb of memory randomly for your program to use?
A segment is not necessarily 64KB. The maximum is 64KB, but a segment could be as small as 16 bytes.
For a .COM program DOS allocates all available memory. For an .EXE program DOS allocates enough memory to contain the program image and the PSP, plus any additional memory specified in the EXE header.
Quote from: MichaelW on May 29, 2014, 05:40:36 PM
For a .COM program DOS allocates all available memory. For an .EXE program DOS allocates enough memory to contain the program image and the PSP, plus any additional memory specified in the EXE header.
Right, but EXE programs are often very memory hungry, too. So it's necessary to shrink the memory for the EXE if you need a dynamic buffer during run time.
Gunther
for most procedures that you write, you will not use far calls
if you type a procedure as far, the assembler will use a far call automatically
one place you may see far procedures is if you decide to revector an interrupt
another is if you write a device driver
in your own code, you might use far code segments in a Medium or Large memory model program
http://en.wikipedia.org/wiki/Intel_Memory_Model (http://en.wikipedia.org/wiki/Intel_Memory_Model)
in a Small or Compact model program, all code is in the same segment
so, procedures can generally be near
it's hard to write a program that needs more than 64 Kb of code - lol
not to say it hasn't been done
but, you won't do it in a few days :biggrin:
you are more likely to use multiple data segments
Hi,
Quote from: Pokerice on May 29, 2014, 01:16:36 PM
With that being said, can you use PROC NEAR for some code and PROC FAR for others?
Yes, but as Dave said, it is not often that you would want to.
Maybe if you wrote a subroutine library or some such.
Quote
Also, regarding to the segments, do some memory block just get automatically allocated as a certain segment or is it always a specific memory block? Say for DOS, since only one segment,
does it just generate 64kb of memory randomly for your program to use?
Usually DOS will load your program in the first available memory.
If you have more than one segment in your program, you can
specify the load order, but they will normally be loaded one after
another with no wasted space. (Give or take.)
Quote from: MichaelW on May 29, 2014, 05:40:36 PM
For a .COM program DOS allocates all available memory. For an .EXE program DOS allocates enough memory to contain the program image and the PSP, plus any additional memory specified in the EXE header.
The default for either a *.COM or *.EXE program is to allocate
all memory to the program. There are LINK options to limit memory
to a lesser value (and programs to edit the EXE header to do the
same thing), but I have seen very few programs that actually do
that.
Quote from: Gunther on May 29, 2014, 08:16:33 PM
Right, but EXE programs are often very memory hungry, too. So it's necessary to shrink
the memory for the EXE if you need a dynamic buffer during run time.
I wrote a program using a variable sized buffer that just uses
the memory following the program without deallocating/reallocating
the memory. I just set a segment register to the end of the program,
and incremented it for each additional data item. Use information
from the PSP to locate the end of the memory allocated to the
program. (And have a whole bunch of fun when your {my} math
does not add up.) I think the shrink/allocate paradigm is a hold-over
from C programming. Or it could be that I am just lazy.
Quote from: dedndave on May 29, 2014, 08:46:30 PM
you are more likely to use multiple data segments
Yeah. Up to a few thousand 48 byte "fake" segments in the
above mentioned program. I have also written programs that
had data arrays that exceeded the normal segment limits and
thus required more than one data segment.
Regards,
Steve N.
Steve,
Quote from: FORTRANS on May 29, 2014, 10:36:05 PM
I think the shrink/allocate paradigm is a hold-over
from C programming. Or it could be that I am just lazy.
in other words, mostly for blended code EXEs (C, Pascal, BASIC + assembly language).
Gunther
compiled code might well set up the EXE header so it doesn't allocate everything
DOS was relatively easy to play with
you can open debug and dump the memory, starting at the 0:0, if desired
as you dump, you can see...
the interrupt vector table
the BIOS data area
resident DOS (msdos.sys, io.sys, resident part of command.com)
your device drivers (link listed)
and, finally, the PSP for debug
each block of memory is prefaced with a heap allocation block
it's a 16-byte (paragraph) of info linking to the next heap block
as you play with the memory free/allocate functions, you can see the heap allocation blocks change
in the BIOS data area, there is a variable that tells how much memory is available
when a TSR installs itself high in memory, it might calculate a new top of memory segment and update the variable
so, you can see that up high, too
if you wanted to free and allocate memory - good idea to consult this variable, first :P
Thank you everyone, it is becoming clearer to me now but one thing still confuses me greatly :icon_redface:. I thought that win32 runs with a flat memory model. The memory models shown in http://en.wikipedia.org/wiki/Intel_Memory_Model (http://en.wikipedia.org/wiki/Intel_Memory_Model) seemed to be segmented. So does that mean I can choose to write my code with either flat memory model or segmented?
I understand that basically flat memory model is just making the memory appear to be one continuous block and segmented is just splitting them into sections and accessing them with register and offset(a way to access more memory). So how come I can write using segmented memory model if win32 uses flat memory model?(while using a virtual machine running windows xp 32bit) Like the "print and search" code I was writing, that is definitely segmented memory model, right?
Could someone explain it kindly and give some examples as to writing what programs in what OS belongs to which memory model. I am sorry for asking so many questions but there seems to be gaps in my knowledge or something I learnt is incorrect.
Hi Pokerice,
your questions are not so easy to answer.
- A DOS program - and your application is one - must use the segemented memory and is limited to see only 1 MB of memory, although you've installed more. It can't see that memory. That has to do with the address generation in Real Mode.
- To use the FLAT memory model - sometimes called the 32-bit COM model - your application has to be a native 32-bit Windows application. You must use the Windows API and your application must have good manners.
- With a lot of tricks, your DOS program can use some DPMI services and as a native 32-bit DPMI client, it can use for a while the 32-bit FLAT memory. If you're interested in these aspects, you'll find examples here (http://masm32.com/board/index.php?topic=2100.0) and here (http://www.masmforum.com/board/index.php?topic=14874.0). But to say it clear: That kind of programming style is to hard for a beginner.
Gunther
yes - that wiki page on segmented memory models applies to 16-bit DOS programs
as Gunther mentioned, the flat model is used for windows
Quote from: FORTRANS on May 29, 2014, 10:36:05 PM
The default for either a *.COM or *.EXE program is to allocate
all memory to the program. There are LINK options to limit memory
to a lesser value (and programs to edit the EXE header to do the
same thing), but I have seen very few programs that actually do
that.
What I recall is that the "default" EXE header values effectively specify all available memory.
I think i get the gist of it now. And indeed those examples Gunther provided are more than what I can digest. :lol: Going to avoid them for now. Thanks for the help everyone! :biggrin:
Hi Pokerice,
Quote from: Pokerice on May 30, 2014, 05:42:06 PM
And indeed those examples Gunther provided are more than what I can digest. :lol: Going to avoid them for now. Thanks for the help everyone! :biggrin:
I wouldn't say that so strict. If you're willing to go that way, you must simply read and learn a lot of new stuff. You should be familiar with the DOS Interrupts for memory management and with such things like DPMI (DOS Protected Mode Interface). That'll work.
Gunther
Hi,
Okay, one can display the data in the *.EXE header with EXEMOD.EXE
program that came with (at least) MASM version 5.0. I looked in
the MASM32\BIN, and didn't find it there. I now see an EXEHDR.EXE
in MASM 6.0, but did not use it.
Anyway, I wrote an EXEHDR.EXE that only prints out exMinAlloc,
exMaxAlloc, and exCheckSum values as documented in the MS-DOS
5.0 Programmer's Reference. Attached with some example output.
Amusingly I tried it on itself, and it has a bad exMinAlloc value. Good
old Microsoft tools. The example output also shows that many programs
do not have a valid checksum.
Cheers,
Steve N.