Looking for .COM program sources in NASM Assembly

28 views
Skip to first unread message

Paolo Amoroso

unread,
Sep 4, 2022, 6:48:22 AMSep 4
to
I'm looking for source code of MS-DOS .COM programs in real-mode 8086 Assembly written in NASM syntax. Any repositories or recommendations?

I'm learning Assembly programming under MS-DOS (and MikeOS). To avoid the complexity of x86 segmentation, for the time being I prefer to focus on single-segment programs, as I plan to write small programs anyway. So I'd like to study examples of how such systems organize and reference data and code. I searched a bit but found remarkably little .COM code.

Kerr-Mudd, John

unread,
Sep 4, 2022, 9:05:35 AMSep 4
to
Just to get you going

; Hi.com
;13:54 2022-09-04 23 clean asm
;13:58 2022-09-04 23 to middle of screen added comments
;14:01 2022-09-04 22 commented out section header; no aligment
cpu 8086
org 0x100
;section .code ; not required
mov ah,0xB8 ; B800 text mode screen seg
push ax
pop es ; es:di pts to scrn
mov si,WelcomeStr ;
mov cl,WelcomeLth ;
mov ah,02 ; green
mov di,2*(12*80+40) ; middle of screen
PrtaChar: ; printloop
lodsb ; get a char
stosw ; put char to screen, attribute in ah
loop PrtaChar
ret ; all done
;section .data ; not required for this example
WelcomeStr db 'Hi!'
WelcomeLth equ $-WelcomeStr



Sorry, I've tried DDGo and got lots of dead ends too. try clax for some
older posts, but I'm not suggesting my stuff is best practice!

news:comp.lang.asm.x86
(moderated, so your post might not show up for a while)

--
Bah, and indeed Humbug.

Steve Nickolas

unread,
Sep 4, 2022, 12:46:45 PMSep 4
to
I happen to have some in https://github.com/buricco/doslite

-look for the .a86 files.

-uso.

Paolo Amoroso

unread,
Sep 5, 2022, 3:39:36 AMSep 5
to
Kerr-Mudd, Steve, thanks for the code and the advice.

Kerr-Mudd, John

unread,
Sep 5, 2022, 5:54:50 AMSep 5
to
I was going to object that a86 isn't nasm but your chcp.a86 assembled
without error (though I have to say that I dislike numbers as labels)

Steve Nickolas

unread,
Sep 5, 2022, 3:45:17 PMSep 5
to
On Mon, 5 Sep 2022, Kerr-Mudd, John wrote:

> I was going to object that a86 isn't nasm but your chcp.a86 assembled
> without error (though I have to say that I dislike numbers as labels)

NASM doesn't care what extension you give it. šŸ¤Ŗ

-uso.

Herbert Kleebauer

unread,
Sep 5, 2022, 6:03:36 PMSep 5
to
But it doesn't make much sense to write .com programs which can't
be run natively on a current computer system. Windows programs also
don't use segmentation and there in no difference in the assembly code
for DOS and Windows (as long as you use also 32 bit instructions in DOS,
which makes things much easier). The big difference is, that there
is no such simple file format as the .com format in DOS so you will have
to use a linker which generates the proper file structure for a Windows
binary.

But if you really want, you can also generate any byte if the .exe
file by your assembler source code so NASM directly generates the
exe file. Here an example for a simple program which reads from
stdin, converts any lowercase letter to upper case and writes it
to stdout (the code itself starts at the label winmain, the rest
is just the data of the exe file format). Because NASM uses an awful
syntax you have to include "mac.inc" to be able to use a readable
instruction format (I post mac.inc in a follow up):


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; upper.asm: copy stdin to stdout, convert a-z to A-Z ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; nasm -O99 -f bin -o upper.exe upper.asm
%include "mac.inc"

UseIdatSection equ 0 ; 0 if no idat section is used
UseUdatSection equ 0 ; 0 if no udat section is used

;#==================================================================#
;# Start of Headers #
;#==================================================================#

; +--------------------------------------------+
; | Start of DOS Header |
; +--------------------------------------------+

section .text vstart=0

doshead_start:
; DOS .EXE header
dc.b 'MZ' ; Magic number
dc.w dosfilesize % 512 ; Bytes on last page of file (0->512)
dc.w (dosfilesize-1)/512+1
; Pages in file (Page=512 byte)
dc.w 0 ; Relocations (nr of entries)
dc.w doshead_size/16 ; Size of header size in paragraphs (16 byte)
dc.w 0 ; Minimum extra paragraphs needed
dc.w $0ffff ; Maximum extra paragraphs needed
dc.w 0 ; Initial (relative) SS value (ss=load_adr+nr)
dc.w dosstack ; Initial SP value
dc.w 0 ; Checksum
dc.w dosmain ; Initial IP value
dc.w 0 ; Initial (relative) CS value (cs=load_adr+nr)
dc.w reloc ; File address of relocation table
dc.w 0 ; Overlay number
dc.w 0,0,0,0 ; Reserved words
dc.w 0 ; OEM identifier (for e_oeminfo)
dc.w 0 ; OEM information; e_oemid specific
dc.l 0,0,0,0,0 ; Reserved words
dc.l WinHeader ; File address of new exe header
reloc:
doshead_end:
doshead_size equ doshead_end-doshead_start

@@0 equ $-$$ ; current file position

section .text0 vstart=0

dosstart:
dosmain:move.w s6,-[sp]
move.w [sp]+,s0
move.w .text,r1
move.b $09,m0
trap $21
move.w $4c01,r0
trap $21
text: dc.b 'Nice to meet somebody who is still using DOS,',13,10
dc.b 'but this program requires Win32.',13,10,'$'
align 16, db 0

dosstack equ $+256 ; 256 Byte stack
dosfilesize equ $-dosstart+256

; +--------------------------------------------+
; | End of DOS Header |
; +--------------------------------------------+


; +--------------------------------------------+
; | Start of Windows Header |
; +--------------------------------------------+

ImageBase equ $00400000
SectionAlignment equ 4096
FileAlignment equ 512

@@1 equ @@0 + $-$$ ; current file position
WinHeader equ @@1

section .text1 vstart=ImageBase
ImageBase1 equ $
; ImageBase1 has same value as ImageBase but is nonrelatve

; see WINNT.H for information
dc.b 'PE',0,0 ; magic word
; _IMAGE_FILE_HEADER:
dc.w $014c ; Machine ($014c=Intel x86 processor)
dc.w NumberOfSections ; NumberOfSections
dc.l $36a57950 ; TimeDateStamp (seconds since 31.12.69 16:00)
dc.l 0 ; PointerToSymbolTable
dc.l 0 ; NumberOfSymbols
dc.w SizeOfOptionalHeader ; SizeOfOptionalHeader
dc.w $010f ; Charcteristics

; 0x0001 Relocation info stripped from file.
; 0x0002 File is executable (i.e. no unresolved externel references).
; 0x0004 Line nunbers stripped from file.
; 0x0008 Local symbols stripped from file.
; 0x0010 Agressively trim working set
; 0x0080 Bytes of machine word are reversed.
; 0x0100 32 bit word machine.
; 0x0200 Debugging info stripped from file in .DBG file
; 0x0400 If Image is on removable media, copy and run from the swap file.
; 0x0800 If Image is on Net, copy and run from the swap file.
; 0x1000 System File.
; 0x2000 File is a DLL.
; 0x4000 File should only be run on a UP machine
; 0x8000 Bytes of machine word are reversed.

@a1 equ $ ; _IMAGE_OPTIONAL_HEADER
dc.w $010b ; Magic
dc.b 5 ; MajorLinkerVersion
dc.b 12 ; MinorLinkerVersion
dc.l SizeOfCode ; SizeOfCode
dc.l SizeOfInitializedData ; SizeOfInitializedData
dc.l SizeOfUninitializedData ; SizeOfUninitializedData
dc.l winmain-ImageBase ; AddressOfEntryPoint
dc.l BaseOfCode ; BaseOfCode
dc.l BaseOfData ; BaseOfData
dc.l ImageBase ; ImageBase
dc.l SectionAlignment ; SectionAlignment
dc.l FileAlignment ; FileAlignment
dc.w 4 ; MajorOperatingSystemVersion
dc.w 0 ; MinorOperatingSystemVersion
dc.w 0 ; MajorImageVersion
dc.w 0 ; MinorImageVersion
dc.w 4 ; MajorSubsystemVersion
dc.w 0 ; MinorSubsystemVersion
dc.l 0 ; Win32VersionValue
dc.l SizeOfImage ; SizeOfImage
dc.l SizeOfHeaders ; SizeOfHeaders
dc.l 0 ; CheckSum
dc.w 3 ; Subsystem
; 0: Unknown subsystem.
; 1: Image doesn't require a subsystem.
; 2: Image runs in the Windows GUI subsystem.
; 3: Image runs in the Windows character subsystem.
; 5: image runs in the OS/2 character subsystem.
; 7: image run in the Posix character subsystem.
; 8: image run in the 8 subsystem.
dc.w $0000 ; DllCharacteristics
dc.l $00100000 ; SizeOfStackReserve
dc.l $00001000 ; SizeOfStackCommit
dc.l $00100000 ; SizeOfHeapReserve
dc.l $00001000 ; SizeOfHeapCommit
dc.l $00000000 ; LoaderFlags
dc.l NumberOfRvaAndSize ; NumberOfRvaAndSize (entries
; in the data dir)

; ..............................................
; : Start of Image Data Directory :
; ..............................................

; virtual address, size
@b equ $
dc.l 0,0 ; Export Directory
dc.l imp_start,imp_size ; Import Directory
dc.l 0,0 ; Resource Directory
dc.l 0,0 ; Exception Directory
dc.l 0,0 ; Security Directory
dc.l 0,0 ; Base Relocation Table
dc.l 0,0 ; Debug Directory
dc.l 0,0 ; Description String
dc.l 0,0 ; Machine Value (MIPS GP)
dc.l 0,0 ; TLS Directory
dc.l 0,0 ; Load Configuration Directory
dc.l 0,0 ; Bound Import Directory in headers
dc.l iat_start,iat_size ; Import Address Table
dc.l 0,0 ; 14
dc.l 0,0 ; 15
dc.l 0,0 ; 16

NumberOfRvaAndSize equ ($-@b)/8
SizeOfOptionalHeader equ $-@a1

; ..............................................
; : End of Image Data Directory :
; ..............................................

; ..............................................
; : Start of Image Sections Header :
; ..............................................

@a2 equ $

dc.b '.text',0,0,0 ; name
dc.l VSizeOf_text ; virtual size
dc.l VBaseOf_text ; virtual address
dc.l FSizeOf_text ; size of raw data
dc.l FBaseOf_text ; pointer to raw data
dc.l 0 ; pointer to relocatins
dc.l 0 ; pointer to line numbers
dc.w 0 ; number of relocations
dc.w 0 ; number of line numbers
dc.l $0e0000020 ; characteristics


%IF UseIdatSection <> 0
dc.b '.idat',0,0,0 ; name
dc.l VSizeOf_idat ; virtual size
dc.l VBaseOf_idat ; virtual address
dc.l FSizeOf_idat ; size of raw data
dc.l FBaseOf_idat ; pointer to raw data
dc.l 0 ; pointer to relocatins
dc.l 0 ; pointer to line numbers
dc.w 0 ; number of relocations
dc.w 0 ; number of line numbers
dc.l $0e0000040 ; characteristics
%ENDIF

%IF UseUdatSection <> 0
dc.b '.udat',0,0,0 ; name
dc.l VSizeOf_udat ; virtual size
dc.l VBaseOf_udat ; virtual address
dc.l FSizeOf_udat ; size of raw data
dc.l FBaseOf_udat ; pointer to raw data
dc.l 0 ; pointer to relocatins
dc.l 0 ; pointer to line numbers
dc.w 0 ; number of relocations
dc.w 0 ; number of line numbers
dc.l $0e0000080 ; characteristics
%ENDIF

NumberOfSections equ ($-@a2)/40

; ..............................................
; : End of Image Sections Header :
; ..............................................

; characteristics
; 0x00000020 // Section contains code.
; 0x00000040 // Section contains initialized data.
; 0x00000080 // Section contains uninitialized data.
; 0x00000200 // Section contains comments or some other type of information.
; 0x00000800 // Section contents will not become part of image.
; 0x00001000 // Section contents comdat.
; 0x01000000 // Section contains extended relocations.
; 0x02000000 // Section can be discarded.
; 0x04000000 // Section is not cachable.
; 0x08000000 // Section is not pageable.
; 0x10000000 // Section is shareable.
; 0x20000000 // Section is executable.
; 0x40000000 // Section is readable.
; 0x80000000 // Section is writeable.

; +--------------------------------------------+
; | End of Windows Header |
; +--------------------------------------------+


@@2 equ @@1 + ($-$$) ; current file position
times ((@@2+FileAlignment-1)/FileAlignment*FileAlignment)-@@2 db 0
@@3 equ @@1 + ($-$$) ; current file position

SizeOfHeaders equ @@3

;#==================================================================#
;# End of Headers #
;#==================================================================#

;#==================================================================#
;# Start of Sections #
;#==================================================================#

; +--------------------------------------------+
; | Start of .text Section |
; +--------------------------------------------+

FBaseOf_text equ @@3
VBaseOf_text equ ($-ImageBase1+SectionAlignment-1)/SectionAlignment*SectionAlignment

BaseOfCode equ VBaseOf_text
section .text2 vstart=ImageBase+VBaseOf_text
ImageBase2 equ $-VBaseOf_text
; ImageBase2 has same value as ImageBase but is nonrelatve



; ..............................................
; : Start of Thunk Table :
; ..............................................


iat_start equ $-ImageBase

KERNEL32_thunk:
ExitProcess: dc.l KERNEL32_ExitProcess -ImageBase
GetStdHandle: dc.l KERNEL32_GetStdHandle -ImageBase
ReadFile: dc.l KERNEL32_ReadFile -ImageBase
WriteFile: dc.l KERNEL32_WriteFile -ImageBase
dc.l 0


iat_size equ $-ImageBase-iat_start

; ..............................................
; : End of Thunk Table :
; ..............................................


; ..............................................
; : Start of Import Directory :
; ..............................................


imp_start equ $-ImageBase

imp:

dc.l KERNEL32_import -ImageBase
dc.l 0
dc.l 0
dc.l KERNEL32_name -ImageBase
dc.l KERNEL32_thunk -ImageBase

dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0

imp_size equ $-imp

; ..............................................
; : End of Import Directory :
; ..............................................



KERNEL32_name:
dc.b 'KERNEL32.dll',0
align 2 , db 0

KERNEL32_import:
dc.l KERNEL32_ExitProcess -ImageBase
dc.l KERNEL32_GetStdHandle -ImageBase
dc.l KERNEL32_ReadFile -ImageBase
dc.l KERNEL32_WriteFile -ImageBase
dc.l 0
align 2, db 0

KERNEL32_ExitProcess:
dc.w 0
dc.b 'ExitProcess',0
align 2, db 0
KERNEL32_GetStdHandle:
dc.w 0
dc.b 'GetStdHandle',0
align 2, db 0
KERNEL32_ReadFile:
dc.w 0
dc.b 'ReadFile',0
align 2, db 0
KERNEL32_WriteFile:
dc.w 0
dc.b 'WriteFile',0
align 2, db 0





; ..............................................
; : Start of Code :
; ..............................................


seg 32


winmain:

20: bsr.l getc
cmpq.l -1,r0
beq.b exit
cmp.b 'a',r0
blo.b .10
cmp.b 'z',r0
bhi.b .10
add.b 'A'-'a',r0
10: bsr.l putc
br.b .20

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; OS specific functions: getc, putc, exit ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

exit: move.l r0,-[sp]
jsr.l [ExitProcess] ; exit program

putc: movem.l r0-r7,-[sp]
eor.l r0,r0
add.l [.handle],r0
bne.b .10
moveq.l -11,-[sp]
jsr.l [GetStdHandle]
move.l r0,[.handle]
10: moveq.l 0,-[sp]
lea.l [r7+4*4],r1
move.l r1,-[sp]
moveq.l 1,-[sp]
addq.l 4*4,r1
move.l r1,-[sp]
move.l r0,-[sp]
jsr.l [WriteFile]
or.l r0,r0
bne.b .20
30: moveq.l 0,-[sp]
jsr.l [ExitProcess]
20: cmpq.l 1,[r7+3*4]
bne.b .30
movem.l [sp]+,r0-r7
rts.l

align 4, db 0
handle:dc.l 0


getc: eor.l r0,r0
movem.l r0-r7,-[sp]
add.l [.handle],r0
bne.b .10
moveq.l -10,-[sp]
jsr.l [GetStdHandle]
move.l r0,[.handle]
10: moveq.l 0,-[sp]
lea.l [r7+4*4],r1
move.l r1,-[sp]
moveq.l 1,-[sp]
addq.l 4*4,r1
move.l r1,-[sp]
move.l r0,-[sp]
jsr.l [ReadFile]
or.l r0,r0
bne.b .20
moveq.l 0,-[sp]
jsr.l [ExitProcess]
20: cmpq.l 1,[r7+3*4]
beq.b .30
move.l -1,[r7+7*4]
30: movem.l [sp]+,r0-r7
rts.l

align 4, db 0
handle:dc.l 0



; ..............................................
; : End of Code :
; ..............................................

VSizeOf_text equ $-ImageBase-VBaseOf_text

@a3 equ $-ImageBase2

@@4 equ @@3 + ($-$$) ; current file position
times ((@@4+FileAlignment-1)/FileAlignment*FileAlignment)-@@4 db 0
@@5 equ @@3 + ($-$$) ; current file position

FSizeOf_text equ @@5-FBaseOf_text
SizeOfCode equ FSizeOf_text


; +--------------------------------------------+
; | End of .text Section |
; +--------------------------------------------+


; +--------------------------------------------+
; | Start of .idat Section |
; +--------------------------------------------+


FBaseOf_idat equ @@5
VBaseOf_idat equ (@a3+SectionAlignment-1)/SectionAlignment*SectionAlignment
BaseOfData equ VBaseOf_idat
section .text3 vstart=ImageBase+VBaseOf_idat
ImageBase3 equ $-VBaseOf_idat
; ImageBase3 has same value as ImageBase but is nonrelatve

; Insert initialized variables here (and set UseIdatSection=1
; at the top of this file). Because the code section is set
; r/w-able, you can put initialized variables also into the
; code section.

; var1: dc.l 0
; var2: dc.l $12345678

VSizeOf_idat equ $-ImageBase-VBaseOf_idat
@a4 equ $ - ImageBase3

@@6 equ @@5 + ($-$$) ; current file position
times ((@@6+FileAlignment-1)/FileAlignment*FileAlignment)-@@6 db 0
@@7 equ @@5 + ($-$$) ; current file position


FSizeOf_idat equ @@7-FBaseOf_idat

; +--------------------------------------------+
; | End of .idat Section |
; +--------------------------------------------+

SizeOfInitializedData equ FSizeOf_idat


; +--------------------------------------------+
; | Start of .udat Section |
; +--------------------------------------------+


FBaseOf_udat equ @@7
VBaseOf_udat equ (@a4+SectionAlignment-1)/SectionAlignment*SectionAlignment
section .bss vstart=ImageBase+VBaseOf_udat
ImageBase4 equ $-VBaseOf_udat
; ImageBase4 has same value as ImageBase but is nonrelatve

; Insert uninitialized variables here (and set UseUdatSection=1
; at the top of this file). Because the code section is set
; r/w-able, you can put uninitialized variables also at the END
; of the code section (but NASM doesn't support this).

; buf1: blk.l 10
; buf2: blk.l 200



VSizeOf_udat equ $-ImageBase-VBaseOf_udat
FSizeOf_udat equ 0


; +--------------------------------------------+
; | End of .udat Section |
; +--------------------------------------------+

SizeOfUninitializedData equ VSizeOf_udat
SizeOfImage equ ($-ImageBase4+SectionAlignment-1)/SectionAlignment*SectionAlignment


;#==================================================================#
;# End of Sections #
;#==================================================================#





Herbert Kleebauer

unread,
Sep 5, 2022, 6:05:29 PMSep 5
to
On 06.09.2022 00:03, Herbert Kleebauer wrote:
> is just the data of the exe file format). Because NASM uses an awful
> syntax you have to include "mac.inc" to be able to use a readable
> instruction format (I post mac.inc in a follow up):
>


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; mac.inc ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

%macro seg 1
%define __seg__ %1
[BITS %1]
%endmacro

seg 16

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


%macro dc.b 1+
db %1
%endmacro

%macro dc.w 1+
dw %1
%endmacro

%macro dc.l 1+
dd %1
%endmacro

%macro blk.b 1
resb %1
%endmacro

%macro blk.b 2
times %1 db %2
%endmacro

%macro blk.w 1
resw %1
%endmacro

%macro blk.l 1
resd %1
%endmacro

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

%macro move.l 2
reg32
%ifidn %2,-[sp]
push dword %1
%elifidn %1,[sp]+
pop dword %2
%elifidn %2,[r6]+-{s1}
%ifidn %1,r0
stosd
%endif
%elifidn %2,[r6.w]+-{s1}
%ifidn %1,r0
stosd
%endif
%elifidn %1,[r5]+-
%ifidn %2,r0
lodsd
%endif
%else
mov dword %2,%1
%endif
reg0
%endmacro

%macro move.w 2
reg16
%ifidn %2,-[sp]
push word %1
%elifidn %1,[sp]+
pop word %2
%elifidn %1,[r5]+-
%ifidn %2,r0
lodsw
%endif
%elifidn %2,[r6.w]+-{s1}
%ifidn %1,r0
stosw
%endif
%else
mov word %2,%1
%endif
reg0
%endmacro

%macro move.b 2
%ifidn %1,[r5]+-
%ifidn %2,[r6]+-{s1}
movsb
%endif
%elifidn %2,[r6.w]+-{s1}
%ifidn %1,r0
stosb
%endif
%else
reg8
mov byte %2,%1
reg0
%endif
%endmacro


%macro moveq.l 2
reg32
%ifidn %2,-[sp]
push dword %1
%endif
reg0
%endmacro

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

%macro movu.bw 2
reg16
movzx %2,byte %1
reg0
%endmacro

%macro movu.bl 2
reg32
movzx %2,byte %1
reg0
%endmacro

%macro movu.wl 2
reg32
movzx %2,word %1
reg0
%endmacro

%macro movem.l 2
%if __seg__ = 16
db $66
%endif
%ifidn %2,-[sp]
pusha
%else
popa
nop
%endif
%endmacro

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

%macro exg.l 2
reg32
xchg %2,%1
reg0
%endmacro

%macro exg.w 2
reg16
xchg %2,%1
reg0
%endmacro

%macro exg.b 2
reg8
xchg %1,%2
reg0
%endmacro

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

%macro add.l 2
reg32
add %2,%1
reg0
%endmacro

%macro add.w 2
reg16
add word %2,%1
reg0
%endmacro

%macro add.b 2
reg8
add %2,%1
reg0
%endmacro

%macro addq.l 2
reg32
add %2,%1
reg0
%endmacro

%macro addq.w 2
reg16
add word %2,%1
reg0
%endmacro

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

%macro addc.l 2
reg32
adc %2,%1
reg0
%endmacro

%macro addc.w 2
reg16
adc word %2,%1
reg0
%endmacro

%macro addc.b 2
reg8
adc %2,%1
reg0
%endmacro


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

%macro sub.l 2
reg32
sub %2,%1
reg0
%endmacro

%macro sub.w 2
reg16
sub word %2,%1
reg0
%endmacro

%macro sub.b 2
reg8
sub %2,%1
reg0
%endmacro

%macro subq.l 2
reg32
sub %2,%1
reg0
%endmacro

%macro subq.w 2
reg16
sub word %2,%1
reg0
%endmacro

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

%macro subc.l 2
reg32
sbb %2,%1
reg0
%endmacro

%macro subc.w 2
reg16
sbb word %2,%1
reg0
%endmacro

%macro subc.b 2
reg8
sbb %2,%1
reg0
%endmacro


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

%macro cmp.l 2
reg32
cmp %2,long %1
reg0
%endmacro

%macro cmp.w 2
reg16
cmp %2,word %1
reg0
%endmacro

%macro cmp.b 2

%ifidn %1,[r6]+-{s1}
%ifidn %2,[r5]+-
%if __seg__ = 16
db $66
%endif
cmpsb
%endif

%elifidn %1,[r6.l]+-{s1}
%ifidn %2,[r5.l]+-
%if __seg__ = 16
db $66
%endif
cmpsb
%endif

%elifidn %1,[r6.w]+-{s1}
%ifidn %2,[r5.w]+-
%if __seg__ = 32
db $66
%endif
cmpsb
%endif

%else
reg8
cmp %2,byte %1
reg0
%endif
%endmacro

%macro cmpq.l 2
reg32
cmp %2,long %1
reg0
%endmacro

%macro cmpq.w 2
reg16
cmp %2,word %1
reg0
%endmacro


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

%macro and.l 2
reg32
and %2,%1
reg0
%endmacro

%macro and.w 2
reg16
and %2,%1
reg0
%endmacro

%macro and.b 2
reg8
and %2,%1
reg0
%endmacro

%macro andq.l 2
reg32
and %2,%1
reg0
%endmacro

%macro andq.w 2
reg16
and %2,%1
reg0
%endmacro

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

%macro or.l 2
reg32
or %2,%1
reg0
%endmacro

%macro or.w 2
reg16
or %2,%1
reg0
%endmacro

%macro or.b 2
reg8
or %2,%1
reg0
%endmacro

%macro orq.l 2
reg32
or %2,%1
reg0
%endmacro

%macro orq.w 2
reg16
or %2,%1
reg0
%endmacro


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

%macro eor.l 2
reg32
xor %2,%1
reg0
%endmacro

%macro eor.w 2
reg16
xor %2,%1
reg0
%endmacro

%macro eor.b 2
reg8
xor %2,%1
reg0
%endmacro

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

%macro tst.l 2
reg32
test dword %2,%1
reg0
%endmacro

%macro tst.w 2
reg16
test word %2,%1
reg0
%endmacro

%macro tst.b 2
reg8
test byte %2,%1
reg0
%endmacro

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

%macro lsl.l 2
reg32
shl %2,%1
reg0
%endmacro

%macro lsl.w 2
reg16
shl %2,%1
reg0
%endmacro

%macro lsl.b 2
reg8
shl %2,%1
reg0
%endmacro

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

%macro lsr.l 2
reg32
shr %2,%1
reg0
%endmacro

%macro lsr.w 2
reg16
shr %2,%1
reg0
%endmacro

%macro lsr.b 2
reg8
shr %2,%1
reg0
%endmacro

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

%macro asr.l 2
reg32
sar %2,%1
reg0
%endmacro

%macro asr.w 2
reg16
sar %2,%1
reg0
%endmacro

%macro asr.b 2
reg8
sar %2,%1
reg0
%endmacro

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

%macro rol.l 2
reg32
rol %2,%1
reg0
%endmacro

%macro rol.w 2
reg16
rol %2,%1
reg0
%endmacro

%macro rol.b 2
reg8
rol %2,%1
reg0
%endmacro

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

%macro ror.l 2
reg32
ror %2,%1
reg0
%endmacro

%macro ror.w 2
reg16
ror %2,%1
reg0
%endmacro

%macro ror.b 2
reg8
ror %2,%1
reg0
%endmacro

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


%macro btst.l 2
reg32
bt dword %2, %1
reg0
%endmacro

%macro bchg.l 2
reg32
btc dword %2, %1
reg0
%endmacro

%macro bset.w 2
%ifidn %1,0
%ifidn %2,sr
stc
%endif
%endif
%endmacro

%macro bclr.w 2
%ifidn %2,sr
%ifidn %1,0
clc
%endif
%ifidn %1,10
cld
%endif
%endif
%endmacro


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

%macro neg.l 1
reg32
neg %1
reg0
%endmacro

%macro neg.w 1
reg16
neg %1
reg0
%endmacro

%macro neg.b 1
reg8
neg %1
reg0
%endmacro

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

%macro not.l 1
reg32
not %1
reg0
%endmacro

%macro not.w 1
reg16
not %1
reg0
%endmacro

%macro not.b 1
reg8
not %1
reg0
%endmacro

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

%macro inc.l 1
reg32
inc dword %1
reg0
%endmacro

%macro inc.w 1
reg16
inc %1
reg0
%endmacro

%macro inc.b 1
reg8
inc %1
reg0
%endmacro

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

%macro dec.l 1
reg32
dec dword %1
reg0
%endmacro

%macro dec.w 1
reg16
dec %1
reg0
%endmacro

%macro dec.b 1
reg8
dec %1
reg0
%endmacro

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

%macro muls.l 3
reg32
%ifidn %3,r1|r0
imul dword %1
%else
imul %2,%1
%endif
reg0
%endmacro

%macro mulu.l 3
reg32
%ifidn %3,r1|r0
mul dword %1
%else
mul %2,%1
%endif
reg0
%endmacro

%macro mulu.b 3
reg8
%ifidn %3,m0|r0
mul %1
%else
mul %2,%1
%endif
reg0
%endmacro

%macro divs.l 2
reg32
idiv %1
reg0
%endmacro

%macro divu.l 2
reg32
div dword %1
reg0
%endmacro

%macro divu.w 2
reg16
div word %1
reg0
%endmacro

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

%macro lea.l 2
reg32
lea %2,%1
reg0
%endmacro

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

%macro adj_dec_sub 1
das
%endmacro

%macro in.b 2
reg8
in %2,%1
reg0
%endmacro

%macro out.b 2
reg8
out %2,%1
reg0
%endmacro

%macro ext.l 2
%ifidn %2,r1|r0
%ifidn %1,r0
cdq
%endif
%endif
%endmacro

%macro ext.w 2
%ifidn %2,r1|r0
%ifidn %1,r0
cwd
%endif
%endif
%endmacro

%macro ext.l 1
%ifidn %1,r0
cwde
%endif
%endmacro

%macro ext.w 1
%ifidn %1,r0
cbw
%endif
%endmacro

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

%macro trap 1
int %1
%endmacro

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

%macro br.b 1
jmp %1
%endmacro
%macro br.l 1
jmp %1
%endmacro
%macro jmp.l 1
jmp %1
%endmacro

%macro bmi.b 1
js %1
%endmacro
%macro bmi.l 1
js %1
%endmacro

%macro bpl.b 1
jns %1
%endmacro
%macro bpl.l 1
jns %1
%endmacro

%macro bcc.b 1
jnc %1
%endmacro
%macro bcc.l 1
jnc %1
%endmacro

%macro bhs.b 1
jnc %1
%endmacro
%macro bhs.l 1
jnc %1
%endmacro

%macro bls.b 1
jbe %1
%endmacro
%macro bls.l 1
jbe %1
%endmacro

%macro bcs.b 1
jc %1
%endmacro
%macro bcs.l 1
jc %1
%endmacro

%macro blo.b 1
jc %1
%endmacro
%macro blo.l 1
jc %1
%endmacro

%macro bhi.b 1
ja %1
%endmacro
%macro bhi.l 1
ja %1
%endmacro

%macro beq.b 1
jz %1
%endmacro
%macro beq.l 1
jz %1
%endmacro

%macro bne.b 1
jne %1
%endmacro
%macro bne.l 1
jne %1
%endmacro

%macro bgt.b 1
jg %1
%endmacro
%macro bgt.l 1
jg %1
%endmacro

%macro bge.b 1
jge %1
%endmacro
%macro bge.l 1
jge %1
%endmacro

%macro ble.b 1
jle %1
%endmacro
%macro ble.l 1
jle %1
%endmacro

%macro dbf.l 2
loop %2
%endmacro

%macro dbf.w 2
loop %2
%endmacro

%macro jmp.ww 1
jmp far %1
%endmacro


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
%macro jsr.l 1
call dword %1
%endmacro

%macro bsr.l 1
call dword %1
%endmacro

%macro bsr.w 1
call word %1
%endmacro

%macro rts.l 0
%if __seg__ = 16
db $66
%endif
ret
%endmacro

%macro rts.l 1
%if __seg__ = 16
db $66
%endif
ret %1
%endmacro

%macro rts.w 0
%if __seg__ = 32
db $66
%endif
ret
%endmacro

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

%macro rep_r2 1+
rep
%1
%endmacro

%macro repeq_r2 1+
repe
%1
%endmacro

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

%define r0.b al
%define r1.b dl
%define r2.b cl
%define r3.b bl
%define m0 ah
%define m1 dh
%define m2 ch
%define m3 bh

%define r0.w ax
%define r1.w dx
%define r2.w cx
%define r3.w bx
%define r4.w bp
%define r5.w si
%define r6.w di
%define r7.w sp

%define r0.l eax
%define r1.l edx
%define r2.l ecx
%define r3.l ebx
%define r4.l ebp
%define r5.l esi
%define r6.l edi
%define r7.l esp

%define s0 ds
%define s1 es
%define s2 fs
%define s3 gs
%define s6 cs
%define s7 ss


%macro reg0 0
%undef r0
%undef r1
%undef r2
%undef r3
%undef r4
%undef r5
%undef r6
%undef r7
%endmacro

%macro reg8 0
%define r0 al
%define r1 dl
%define r2 cl
%define r3 bl
%endmacro

%macro reg16 0
%define r0 ax
%define r1 dx
%define r2 cx
%define r3 bx
%define r4 bp
%define r5 si
%define r6 di
%define r7 sp
%endmacro

%macro reg32 0
%define r0 eax
%define r1 edx
%define r2 ecx
%define r3 ebx
%define r4 ebp
%define r5 esi
%define r6 edi
%define r7 esp
%endmacro


Paolo Amoroso

unread,
Sep 6, 2022, 3:00:15 AMSep 6
to
On Tuesday, September 6, 2022 at 12:03:36 AM UTC+2, Herbert Kleebauer wrote:
> But it doesn't make much sense to write .com programs which can't
> be run natively on a current computer system. Windows programs also

I actually don't have Windows devices and don't plan to get any. On the desktop I use exclusively chromeOS, here are some notes on my emulation setup based on DOSBox-X as well as my motivations and goals: https://journal.paoloamoroso.com/setting-up-an-ms-dos-emulation-and-development-environment

So MS-DOS and .COM are more than enough for my personal experimentation and fun.

Kerr-Mudd, John

unread,
Sep 6, 2022, 5:09:12 AMSep 6
to
On Tue, 6 Sep 2022 00:05:27 +0200
Herbert Kleebauer <kl...@unibwm.de> wrote:

> On 06.09.2022 00:03, Herbert Kleebauer wrote:
> > is just the data of the exe file format). Because NASM uses an awful
> > syntax you have to include "mac.inc" to be able to use a readable
> > instruction format (I post mac.inc in a follow up):
> >
[lines snipped]

a NASM DOS program to do what you posted would be about (guesses) 50 bytes.
OK I'll post it here. Remind me in a week if I've not done so earlier.

Herbert Kleebauer

unread,
Sep 7, 2022, 4:11:12 AMSep 7
to
On 06.09.2022 11:09, Kerr-Mudd, John wrote:
> On Tue, 6 Sep 2022 00:05:27 +0200

>> > is just the data of the exe file format). Because NASM uses an awful

> a NASM DOS program to do what you posted would be about (guesses) 50 bytes.
> OK I'll post it here. Remind me in a week if I've not done so earlier.

The code and therefore the size is the same. The CPU doesn't know which OS
is running, it just executes your instructions step by step. The binary
of a Windows executable is much larger than a DOS .com program not because
of a bigger code but because of the file structure and the more complicated
interface to the OS.

Time goes by so slowly, but not so slowly that it still makes sense
to write DOS .com programs. If somebody wants to write assembly code
which can't be executed on current computer systems I would suggest
PDP11 or 68000. In opposite to 16 bit 8086 they have a well designed
processor architecture and there are also emulators available as
for DOS/x86.

ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘
ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘
ā–‘ā–‘ā–‘ā–‘ā–ˆā–€ā–€ā–€ā–€ā–€ā–ˆā–‘ā–‘ā–„ā–€ā–‘ā–‘ā–„ā–ˆā–„ā–„ā–‘ā–ˆā–€ā–€ā–€ā–€ā–€ā–ˆā–‘ā–‘ā–‘ā–‘
ā–‘ā–‘ā–‘ā–‘ā–ˆā–‘ā–ˆā–ˆā–ˆā–‘ā–ˆā–‘ā–€ā–„ā–‘ā–€ā–‘ā–„ā–„ā–€ā–‘ā–‘ā–ˆā–‘ā–ˆā–ˆā–ˆā–‘ā–ˆā–‘ā–‘ā–‘ā–‘
ā–‘ā–‘ā–‘ā–‘ā–ˆā–‘ā–€ā–€ā–€ā–‘ā–ˆā–‘ā–‘ā–€ā–„ā–„ā–ˆā–„ā–ˆā–ˆā–ˆā–‘ā–ˆā–‘ā–€ā–€ā–€ā–‘ā–ˆā–‘ā–‘ā–‘ā–‘
ā–‘ā–‘ā–‘ā–‘ā–€ā–€ā–€ā–€ā–€ā–€ā–€ā–‘ā–ˆā–‘ā–€ā–„ā–ˆā–„ā–€ā–„ā–ˆā–‘ā–€ā–€ā–€ā–€ā–€ā–€ā–€ā–‘ā–‘ā–‘ā–‘
ā–‘ā–‘ā–‘ā–‘ā–€ā–€ā–€ā–„ā–€ā–€ā–€ā–ˆā–€ā–„ā–‘ā–„ā–„ā–ˆā–„ā–‘ā–ˆā–ˆā–ˆā–‘ā–‘ā–‘ā–€ā–‘ā–„ā–‘ā–‘ā–‘ā–‘
ā–‘ā–‘ā–‘ā–‘ā–€ā–‘ā–€ā–ˆā–„ā–ˆā–€ā–€ā–ˆā–„ā–ˆā–„ā–ˆā–ˆā–„ā–‘ā–€ā–€ā–„ā–ˆā–ˆā–‘ā–€ā–ˆā–€ā–‘ā–‘ā–‘ā–‘
ā–‘ā–‘ā–‘ā–‘ā–€ā–€ā–ˆā–€ā–„ā–€ā–€ā–ˆā–€ā–„ā–ˆā–‘ā–„ā–ˆā–‘ā–‘ā–ˆā–€ā–ˆā–€ā–‘ā–ˆā–‘ā–€ā–ˆā–‘ā–‘ā–‘ā–‘
ā–‘ā–‘ā–‘ā–‘ā–€ā–„ā–„ā–„ā–„ā–€ā–€ā–€ā–€ā–„ā–„ā–‘ā–€ā–ˆā–€ā–‘ā–ˆā–€ā–€ā–€ā–„ā–‘ā–€ā–ˆā–€ā–‘ā–‘ā–‘ā–‘
ā–‘ā–‘ā–‘ā–‘ā–€ā–‘ā–€ā–‘ā–‘ā–‘ā–€ā–€ā–„ā–„ā–€ā–„ā–„ā–€ā–ˆā–ˆā–ˆā–€ā–€ā–€ā–ˆā–ˆā–‘ā–„ā–„ā–‘ā–‘ā–‘ā–‘
ā–‘ā–‘ā–‘ā–‘ā–ˆā–€ā–€ā–€ā–€ā–€ā–ˆā–‘ā–ˆā–ˆā–ˆā–‘ā–ˆā–„ā–ˆā–ˆā–ˆā–‘ā–€ā–‘ā–ˆā–ˆā–‘ā–ˆā–€ā–‘ā–‘ā–‘ā–‘
ā–‘ā–‘ā–‘ā–‘ā–ˆā–‘ā–ˆā–ˆā–ˆā–‘ā–ˆā–‘ā–€ā–‘ā–‘ā–„ā–„ā–€ā–‘ā–‘ā–€ā–€ā–€ā–ˆā–ˆā–ˆā–„ā–€ā–‘ā–‘ā–‘ā–‘ā–‘
ā–‘ā–‘ā–‘ā–‘ā–ˆā–‘ā–€ā–€ā–€ā–‘ā–ˆā–‘ā–ˆā–‘ā–ˆā–‘ā–„ā–ˆā–€ā–€ā–ˆā–€ā–‘ā–‘ā–ˆā–„ā–‘ā–„ā–€ā–‘ā–‘ā–‘ā–‘
ā–‘ā–‘ā–‘ā–‘ā–€ā–€ā–€ā–€ā–€ā–€ā–€ā–‘ā–€ā–€ā–€ā–€ā–€ā–‘ā–‘ā–€ā–€ā–‘ā–€ā–€ā–‘ā–‘ā–‘ā–€ā–€ā–‘ā–‘ā–‘ā–‘
ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘
ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘ā–‘


Herbert Kleebauer

unread,
Sep 7, 2022, 4:32:37 AMSep 7
to
On 06.09.2022 09:00, Paolo Amoroso wrote:

> So MS-DOS and .COM are more than enough for my personal experimentation and fun.

But even then you should only use 32 bit instructions. This
allows you to run the code in DOS, Windows and Linux without
modifications. Only the part of the OS interface has to be
different. But for a start it is enough to use only three
OS functions getc(), putc() and exit().



Reply all
Reply to author
Forward
0 new messages