Programming in 80x86 assembly language
HTML Flowcharted sourcecode
Below is the source of a small program to produce a (hello Linux guys!)
I soaked the files with HTML codes so you can click your way through the execution of a program. Just use your
browser as if this were a website.
In good A86 style, this program starts just after the assembler directive
CODE segment.
This is an unconditional jump to the actual main routine of the program. Between the
JMP MAIN
and the actual
MAIN
routine are (to make life easier for A86; it's a single pass assembler) the subroutines that are called in
that order (approximately).
Give it a go and see if yoy can work your way to the end of the program. If you have questions or remarks
about this source, or about programming in assembly language in general, don't hesitate to send me an E-mail.
You can get a copy of the A86 assembler via the website of
the maker.
The coredump program under DOS: Mem2File
name mem2file
title Send an area of memory to a diskfile.
page 80, 120
; version 1.0 : Had to be compiled for each area/filename OK: 01-01-1991
; version 1.1 : Same as above, for A86 format OK: 01-01-1999
; version 1.2 : Make it commandline driven OK: 01-02-1999
; version 1.3 : Make it reliable OK: 02-02-1999
; version 1.4 : Provide linear addresses as well OK: something FOR YOU?
; ----------------------
stdout = 1
tab = 9
lf = 10
cr = 13
store MACRO
mov al, #1
stosb
#EM
clr MACRO
mov #1, 0
#EM
Dum1 STRUC
OffVal dw ?
SegVal dw ?
ENDS
; ----------------------
Here start the variables which need no initialisation.
DATA segment
ByteF = $
dummy db ? ; just to fool D86....
even
Start dw ?, ? ; segment:address to start
Stop dw ?, ? ; segment:address to stop
Block dw ? ; number of 16K chucks to save
Rest dw ? ; remaining part to save
ArgNum dw ? ; nr of bytes in this argument
OldClp dw ? ; current pointer into command line
Handle dw ?
Length dw ?, ?
FileName:
Argument db 80 dup (?) ; storage for next argument from command-line
Output db 16K dup (?) ; buffered output
Bytes = $ - ByteF
; ----------------------
Place for the variables that do need initialisation and messages
CODE segment
jmp main
HexTable db '0123456789ABCDEF', 0
db 'VeRsIoN=Mem2File 1.3', 0
db 'CoPyRiGhT=CopyLeft Jan Verhoeven, fruttenboel@verhoeven272.nl', 0
Mess001 db 'Mem2File collects a part of conventional memory and sends it to a file.', cr, lf, lf
db 'The syntax is:', cr, lf, lf
db tab, 'Mem2File segm1:offs1 [-] segm2:offs2 <path>file.ext.', cr, lf, lf
db 'Mem2File is GNU GPL style FREE software. ', cr, lf
db 'Please read the GNU GPL if you are in doubt.', cr, lf, lf
Mess002 db 'Mem2File was made by Jan Verhoeven, NL-5012 GH 272, The Netherlands', cr, lf
db 'E-mail address : fruttenboel@tomaatnet.nl', cr, lf, lf
Len001 = $ - Mess001
Len002 = $ - Mess002
Mess004 db 7, 'Error! All numbers are expected to be hexadecimal.', cr, lf
Len004 = $ - Mess004
;------------------------
InitMem: mov di, ByteF  ; Init memory with zero's.
mov cx, Bytes
mov al, 0
rep stosb
ret
;------------------------
L0: mov b [di], 0 ; terminate argument string
mov [OldClp], si ; done, => clean up.
clc ; indicate "No Error"
L3: pop di, si, ax ; restore registers, ...
ret ; ... and leave.
GetArg: push ax, si, di ; get next argument from command-line in ASCIIZ format
mov si, [OldClp] ; now, where did we leave last time?
cmp si, 0 ; Have we ever used this routine?
IF E mov si, 081 ; if not, prime SI, ...
mov di, offset Argument ; ... DI and ...
mov [ArgNum], 0 ; ... nr of chars in argument.
L1: lodsb ; get byte
cmp al, ' ' ; skip over spaces, ...
je L1
cmp al, tab ; ... and tabs.
je L1
cmp al, 1 ; ONLY if AL is 0, we get a carry
jc L3 ; if CARRY, we're done
L2: stosb ; else store char in Arguments array
inc [ArgNum] ; adjust counter
lodsb ; and get next char
cmp al, ' ' ; is it a delimiting space?
je L0
cmp al, tab ; or a tab?
je L0
cmp al, ':' ; or a colon?
je L0
cmp al, 0 ; or an end-of-line?
jne L2 ; if not, loop back,
mov si, 0FFFF ; else make SI ridiculously high, ...
stc ; ... set carry flag, ...
jmp L0 ; and get out.
;------------------------
L1: stc ; byte not in table!
pop dx
ret ; exit
L2: sub bx, dx ; calculate position in table
pop dx
clc
ret
TableFind:
push dx ; find AL in ASCIIZ table [BX] and report position
mov dx, bx ; keep value of SI
L0: cmp b [bx], 0 ; is it end of table?
je L1 ; if so, jump out
cmp al, [bx] ; compare byte with table
je L2 ; if same, jump out
inc bx ; else increment pointer
jmp L0 ; and loop back
;------------------------
MakeUpper:
cmp al, 'a'
jb ret
cmp al, 'z' ; if in range, ...
ja ret
and al, not bit 5 ; ... make uppercase
ret
;------------------------
BadNumber: ; hey typo, you made a dumbo!
mov dx, offset Mess004
mov cx, Len004
mov bx, StdOut
mov ah, 040
int 021
mov ax, 04C02 ; and exit with errorcode 2
int 021
;------------------------
SyntErr: mov dx, offset Mess001
mov cx, Len001
mov bx, StdOut
mov ah, 040 ; print out "help" screen and ...
int 021
mov ax, 04C01 ; ... exit with errorcode 1
int 021
;------------------------
L8: mov ax, dx ; ConvertHex has result in DX, that's why.
pop dx, bx
ret
Convert: push bx, dx
mov si, offset Argument
clr dx
L1: lodsb
cmp al, 0 ; end of string?
je L8
call MakeUpper ; if not, make uppercase
mov bx, offset HexTable
call TableFind ; and lookup in table
jc BadNumber
shl dx, 4 ; multiply DX by 16
or dl, bl ; bx = index into table
jmp L1 ; repeat until done
;------------------------
Credits: mov dx, offset Mess002
mov cx, Len002
mov bx, stdout
mov ah, 040
int 021
ret
;------------------------
main: call InitMem ; prime volatile data
mov al, [080]
cbw
mov si, 081 ; point to start of tail
add si, ax ; point to end of tail
mov [si], ah ; make commandtail ASCIIZ
call GetArg
jc SyntErr
call Convert
mov [Start.SegVal], ax
call GetArg
jc SyntErr
call Convert
mov [Start.OffVal], ax
L0: call GetArg
jc SyntErr
cmp b [Argument], '-'
je L0
call Convert
mov [Stop.SegVal], ax
call GetArg
jc SyntErr
call Convert
mov [Stop.OffVal], ax
call GetArg
IF C jmp SyntErr
mov si, offset Argument
add si, [ArgNum]
mov b [si], 0
mov dx, offset FileName ; same as Argument buffer....
mov cx, 0
mov ah, 03C
int 021 ; create the file
IF C jmp SyntErr
mov [Handle], ax
mov ax, [Stop.SegVal]
mov dx, 0 ; prime DX
mov cx, 4
L0: shl ax, 1
rcl dx, 1
loop L0 ; shift upper 4 bits of address into DX
add ax, [Stop.OffVal]
adc dx, 0 ; now, dx:ax = linear address to stop at
mov [Stop.SegVal], dx
mov [Stop.OffVal], ax ; store linear address STOP
mov ax, [Start.SegVal]
mov dx, 0 ; prime DX
mov cx, 4
L0: shl ax, 1
rcl dx, 1
loop L0 ; shift upper 4 bits of address into DX
add ax, [Start.OffVal]
adc dx, 0 ; now, dx:ax = linear address to start from
mov [Start.SegVal], dx
mov [Start.OffVal], ax ; store linear address START
cmp dx, [Stop.SegVal] ; start > stop?
ja >L1 ; fix it!
jb >L2
cmp ax, [Stop.OffVal] ; start > stop?
jbe >L2 ; if not, OK
L1: push [Stop.SegVal]
push [Stop.OffVal]
mov [Stop.SegVal], dx
mov [Stop.OffVal], ax
pop [Start.OffVal]
pop [Start.SegVal]
L2: mov dx, [Stop.SegVal]
mov ax, [Stop.OffVal]
add ax, 1
adc dx, 0 ; limits are INCLUSIVE
sub ax, [Start.OffVal]
sbb dx, [Start.SegVal] ; dx:ax = bytes to move
shl ax, 1
rcl dx, 1
shl ax, 1
rcl dx, 1 ; dx = nr of 16 Kb blocks to move
mov [Blocks], dx ; store it
shr ax, 2 ; ax = remainder to move
mov [Rest], ax ; save it
mov ax, [Start.SegVal] ; end of linear addressing, we're going to DOS!
mov cl, 12
shl ax, cl
mov [Start.SegVal], ax
mov es, ds ; use es to refer to data
mov bx, [Handle]
lds dx, d [Start]
es cmp [Blocks], 0 ; if less than 16 Kb, skip this one.
je >S0
mov cx, 16K
L0: mov ah, 040
int 021
mov ax, ds ; store ds into ax
add dx, 04000 ; next buffer to load data from
IF C add ax, 01000 ; if carry, inc ds
mov ds, ax ; ds:dx now ready for next bufferfull of data
es dec [Blocks]
jnz L0
S0: es cmp [Rest], 0
je >L1
mov ah, 040
es mov cx, [Rest]
int 021
L1: mov ds, es
mov bx, [Handle]
mov ah, 03E
int 021 ; close file
call Credits ; show my ego
mov ax, 04C00
int 021 ; exit to DOS
About the source.
If you tinker out the HTML tags, you can use A86 to assemble this source to create "MEM2FILE.COM" so you can try it out. See how far you can come. If tinkering is too much effort, you can also download the original source here.
Page created in 1998,
Page equipped with FroogleBuster technology