woaicici 发表于 2006-4-17 18:58:03

3.4 再谈寄存器和内存的区别
第零讲说到“寄存器在CPU中。内存在内存条中。前者的速度比后者快100倍左右。后面的程序要求每条指定要么没有内存数据,要么在有一个寄存器的参与下有一个内存数据。(也就是说,不存在只访问内存的指令)。”
寄存器是在CPU中的存储器,而内存是在内存条中的存储器。CPU访问寄存器,只需要通过微指令直接就可以访问,而访问内存则要先经过总线,再由总线到达内存控制器,读到某单元的内存数据后放上总线,再传到CPU中,CPU才能使用。
8086系列计算机的寄存器,共有14个,每个都是十六位的。
AX,BX,CX,DX,SP,BP,SI,DI,CS,DS,SS,ES,IP,FLAGS。
其中前四位,每个可以单位再分成两个,AX=AH+AL,BX=BH+BL,CX=CH+CL,DX=DH+DL。这些分开的每个都是8位的。
这个分开不要理解成平时语言中的分开,你可以理解为AX是由AH和AL组合成的,你给AL付值,就意味着同时给AX的低半部付值。你给AX付值,就意味着同时改变AH和AL。这样作的好处是你可以更灵活地控制这个寄存器。


3.5 指令说明
看了3.3的指令集和3.4的寄存器,是不是已经了,或者了?不要急,上面的东西虽然多,我也没让你一下学会,(其实有些永远也不会似乎也不是什么大不了的事)。为了应付看的懂我后面所说的,我把其中的指令挑几个重点的,你必须要记住,其它的慢慢学吧。

1数据传输指令。
mov A,B
注意不是move,这个指令是把B中的数据复制给A,(B中仍保存原状)。这里的A和B可以是寄存器,可以是内存。但可以同时是寄存器,不能同时是内存。比如
mov ax,100 ;这是对的,注意100在这里叫立即数,但这个数在编译系统编译成exe的时候保存在内存中。如果学过别的高级语言,你就可以理解为这就是赋值语句 Let ax=100/ax:=100;/ax=100。
2 伪指令
伪指令就是不是真的指令,但他同时又是指令。之所以说这样矛盾的话,是因为伪指令不是机器语言的一部分,而是汇编语言的一部分,是你告诉汇编的编译系统如何去作。
string DB '这是我的第一个汇编语言程序$'
上面一行指令中,DB就是伪指令,他的作用就是告诉编译程序,把后面一些数据或字符串放到内存中。当然对于exe来说,已在内存中了,就不用“告诉”了。(这就是为什么叫伪指令)。string是你给这段内存起的名字,如果你不需要这段内存,不起名字也可以,但如果后面要用,当然要加上这个名字。'这是我的第一个汇编语言程序$'这个就是要处理的数据,当然你也可以换成别的内容,但需要注意的是,要以'$'结尾,这是汇编的约写,即:只是到了$,就认为字符串结束,否则就一直向下找,直到找到一个$为止。所以这就要求你的字符串中不能有'$',如果必须有,再换别的处理方式,后面再说。
3 地址传送指令
Lea A,string
前面已经定义了string,后面要把地址找到,就要用到lea指令。lea是把字符串的地址给A这个寄存器中,A当然可以上前面提到的任意寄存器。注意地址和内容的区别。如果是内容就是把string的字符串给A了。(当然这也不成立,一个字符串有很多字节,而一个寄存器只有两个字节)。
那么从上面也看到了,string代表一个地址,lea把这个地址给了A,那这个地址到底在哪里呢?事实上这不重要,就象你要把某书店买书,这个书店在哪并不是最重要的,有没有你要的书才是最重要的。所以你前面标出string,后面引用就行了,至于这个地址到底在哪是编译程序的事,不是你的事。

4 运算指令
ADD A,N
这个很容易理解吧,寄存器A加上N,把和仍存在A中。类似于高级语言中的let a=a+n/a:=a+n/a+=n。

5 串操作指令
记住串操作指令表面很复杂,其实很简单。
因为他就象一个复杂的数学公式一样简单,你所要记住的就是公式的格式,使用时具体套用即可。
从一个地址到另一个地址的复制需要注意的是:
*把源串段地址给DS。
*把源串编址给SI。
*把目的串段址给ES。
*把目的串偏址给DI。
*把要复制的个数给CX,这里可不考虑$了。
*把FLAG中的方向标志标志你要的方向,一个是顺向,另一个是逆向。
*发送loop movs,scans等命令。


6 转移指令
记住:无条件转移指令 jmp。等于转 jz,不等于时转jnz

7 中断指令
int 中断号,注意进制,默认是十进制,所以十六进制就加h。

好了,上面的指令变成七八个了,这你不能嫌多了吧,如果再嫌多就不要继续向下看了。

woaicici 发表于 2006-4-17 18:58:39

-------------------------------------------------------------------------------------------

第四讲 汇编程序

4.1 汇编程序框架

data SEGMENT '数据段,编程者可以把数据都放到这个段里
....数据部分
'数据格式是: 标识符 db/dw 数据。
data ENDS'数据段结束处。

edata SEGMENT '附加数据段,编程者可以把数据都放到这个段里
....附加数据部分
edata ENDS'附加数据段结束处。

code SEGMENT'代码段,实际的程序都是放这个段里。
      ASSUME CS:code,DS:data,ES:edata '告诉编译程序,data段是数据段DS,code段是代码段CS
start:MOV AX,data '前面的start表示一个标识位,后面用到该位,如果用不到,就可以不加
      MOV DS,AX '这一句与上一行共同组成把data赋值给DS。段寄存器.
      MOV AX,edata
      MOV ES,AX '与前一句共同组成edata->ES
      .......程序部分
      MOV AX,4C00h'程序退出,该句内存由下一行决定。退出时,要求ah必须是4c。
      INT 21h
code ENDS'代码段结束。
END start'整个程序结束,并且程序执行时由start那个位置开始执行。


上面就是一个程序的框架结构。在这个结构中,有三个段,DS,ES,CS。这三个段分别存数据,附加数据,代码段。

4.2 编写我们的Hello,world思路。
开始编写我们的第一个程序。
程序要求:显示一个“Hello,Mr.286.”怎么样?
思路:
1 要显示一个字符串,根据前面我让你们记的七八个指令够吗?答案是:不仅够,而且还用不完。
首先定义一下总可以吧。

hellostr db 'Hello,Mr.286.$'
最后的$不要忘了。

2 首先要考虑的问题就是找中断,找到合适的中断,该中断就能帮我们完成这个显示任务。我找到(在哪找到的,怎么找到的,别问我,到网上或书上都能找到):
-------------------------------------------
中断INT 21H功能09H

功能描述: 输出一个字符串到标准输出设备上。如果输出操作被重定向,那么,将无法判断磁盘已满
入口参数: AH=09H
DS:DX=待输出字符的地址
说明:待显示的字符串以’$’作为其结束标志
出口参数: 无
-------------------------------------------
由上面看到,我们所需要作的就是把DS指向数据段,DX指向字符串的地址,AH等于9H,调用21h中断。
mov ds,数据段地址
lea dx,hellostr 'hellostr已在前面1中定义了。
mov ah,9h
int 21h。
由于只要在调用int 21h之前把准备的东西准备齐就行了,所以int 21h前面三行的顺序并不重要。

3 退出程序,运行完总要退出呀。再查中断手册
--------------------------------------------
中断INT 21H功能4CH

功能描述: 终止程序的执行,并可返回一个代码
入口参数: AH=4CH
AL=返回的代码
出口参数: 无

--------------------------------------------
mov ah,4Ch
mov al,0
int 21h

mov ax,4c00h
int 21h
这里需要说明的是返回代码有什么用,返回给谁?返回给操作系统,因为是操作系统DOS调用的这个程序,这个返回值可以通过批处理中的errorlevel得到,这里不多说明,实际上操作系统很少处理这一值,因此al你随便写什么值影响都不大。

4.3 程序实现
data SEGMENT
msg DB 'Hello, Mr.286.$'
data ENDS

code SEGMENT
      ASSUME CS:code,DS:data
start:MOV AX,data
      MOV DS,AX
      lea dx,msg
      mov ah,9h
      int 21h
      MOV AX,4C00h
      INT 21h
code ENDS
END start

4.4 编译运行。
把上面程序保存成hello286.asm后,就可以编译运行了。进入DOS,进入汇编目录,如果还没下载,到前面找下载地址。

=================================================
E:\Download\Masm>masm hello286.asm
Microsoft (R) Macro Assembler Version 5.00
Copyright (C) Microsoft Corp 1981-1985, 1987.All rights reserved.

Object filename :
Source listing:
Cross-reference :

50408 + 415320 Bytes symbol space free

      0 Warning Errors
      0 SevereErrors
说明:上面连续三个回车,表示我要的都是默认值。下面是零个警告,零个严重错误,(当然了,我的程序还敢错吗?)

E:\Download\Masm>link hello286

Microsoft (R) Overlay LinkerVersion 3.60
Copyright (C) Microsoft Corp 1983-1987.All rights reserved.

Run File :
List File :
Libraries [.LIB]:
LINK : warning L4021: no stack segment

说明:三个回车仍要默认,后面有个警告,没有栈段,这个没关系,没有的话系统会自动给一个()。

E:\Download\Masm>hello286
Hello, Mr.286.
说明:运行成功。
E:\Download\Masm>


-------------------------------------------------------------------------------------------

-------------------------------------------------------------------------------------------

4.4 深度思考
4.4.1 是不是数据必须放数据段,代码必段放代码段呢?
答,代码必段放代码段,否则你怎么执行呀?但数据也可以放到代码段,只是程序要作修改。
code SEGMENT
      ASSUME CS:code,DS:data
      msg DB 'Hello, Mr.286.$'
start:MOV AX,data
      MOV DS,AX
      lea dx,msg
      mov ah,9h
      int 21h
      MOV AX,4C00h
      INT 21h
code ENDS
END start
编译后仍然可以。
4.4.2 我编的程序在内存中是什么样子的呢?
------------------------------------------------------------------------
E:\Download\Masm>debug hello286.exe
-u
1420:0000 B81F14      MOV    AX,141F
1420:0003 8ED8          MOV    DS,AX
1420:0005 8D160000      LEA    DX,
1420:0009 B409          MOV    AH,09
1420:000B CD21          INT    21
1420:000D B8004C      MOV    AX,4C00
1420:0010 CD21          INT    21
1420:0012 FF362421      PUSH   
1420:0016 E87763      CALL    6390
1420:0019 83C406      ADD    SP,+06
1420:001C FF362421      PUSH   
-d 141f:0000 L20
141F:000048 65 6C 6C 6F 2C 20 4D-72 2E 32 38 36 2E 24 00Hello, Mr.286.$.
141F:0010B8 1F 14 8E D8 8D 16 00-00 B4 09 CD 21 B8 00 4C............!..L
-q

E:\Download\Masm>
------------------------------------------------------------------------------
上面是什么呀?,还记得前面说的吗?
1420:0000 B81F14      MOV    AX,141F
||      |          |          |
段址:偏址 机器语言      mov指令 把段地址的地址(141f)赋值给AX寄存器。

1420:0012后面的是垃圾数据,不用管它,把上面程序与源程序作一个比较,看有什么不用,差别在于把标号语言转成实际地址了。
程序前两行一执行,数据段地址就变成了141f,而那个字符串偏移地址在0000,由(LEA    DX,看出),所以我用-d 141f:0000 L20(后面L20表示只显示20个字节),就能把段地址显示出来了。
所以刚才的程序在内存中就变成了:
141f:0000 Hello, Mr.286.$----->这是段地址里的内存
1420:0000 B81F14      MOV    AX,141F------>这是代码段里的内存。data变成了实际地址
1420:0003 8ED8          MOV    DS,AX
1420:0005 8D160000      LEA    DX, ------>偏址变成了0000,因为实际上msg也就是从头开始的。当然是0了。
1420:0009 B409          MOV    AH,09    ------->注意Debug里,默认的是十六进制
1420:000B CD21          INT    21
1420:000D B8004C      MOV    AX,4C00
1420:0010 CD21          INT    21

hjd7578 发表于 2006-4-17 18:59:45

好东西!!顶顶!

woaicici 发表于 2006-4-17 19:00:24

-------------------------------------------------------------------------------------------

回复: 青蛙 (一网友回复的)

4.4深度思考中的这个程序没有定义数据段;不会通过编译;
code SEGMENT
      ASSUME CS:code,DS:data
      msg DB 'Hello, Mr.286.$'
start:MOV AX,data
      MOV DS,AX
      lea dx,msg
      mov ah,9h
      int 21h
      MOV AX,4C00h
      INT 21h
code ENDS
END start
应该在前面添加
data segment
data ends

-------------------------------------------------------------------------------------------

-------------------------------------------------------------------------------------------

回复: 青蛙 (一网友回复的)

哪个程序在我的机子的内存上怎么是这个样子?
0B49:000F B8490B      MOV    AX,0B49
0B49:0012 8ED8          MOV    DS,AX
0B49:0014 8D160000      LEA    DX,
0B49:0018 B409          MOV    AH,09
0B49:001A CD21          INT    21
0B49:001C B8004C      MOV    AX,4C00
0B49:001F CD21          INT    21
0B49:0021 C786FEFE0000MOV    WORD PTR ,0000
0B49:0027 EB05          JMP    002E
0B49:0029 90            NOP
0B49:002A FF86FEFE      INC    WORD PTR
0B49:002E A15607      MOV    AX,
怎么根286的不一样?


-------------------------------------------------------------------------------------------

-------------------------------------------------------------------------------------------
回复: jueguzi (一网友回复的)

哪个程序在我的机子的内存上怎么是这个样子?
0B49:000F B8490B      MOV    AX,0B49
0B49:0012 8ED8          MOV    DS,AX
0B49:0014 8D160000      LEA    DX,
0B49:0018 B409          MOV    AH,09
0B49:001A CD21          INT    21
0B49:001C B8004C      MOV    AX,4C00
0B49:001F CD21          INT    21
0B49:0021 C786FEFE0000MOV    WORD PTR ,0000
0B49:0027 EB05          JMP    002E
0B49:0029 90            NOP
0B49:002A FF86FEFE      INC    WORD PTR
0B49:002E A15607      MOV    AX,
怎么根286的不一样?

你的机子当然不是286的了,所以你的数据段和他的不是一个东东了!
-d 0B49:0000 20 就ok 了!



-------------------------------------------------------------------------------------------

-------------------------------------------------------------------------------------------

最近太忙,没时间看,没想到还真有不少人看这个贴子。续写短时间内可能性不大。不过,我就针对上面几个回答作一个回复。

1 那个只有代码段的程序。很多看客估计已经试过,但没试成功,部分人还给出了修改意见,但我看了所有的修改,都有问题,改后当然是通过了,但结果是不对的,也与我说的数据段代码段合并有冲突。
其原因很简单,因为我很多东西是在线写的,部分程序也没有去调试。错就错在一个符号上。现在我把正确的贴出,大家可以试试。
code SEGMENT
      ASSUME CS:code    ------------->改处一,既然不要数据段了,也没必要要DS了。当然这个地步是小地方,前面说过ASSUME只是告诉其作用,多写DS:DATA也不算错。
      msg DB 'Hello, Mr.286.$'
start:MOV AX,code      ------------->改处二:这个地方才是关键,原来是DATA,现在合并了,应该改为CODE。
      MOV DS,AX
      lea dx,msg
      mov ah,9h
      int 21h
      MOV AX,4C00h
      INT 21h
code ENDS
END start

2 很多人说DEBUG一项显示的内容与我显示的不一样。一个程序被加载到内存中,此前运行过的程序个数和顺序是不一样的,一般来说,程序被加载到内存最低端,因此新程序的段地址不一样是正常的。也就是说你们显示结果和我的显示结果“不完全”一样是正常的。比如。
|------A程序-----|------B程序-----|-----你的程序-----|
|------A程序-----|------你的程序-----|-----C程序-----|
上面两种情况下,两个“你的程序”首地址当然会不一样,但偏移地址肯定是一样的。

------------------------引用我此前的内容-------------------------------
E:\Download\Masm>debug hello286.exe
-u
1420:0000 B81F14      MOV    AX,141F
1420:0003 8ED8          MOV    DS,AX
1420:0005 8D160000      LEA    DX,
1420:0009 B409          MOV    AH,09
1420:000B CD21          INT    21
1420:000D B8004C      MOV    AX,4C00
1420:0010 CD21          INT    21
1420:0012 FF362421      PUSH   
1420:0016 E87763      CALL    6390
1420:0019 83C406      ADD    SP,+06
1420:001C FF362421      PUSH   
-d 141f:0000 L20
141F:000048 65 6C 6C 6F 2C 20 4D-72 2E 32 38 36 2E 24 00Hello, Mr.286.$.
141F:0010B8 1F 14 8E D8 8D 16 00-00 B4 09 CD 21 B8 00 4C............!..L
-q

E:\Download\Masm>
---------------------------------------引用结束----------------------------
在上述引用框内,你的内存映象中段址和我的内存映象中,你的代码段段址可以和我的1420不一样,你的数据段地址可以和我的141F不一样。1420:0012 以后的内容可以不一样,因为那已是咱们的程序之外的随机数据。但其它的应该一样,包括MOV    AX,141F应该是0000,MOV    AX,4C00应该是000D。
有些书为了避免大家产生误会,常常写成:
CS:0000 B81F14      MOV    AX,141F
CS:0003 8ED8          MOV    DS,AX
CS:0005 8D160000      LEA    DX,
CS:0009 B409          MOV    AH,09
CS:000B CD21          INT    21
CS:000D B8004C      MOV    AX,4C00
CS:0010 CD21          INT    21


-------------------------------------------------------------------------------------------

-------------------------------------------------------------------------------------------

那个日期显示部分,我现在下班了。,没时间编写了。不过你们可以通过这种方式验证。

E:\Download\Masm>debug
-a
1360:0100 mov ah,2a
1360:0102 int 21
1360:0104 int 3    ---------------》INT 3 就是程序运行到这里停一下。
1360:0105
-g=100

AX=2A05BX=0000CX=07D5DX=0910SP=FFEEBP=0000SI=0000DI=0000
DS=1360ES=1360SS=1360CS=1360IP=0104NV UP EI PL NZ NA PO NC
1360:0104 CC            INT    3
-
2A功能描述为: 取系统日期
入口参数: AH=2AH
出口参数: CX=年(1980~2099),DH=月(1~12),DL=日(1~31)
AL=星期几(0=Sunday,1=Monday,...)
看看上面的结果,DH=09,也就是9月份。DL=10H=16,记得H是什么意思吗?就是十六进制,十进制就是16,今天是9月16日。后天是中秋节。AL=05,今天是周五。CX=07D5H=2005年。
具体怎么显示出来,下次再说吧。

woaicici 发表于 2006-4-17 19:02:58

回复: GuessMe

大家来讨论汇编这么热闹,我也来凑乎凑乎。下面的是我在www.cnxhacker.com发的帖子,下面转到这里来,大家来看看。
-------------------------------------------------------------------------------------
刚刚学习了8086/8088汇编语言,发现寻址方式非常重要,于是做了一个小总结,请各位笑纳。
概念:
    1.指令集:cpu能够执行的指令的集合。
    2.指令:cpu所能够执行的操作。
    3.操作数:参加指令运算的数据。
    4.寻址方式:在指令中得到操作数的方式。
现在就重点讨论寻址方式,说白了也就是cpu怎么样从指令中得到操作数的问题。另外再强调一点操作数还分种类:
1)数据操作数:全都是在指令当中参加操作的数据。
    1.立即操作数:它在指令中直接给出。
    2.寄存器操作数:它被放到寄存器中。
    3.存储器操作数:当然在存储器也就是内存中。
    4.i/o操作数:它在你给出的i/o端口中。
2)转移地址操作数:在指令当中不是参加运算或被处理的数据了,而是转移地址。
还可以按照下面分类方式:
1)源操作数src
2)目的操作数dst
源操作数都是指令当中的第2个操作数,在执行完指令后操作数不变。而目的操作数是指令当中的第1个操作数,在执行完操作指令后被新的数据替代。
我们就围绕这几种操作数,也就是操作数所在的位置展开讨论。
先说数据操作数,它分3大类共7种。
1)立即数寻址方式:是针对立即操作数的寻址方式。在指令当中直接给出,它根本就不用寻址。
例1:mov ax,1234h
    mov ,5678h
在这里1234h和5678h都是立即操作数,在指令当中直接给出。
2)寄存器寻址方式:是针对寄存器操作数的寻址方式,它在寄存器中我们就用这中方式来找到它。
例2:movbx,ax
    movbp,
在这里ax,bx,ds都算是寄存器寻址,例1中的ax也是寄存器寻址方式。
3)存储器寻址方式:针对在内存中的数据(存储器操作数)都用这种方式来寻找,一共有5种(这是我自己的说法,便于记忆)。
不得不提及以下的概念:由于8086/8088的字长是16bit,能够直接寻址2的16次方也就是64kb,而地址总线是20bit,能够直接寻址2的20次方也就是1M空间,所以把内存分为若干个段,每个段最小16byte(被称为小节),最大64kb,它们之间可以相互重叠,这样一来内存就被分成以16byte为单元的64k小节,cpu就以1小节为单位寻址:在段寄存器中给出段地址(16bit),在指令当中给出段内偏移地址(16bit),然后把段地址左移4bit再与偏移地址求和就得到数据在内存当中的实际物理地址了,因而可以找到数据。
1.存储器直接寻址方式:在指令当中以[地址]的方式直接给出数据所在内存段的偏移地址。
例3:movax,es:
    movdx,VALUE
    movdx,
在这里和VALUE就是在指令中直接给出的数据所在内存段的偏移地址(16bit)。
VALUE是符号地址,是用伪指令来定义的,它代表一个在内存中的数据(也就是它的名字)。es:是段前缀符,用来指出段地址,在这之前应该将段地址添入段中,本例中是es,默认是ds,也就是不需给出。应该注意[地址]与立即寻址的区别,在直接给出的数据两边加[]表示存储器直接寻址,以区别立即寻址。另外VALUE=。
2.寄存器间接寻址:不是在指令中直接给出数据在内存中的偏移地址,而是把偏移地址放到了寄存器中。
例4:movax,
这里就是寄存器间接寻址,bx中应方入段内偏移地址。其中:若使用bx,si,di默认段地址为ds,若使用bp则默认段地址为ss,并且允许段跨越,也就是加段前缀符。注意:在寄存器两边加[]以与寄存器寻址区别。
3.寄存器间接相对寻址:偏移地址是bx,bp,si,di中的内容再与一个8bit或16bit 的位移量之和。
例5:movax,+12h
    movax,+5678h
    movax,+1234h
在这里+12h,+5678h,+1234h都是寄存器间接相对寻址。12h是8bit位移量,1234h和5678h是16bit位移量。若使用bx,si,di则默认段寄存器是ds,若使用bp则默认段寄存器是ss,并且允许段跨越。
4.基址变址寻址:偏移地址是一个基址寄存器和一个变址寄存器内容的和,既:bx或bp中的一个与si或di中的一个求和而得到。
例6:movax,
    movax,
上面和都是基址变址寻址。若使用bx做基址寄存器则默认段地址为ds,若使用bp为基址寄存器则默认段为ss,允许段跨越。
5.基址变址相对寻址:偏移量是一个基址寄存器一个变址寄存器只和再与一个8bit或一个16bit位移量只和得到。
例7:movax,+12h
    movax,+1234h
+12h和+1234h就是基址变址相对寻址。若使用bx做基址寄存器则默认段是ds,若使用bp做基址寄存器则默认段为ss。允许段跨越。

下面是转移地址操作数的寻址方式:
1)段内直接转移
    1.段内直接短转移:cs(代码段)内容不变,而ip(指令指针寄存器)内容由当前ip内容+(-127~127),在指令中直接给出。
例8:jmpshortSHORT_NEW_ADDR
其中,short是段内短转移的操作符,用以指出是转移到当前位置前后不超过±127字节的地方。而NEW_ADDR是要转移到的符号地址,它的位置应该在当前ip指针所在偏移地址不超过
±127的地方。否则语法出错。
    2.段内直接近转移:cs内容不变,而ip内容由当前ip内容+(-32767~32767),在指令中直接给出。
例9:jmpnearptrNEAR_NEW_ADDR
其中near ptr是段内近转移的操作符,用以指出转移到当前位置前后不超过±32767的地方。NEAR_NEW_ADDR是要转移到的符号地址。
2)段内间接转移:cs的内容不变,而ip的内容放在寄存器中或者存储器中给出。
例10:jmpbx
      jmpwordptr+1234h
这种寻址方式是在寄存器或存储器中找到要转移到的地址,而地址是16bit的,因而寄存器必须为16bit,如:bx,我们用wordptr来指定存储器单元也是16bit的。注意:它是间接的给出,只能使用类似于数据操作数中的除立即寻址以外的6种寻址方式(就在上面)。
3)段间直接寻址:cs和ip的内容全都变化,由指令当中直接给出要转移到的某一个段内的某一个偏移地址处。
例11:jmp1234h:5678h
      jmpfarptrNEW_ADDR
1234h送入cs中作为新的段地址,5678h送入ip中作为新的偏移地址。farptr是段间直接转移操作符,NEW_ADDR是另外一个段内的偏移地址,在这个指令中把NEW_ADDR的段地址送入cs(不用你给出),把它的段内偏移地址送入ip中作为新的偏移地址。
4)段间间接寻址:cs和ip的内容全变化,由指令当中给出的一个4字节连续存储单元,其中低2字节送入ip作为偏移地址,高2字节送入cs作为段地址。
例12:jmpdwordptr+1234h
      jmpdwordptr
      jmpdwordptr
dwordptr是双字(4个字节连续存储单元)操作符,用来指出下面的存储单元是4个字节的。由于它是4个字节的,所以只能使用类似于数据操作数中的存储器寻址方式(共5种,还记得吗?)。


另外作为特殊的寻址方式还有三种:I/O寻址,串寻址,隐含寻址。它们都分别针对I/O指令,串操作指令以及无操作数的指令,而且都比较简单,读者自行总结。


到此为止说明了8086/8088cpu中的所有寻址方式,我这里只是个总结,具体的细节还要大家自己钻研课本,才能理解。
写的有些仓促可能有些遗漏或错误,还请谅解。

一定要记住寻址方式特别重要,这是我“毕生” 的总结,请笑纳,笑纳。


-------------------------------------------------------------------------------------------

-------------------------------------------------------------------------------------------

回复: 286 (这个帖子的作者)

1.最新面的.386是表示运行在386保护模式,而不是运行在386的机器上。
2.CMPXCHG 比较并交换操作数.( 第二个操作数必须为累加器AL/AX/EAX )
3.你的编译器是不是我指定的masm.exe,这个对很多新指令是不是认识的。所以不一定能用。


-------------------------------------------------------------------------------------------

-------------------------------------------------------------------------------------------

关于此贴,请参阅:

原贴]http://www.20cn.net/cgi-bin/club/guest_show.pl?cat=tech&forum=code&page=1&position=3901&id=1103878483

原贴在不断更新中

-------------------------------------------------------------------------------------------

-------------------------------------------------------------------------------------------

5ipyg 发表于 2006-4-20 11:21:26

谢谢了, 收下

huangfei555 发表于 2006-4-23 14:33:48

谢谢,下载收下了!

无为道长 发表于 2006-4-23 19:04:57

谢谢老大.......

huahangyan 发表于 2006-4-28 12:08:41

谢谢,下载收下了! 工具不能下载........

恋·梦尽了 发表于 2006-4-29 01:14:36

系统 大哥 能尽快的更新。
谢谢
页: 1 2 3 4 5 [6] 7 8 9 10 11 12 13 14 15
查看完整版本: [讲座]跟我学汇编