这个SideKick是个好东东。 uwId
rx}*u3x=
下面的程序不是我写的。 z[Z2H5[
c G*(C
用汇编编写DOS下的内存驻留程序(1) T(&kXMaB
tU(y~)]
A ~XOK;sB
CX.SYr&!R
C;%Y\S
m1i4 ,
"kU>~~y,
绪言 ])S$x{.g
-3\7vpcdN
G#'Q~N
0.1 内存驻留与中断 k~R{Y~W!!
+>u>`|
(>mi!:
内存驻留程序英文叫Terminate and Stay Resident Program,缩写为TSR.这些程序加载进内存,执行完后,就驻留在内存里,当满足条件时,调到前台来执行。 $59nu7yr
pIvfmIm
KZW'O
b>[
内存驻留程序的常用形式有: {Wa~}1`Kl
hXPocP
L2d:.&5
>诸如Borland 的SideKick弹出式实用程序 iT[oKD0)
6#O#T;f)
99a\MH`^
>日历系统 )ib7K1GJ
,y{0bq9*2
O%prD}x
>网络服务器 w)^\_uAlS
CQ$::;
x!`b'U\
>通讯程序 ]ZDTn
k*OvcYL1A
zw
,-.fmM#
>本地的DOS扩展(如CCDOS,UCDOS等中文系统都属于这个范畴) TZj[O1E
F G3Sk!O6
RP(a,D|
>一些可恶的人利用TSR技术制作很多可恶的病毒程序,几乎所有的病毒程序都是TSR程序. )7k&`?Mh
:b<KX%g
B%
2L1T=
就象多任务系统调度一个进程有一个调度程序一样,在PC中从前台程序进入到一个TSR,也要有一个调度者,只是PC操作系统的调度不称为调度程序,而只称为触发机制.触发机制调度TSR执行在PC机上党称为激活一个TSR.触发机制主要有以下几种: u7n[f@Eg,%
-E}>h[;qZ
T
G_bje
>硬件中断:党用的是键盘中断INT 9H,时钟中断INT 8H,通讯中断INT 14H,磁盘中断INT 13H等等. U>in
2u9
/MhS=gVxM
ZWFG?8lJ
>软件中断:党用的是键盘中断INT 16H,时钟中断INT 1CH,DOS中断INT 21H,等等. /%5_~Jkr,
_/ct=
Q
g$($
>以上各种的结合. E*OG-r
\WiqN*ZF
})K
J60B
从以上的触发机制可以看出,TSR和PC机的中断系统有着密切的关系.每种激活方式实际上都是与中断有关的.常用特殊的击键序列的识别码是通过截获INT 9H和INT 16H来实现.实际上不管TSR程序的哪一个环节,都与中断有着密切的关系.因此在具体进行TSR和程序设计之前,先介绍PC中断系统.在此只作简单说明. z'_&|-m
&adY
di--
:h/
在PC机内存的最低端(0000H开始)的1K字节中,存放着256个指针即常说的中为向量或中断矢量(Interrupt vertor),每个中断向量都指向一个子程序,该程序称为中断处理程序(Interrup handler).一个中断向量由四个字节组成,有一个字是中断处理程序的偏移量值,后一个字是中断处理程序的段值.256中断向量一起称为中断向量表. &;Ed*OJ
{:,_A
@W#fui<<}Y
手式计算中断向量的首址,可通过以下的公式来求得: =w?M_[&K)
Ri;=aZ5m
z;[gEA+I
X号中断向量的首址=0000H:X*4 zuk"
[7'#~[a~
!O 4<I_EY{
当产生一个中断时,处理器都按顺序执行以下步骤: pXve02b1B
AvyQ4xim+
eN2dy-0
>在堆栈上压入处理器的标志(相当于指令PUSHF). TF%3uH
Zd8drT'@#
8W;xi:CC
>在堆栈上压入当前CS和IP值(相当于指令PUSH CS和PUSH IP). qFrt^+@
:4%<Rp
E(%
XVr0W
>关闭中断(CLI) Q!YF!WoBX
6g}^Q?cpV#
3mk=ZWwv
>从中断向量加载的CS和IP,执行中断处理程序. \QliHm!
|xp$OL"a
<D~6v2$
当执行完中断处理程序后,一般用IRET返回,它的作用是: Q,D0kS P
gxI&f
';&0~ [R[
>从堆栈上取出保存的IP和CS(相当于指令POP CS和PUSH CS). J6eJIKK
r }ZLf
sfyBw
>同时恢复中断前的处理器标志(相当于指令POPF). Mm "Wk
UOw~rK
B*y;>q "{U
中断有多种分类,由触发的原因和实现的性质来分,可分为硬件中断和软件中断,从操作系统分层实现来说,可以分成BIOS中断,BOS中断和用户中断. ]/LWrQD
NvUu.
0{-`Th+h
一方面,BIOS和DOS通过中断系统向用户提供一个操作系统功能界面.也就是说用户(一般来说是前台程序)的功能主要是通过调用DOS和BIOS的中断服务来实现的,具体来说就是通过INT指令来实现的.另一方面,BIOS和DOS由中断系统所构成,BIOS对硬件成为高层的功能,并通过中断的形式向用户提供. bo&\3
~B<97x(X
qC\]"Z`m
如果在当前程序执行的同时,能将一块代码放在内存,把中断向量指向代码中的子程序,那么在当前程序执行中产生中断时,就有可能执行不属于当前程序和操作系统的代码,产生的中断可能是当前程序产生的软件中断,也可能是由硬件产生的硬件中断.这就是单任务的PC操作系统可能执行多于一个进程的简单说明. Y 5Qb4Sa
y
+?=E g
a#^_"GX
在PC中断系统中有几个中断具有周期性,即INT 8H,INT 1CH和INT 28H.它们或者周期性被执行用于时间计时,或者周期性产生用于等待.它们是在实现TSR时进行轮询触发的基础.键盘中断(INT 9H和INT 16H)当用户击键时发生,利用它们是进行热键处理的基础.串行口通讯也是触发的一个重要机制.此外众多的软件中断也是触发的媒介. }i
D$4\ L
:G^"e
$4DFgvy$
K?9WY]Ot
0.2 DOS的可重入性分析 yQ8M >H#J
kmmL>fCV"M
"EN98^
Sl
一个多任务操作系统之所以能使多个进行并存,是因为操作系统的大部分代码是可以了重的,对于临界资源有相应的PV操作,使得当调度一个新的进程时,能完整地保存前一个里程的现场,当再一次调度被挂起的进程时能象没有被中断一样继续执行. O;UiYrXU
xy$vYDAFw
{cmo^~[L$
对于PC机来说,代码的重入性比较弱,对临界资源没有PC操作.当我们用中断程序启动用户的TSR时,如果只保存标志和寄存器,以及当前进程一些信息,那么只保存了当前程序的一部分现场,DOS的临界资源不会自动保存.在进行TSR设计时,一定要了解PC操作系统的重入性和临界资源. @55bE\E?@
RV(
w%g
,>&?ty9o
重入性总是体现在代码上,所谓可重入代码的指这样的代码,即该代码被执行时还没有从中退出,由于某种原因又一次或者多次进入相同的代码,该代码每次的执行结果都是正确的,就说该代码是可重入的.相反,如果结果不正确,那么就就该代码是不可重入的.下面是一个可重入的子程序的例子: ]Mn&76fu
1po"gVot
5LO4P>fq
Add proc near ZEL/Ndk
^CfM|L8>
?E%U|(S)=L
cmp DS:word ptr [si],0 mr@_%U
*C5:#A0
sk~ za
je DonotAddTheValue {-o7w0d_
U&,r4>V@h>
y>@v>S
add ax,DS:word ptr [si] ^uC"dfH
r4 9UJE
`@4 2jG}*
DonotAddTheValue: h0T< :X
wDB)&b
4,j4E@?pG9
ret NR;q`Xe-
|.y>[+Qb*
ooomi"u
Add endp [&1iF1)4
B"7$!C o
GEhdk]<a7
上面的例子不管在其中任何一处再一次执行该子程序,执行结果不变.为了说明,只举多种可能性中的一种. cC b>zI
\H,V 9!B
qnabw F
mov ds,0100h ;ds=0100h o,g6JTh
uG2Xkj
_2]e1_=
mov si,0010h ;si=0010h B1x'5S;Bq
g!p+rq_f
Z"l`e0{
mov ax,0001h ;ax,=0001h nsZDZ/jx
$|>6z_3%
2ZU@>W
call Add UVc>i9,0
nwY2BIB
Lv
cmp 0100h:word ptr [0010h],0 ;Call Add subroutine :5r:I[FFy
enPzy:C
GA'*58
push ds ;Interrupted T^KCB\\<
-;sJ25(
R'vdk<
push si CbnR<W-j
"CIpo/ebL
E^oEG4X@
push ax `K$:r4/[
u86J.K1Q
%2^['8t#NH
mov ds,0200h ;ds=0200h /Lq;w'|I
JOA%Y;`<#
lf?Z{^
mov si,0200h ;si=0020h \7|s$ XQ\
'}wG"0
vs5
D:cZ}
mov ax,0003h ;ax=0003h cFRSd
}p=
`Mo~EHso.
6$W -?
call Add <'g0il
2Som0T<2
*raIV]W3
cmp 0200h:word ptr [0020h],0 ;0200:0020h=0004h zb@L)%
zi?qK?m
=@bXGMsV!
jne WpZy](,
O{;M6U8C\
Q'FX:[@x-S
add ax,0200h:word ptr [0020h] ;ax=0007h ^?H\*N
4
ph Wc8[Q
0|WOReskK
ret ;Return VFe-#"0ZO
&@mvw=d
L~^e\^sP
pop ax ;ax=0001h 0|],d?-h
#nU@hOfg
Ln"+nKr
pop si ;si=0010h /AK*aRU^
~J8cS
~*66 3pA
pop ds ;ds=0100h ?9o#%?6k
@qg0u#k5
@)aXNQ
Y
iret ;Return to Add subroutine hXV4$Dai
I>N-95
H=JP3ID>{
jne 5A0KV7N5
~
@b9
Da9* /
add ax,0100h:word ptr [0100h] ;ax= 0001h T+&x{+gZ
"U/NMGMj
6LSPPMM
;0100h:0010h= 0002h I T*fjUY&
v&t`5-e-A
h#(.(d
;---------------------------------------- yrxx+z|wR
,U|u-.~ZU
m
_t(rn~f6
;ax = 0003h Y;a6:>D%cT
H;7O\
+=n
x|:no
ret ')5jllxv
r?Ev.m
v:'P"uU;4
mov bx,ax ANA2S*r
')C_An>X6
*X-~TC0
[
而下面的子程序是不可重入的: TzD:bKE&
Sa?~t3*H
/u
"
cl2|
Add proc near "Qiq/"h
`^s]?
]1/W8z%
mov Temp,ax Y\Fuj)
zJB+C=]D7H
B`RW-14g
mov ax,DS:word ptr [si] y1@"H/nYJ
uAPLT~
3L
1lq .
cmp ax,0 EvGU j$
@F""wKnV
e3HF"v]2!
je DonotTheValue B}TInI%H
18[?
dV
!5g)3St
add ax,Temp A-AN6.
ql%]$`IV6
sT;=7L<TA
DonotTheValue: i9#`F.7F
o
m{n"cg
?z4uze1
ret a$+e8>
2vk8+LA(6
Sgjr4axu
Temp: MJ*oeI!.=
h0y\,iWXb
?kT~)k
dw 0 'vf,T4uQ"
x~3>1Wr#M
e+]YCp[(
Add endp ;6\Ski0=l