这个SideKick是个好东东。 #%5>}$
(R,eWWF8~
下面的程序不是我写的。 z(xvt>
"~ /3
用汇编编写DOS下的内存驻留程序(1) Z6=!}a%
$#!~K2$
^V:YNUqp#
iw{n|&Y#`
+38t82%YWo
La!PGZ{
{MS&t09Wh
绪言 s-*XAnot
5^xt/vYa)
k}/:
xN"
0.1 内存驻留与中断
Wwz
>tE
8|l
Yf%n>j
kU /?#s
内存驻留程序英文叫Terminate and Stay Resident Program,缩写为TSR.这些程序加载进内存,执行完后,就驻留在内存里,当满足条件时,调到前台来执行。 N P"z
\@xnC$dd/
buoz L
a
内存驻留程序的常用形式有: (7IF5g\
>iCMjT]4
mH?hzxa+
>诸如Borland 的SideKick弹出式实用程序 %bsdC0xM
zR4huo
@ZVc!5J_,
>日历系统
rk~/^(!
~ 0[K
%]]
Xk3Ufz]QN
>网络服务器 0\mzGfd
KQqlM
@6E[K'5c1
>通讯程序 \bg^E>-
[H&m@*UO
m} V,+E
>本地的DOS扩展(如CCDOS,UCDOS等中文系统都属于这个范畴) Hq~ 2,#Ue
B}Qo8i7
z
U+ 8[Ia(t
>一些可恶的人利用TSR技术制作很多可恶的病毒程序,几乎所有的病毒程序都是TSR程序. >
+SEze
g/E;OcFaO
S$#Awen"@
就象多任务系统调度一个进程有一个调度程序一样,在PC中从前台程序进入到一个TSR,也要有一个调度者,只是PC操作系统的调度不称为调度程序,而只称为触发机制.触发机制调度TSR执行在PC机上党称为激活一个TSR.触发机制主要有以下几种: oeIS&O.K
*n47.(a2i
H\S,^)drJ?
>硬件中断:党用的是键盘中断INT 9H,时钟中断INT 8H,通讯中断INT 14H,磁盘中断INT 13H等等. YcI]_[
'fB `e]_
ldxUq,p
>软件中断:党用的是键盘中断INT 16H,时钟中断INT 1CH,DOS中断INT 21H,等等. $$4% .J26Z
1
v Thb
b9U2afd
>以上各种的结合. ~7m+cWC-+
oH;Y} h
c*h5lM'n6
从以上的触发机制可以看出,TSR和PC机的中断系统有着密切的关系.每种激活方式实际上都是与中断有关的.常用特殊的击键序列的识别码是通过截获INT 9H和INT 16H来实现.实际上不管TSR程序的哪一个环节,都与中断有着密切的关系.因此在具体进行TSR和程序设计之前,先介绍PC中断系统.在此只作简单说明. $qvNv[
H0Tt(:.&
_w26iCnB{
在PC机内存的最低端(0000H开始)的1K字节中,存放着256个指针即常说的中为向量或中断矢量(Interrupt vertor),每个中断向量都指向一个子程序,该程序称为中断处理程序(Interrup handler).一个中断向量由四个字节组成,有一个字是中断处理程序的偏移量值,后一个字是中断处理程序的段值.256中断向量一起称为中断向量表.
R[Rs2eS_
)*uI/E
("aYjKk
手式计算中断向量的首址,可通过以下的公式来求得: qGw6Wp~
1{wy%|H\
=:b/z1-v
X号中断向量的首址=0000H:X*4 ~UnfS};U
kSDV#8uZ
3lJK[V{'#'
当产生一个中断时,处理器都按顺序执行以下步骤: 8_uDxd
q<1@ut
6QV/8IX
>在堆栈上压入处理器的标志(相当于指令PUSHF). H$;\TG@,
D,7! /u'
/oI''O%M
>在堆栈上压入当前CS和IP值(相当于指令PUSH CS和PUSH IP). ]
=D+a
&
R'F|z{8
vL><Y.kOEs
>关闭中断(CLI) !>+
0
/
QEVjXJOt0
WlY%f}ln
>从中断向量加载的CS和IP,执行中断处理程序. HG^8&uh]
YP6
+o#==
lRrOoON
当执行完中断处理程序后,一般用IRET返回,它的作用是: D&'".N
,}
R6!3Y/Q@
#qPk ,a
>从堆栈上取出保存的IP和CS(相当于指令POP CS和PUSH CS). 5!Guf?i
bUBuJ
>!$4nxq2>
>同时恢复中断前的处理器标志(相当于指令POPF). =m40{
HCP Be2
Y5;:jYk#<_
中断有多种分类,由触发的原因和实现的性质来分,可分为硬件中断和软件中断,从操作系统分层实现来说,可以分成BIOS中断,BOS中断和用户中断. eY-$hnUe
eI[z%j[Y*
8'YL!moG|
一方面,BIOS和DOS通过中断系统向用户提供一个操作系统功能界面.也就是说用户(一般来说是前台程序)的功能主要是通过调用DOS和BIOS的中断服务来实现的,具体来说就是通过INT指令来实现的.另一方面,BIOS和DOS由中断系统所构成,BIOS对硬件成为高层的功能,并通过中断的形式向用户提供. y0Tb/&xN
+vQyHo
K+7xjFoDIR
如果在当前程序执行的同时,能将一块代码放在内存,把中断向量指向代码中的子程序,那么在当前程序执行中产生中断时,就有可能执行不属于当前程序和操作系统的代码,产生的中断可能是当前程序产生的软件中断,也可能是由硬件产生的硬件中断.这就是单任务的PC操作系统可能执行多于一个进程的简单说明. Q=dR[t>^
{ sZrI5
u66w('2
在PC中断系统中有几个中断具有周期性,即INT 8H,INT 1CH和INT 28H.它们或者周期性被执行用于时间计时,或者周期性产生用于等待.它们是在实现TSR时进行轮询触发的基础.键盘中断(INT 9H和INT 16H)当用户击键时发生,利用它们是进行热键处理的基础.串行口通讯也是触发的一个重要机制.此外众多的软件中断也是触发的媒介. (/)JnBy0
J:>TV.TP
&8 (2U-
t^YDCcvoQ
0.2 DOS的可重入性分析 j_{gk"2:d`
f ZISwr
Vf:t!'WD?2
一个多任务操作系统之所以能使多个进行并存,是因为操作系统的大部分代码是可以了重的,对于临界资源有相应的PV操作,使得当调度一个新的进程时,能完整地保存前一个里程的现场,当再一次调度被挂起的进程时能象没有被中断一样继续执行. *8Lym,]
rUyT5Vf
cx02b-O
对于PC机来说,代码的重入性比较弱,对临界资源没有PC操作.当我们用中断程序启动用户的TSR时,如果只保存标志和寄存器,以及当前进程一些信息,那么只保存了当前程序的一部分现场,DOS的临界资源不会自动保存.在进行TSR设计时,一定要了解PC操作系统的重入性和临界资源. PvM<#zq_
Wc)^@f[~<
l"-D@]"
重入性总是体现在代码上,所谓可重入代码的指这样的代码,即该代码被执行时还没有从中退出,由于某种原因又一次或者多次进入相同的代码,该代码每次的执行结果都是正确的,就说该代码是可重入的.相反,如果结果不正确,那么就就该代码是不可重入的.下面是一个可重入的子程序的例子: 8FMP)N4+
n;MoMGnPh,
^^[,aBu
Add proc near iD\joh-C
$yt|nO
5p~Z-kU&
cmp DS:word ptr [si],0 zJ\I%7h*
[]Z6<rC|
`wq\K8v
je DonotAddTheValue 3w-0v"j U
"ZH1W9A
gt
?&!S^
add ax,DS:word ptr [si] $q+7,,"
c{E-4PYbah
.OjJK?
DonotAddTheValue: [Nq4<NK
T^79p$
\&cVcAg
ret mr;WxxO5
B1GSZUd^?0
S`-z$ph}
Add endp c"|^Lo.
&K7g8x"x.
|.,yM|
上面的例子不管在其中任何一处再一次执行该子程序,执行结果不变.为了说明,只举多种可能性中的一种. 7#RW4ZM
Ah"RxA
XnNK)dUT}
mov ds,0100h ;ds=0100h 6q5V*sJ&
f(3#5288
I5e!vCG)
mov si,0010h ;si=0010h \UiuJ+
lmod8B
:c6%;2
mov ax,0001h ;ax,=0001h "XH]B
MXhS\vF#m
?{FxbDp>
call Add 86I".R$d
:O{ :;X)
CocvEoE*z
cmp 0100h:word ptr [0010h],0 ;Call Add subroutine xv)7-jlx
s^AYPmR6
~r{Nc j
push ds ;Interrupted fpzTv3D=I
xNx!2MrR;
lr|-_snx2
push si Um|:AT}`^
f[z#=zv
bkY7]'.bz&
push ax 8g$ 8]'M^T
CfVz
'
Lrk^<:8;
mov ds,0200h ;ds=0200h <uAqb Wu
:gR`rc!
jHFdDw|N`
mov si,0200h ;si=0020h 'r-a:8:t^
OtC/)
sX
B
(BWdrG
mov ax,0003h ;ax=0003h -j(/5.a
osnDW
aN
xX&*&RPZ
call Add h;B'#$_
KJ-D|N,8@^
#)\KV7f!;
cmp 0200h:word ptr [0020h],0 ;0200:0020h=0004h Sw0~6RZ
"c}bqoN
x|Q6[Y
jne %xY'v$
%
6h5*b8LxA
Pukq{/27
add ax,0200h:word ptr [0020h] ;ax=0007h tvg7mU]l
*d%m.:)N
I*0W\Qz@
ret ;Return "BTA"
l\S..B
+
;DRJL
pop ax ;ax=0001h 10a=[\ Q
rVz#;d!`z
?1[go+56X
pop si ;si=0010h F'Wef11Yz
L5>>gG,
DO0["O74
pop ds ;ds=0100h $[z*MQ
(;s\Ip0
BtjsN22
iret ;Return to Add subroutine 8]0R[kjD
d29]R.
]-0
&[@I4@
jne *<9p88FpDU
Kr9 @
79i>@u%
add ax,0100h:word ptr [0100h] ;ax= 0001h 4u
/?..L.
{i=qx#2X?H
9zX\ioT
;0100h:0010h= 0002h > sUk6Z~
Hiq9Jn uv(
,,i;6q_f
;---------------------------------------- _)
p%
pa.W-qyu
b]J_R"}
;ax = 0003h jdhhvoQ
&^z~wJ,]
NE/3aU
ret r<"1$K~Ka
YAO.Cc z
\ii^F?+b
mov bx,ax ArF+9upGY
t4,6`d?C
)EO$JwQ
而下面的子程序是不可重入的: /+3|tb
643 O(0a
/423!g0
Q
Add proc near Lrz>00(*4
Q:%gJ6pa
aZmSCi:&'
mov Temp,ax wD*_S}]
@ws3X\`<C
`B^?Za,xN
mov ax,DS:word ptr [si] &gq\e^0CRZ
xOS4J+' s@
KC
cmp ax,0 h88
3pe=
QjRVdb>
"F0,S~tZZ
je DonotTheValue e#08,wgW
YHE7`\l
}|x]8zL8G
add ax,Temp NjMo"1d
AN^;~m ^
d,$[633It}
DonotTheValue: or(Z-8a_
(=7e~'DC
Um*{~=;u
ret BB~Qs
cnI!}Bu
Z EG
Temp:
4$.4,4+
fa$ Fo(.
k8w8I$QEM
dw 0 FzW(An&x2
&ts!D!Hj
z<)?8tAgq
Add endp Ii;~ xc