汇编知识点2019-04-17

段的综述

  1. 对于数据段,将它的段地址放在DS中,用mov、ADD、sub等访问内 存单元的指令时,CPU就将我们定义的数据段中的内容当作数据来访问;
    对于代码段,将它的段地址放在CS中,将段中的第一条指令的偏移地 址放在IP中,这样CPU就将执行我们定义的代码段中的指令;
    对于栈段,将它的段地址放在SS中,将栈顶单元的偏移地址放在SP中,这样CPU在需要进行栈操作的时候,比如执行PUSH、POP指令等,就将我们定义的栈段当作栈空间来用。
    可见,不管我们如何安排,CPU将内存中的某段内存当作代码,是因CS:IP指向了那里。。。
  2. 汇编语言的源程序包括伪指令与汇编指令。源程序的汇编指令最终由计算机执行,而源程序的伪指令由编译器处理。
    assume:这条伪指令的含义是“假设”,将有特定用途的段和相关的寄存器关联起来。
    标号:一个标号指代一个地址(p79).
    程序返回:一个程序P2在可执行文件中,则必须有一个正在运行的程序P1,将P2从可执行文件中加载到内存中,将CPU的控制权交给P2,P2才得以运行。P2开始运行后,P1暂停运行。而当P2运行完毕后,将CPU的控制权交还给P1,此后,P1继续运行。。所以,一个程序结束后,将cpu的控制权交还给使它得以运行的程序,称这个过程为程序返回,如何返回:在程序的末尾段添加返回的程序段:
mov ax,4c00H
int 21H

这俩条指令实现的功能就是程序返回

汇编程序执行的过程:
编译--->连接--->加载(command程序)(送入内存中)--->运行(CPU)

利用debug对程序执行过程的跟踪(P91)

当CS:IP指向程序的入口,command就放弃了对CPU的控制权,CPU立即开始运行程序,直到程序结束,但debug对cpu的控制还在,所以可以用debug实现对程序的跟踪.

【BX】、【LOOP】指令 2019-06-01

inc bx:bx中的内容加1

mov bx,1
inc bx

执行后,bx = 2

LOOP:

LOOP指令的格式:LOOP+标号,CPU执行LOOP指令的时候,要进行俩步操作:①(cx)=(cx)-1 ②判断cx中的值,不为零则转至标号处执行程序,为零则向下执行(一般在cx中存放循环次数)
用cx和LOOP指令相配合实现循环功能的程序框架如下:

mov cx,循环次数
s:循环执行的程序段
loop s


A(97h)a(65H)
1、mov AX, [ BP] 在求物理地址时 为什么使用ss为段地址而不使用DS为段地址
===
===>这是设计cpu时默许的设置方式,必须遵守。
BX、SI和DS配合适用;DI和ES配合使用;BP和SS配合使用。 AX、CX、DX通常不用来作为偏移地址。AX为累加器,CX为计数器,dos的有些功能调用也用DX存放有效地址。


OFFSET 返回的是偏移地址EA的地址
立即数不能给段寄存器
##
CX:cx中的值影响LOOP指令的执行结果,cx中存放循环次数
在源程序中,数据不能以字母开头(eg:0A003)

  1. debug调试后r查看寄存器时,cx中存放的是程序的长度(字节)
  2. debug执行“g 0012”后,CS:0012前的程序段被执行
    在遇到t调试后出现LOOP 0012时,用P命令会使debug自动重复执行循环中的指令,直到cx=0(代替多个单步执行t)===>也可以用g 0016直接执行到cs:0016处
  3. 在源程序中,如果用指令访问一个内存单元,则在指令中必须用【】来表示内存单元,如果在【】里用一个常量idata直接给出内存单元的偏移地址,就要在【】的前面显式地给出段地址所在的段寄存器 eg:
mov al,ds:【0】

.如果没写段寄存器,编译器masm将把指令的【idata】解释为idata
.如果在【】里用寄存器,比如bx,间接地给出了内存单元的偏移地址,则段地址默认在ds中,也可以显式地表示出段寄存器
0:200~0:2FF的内存空间相对安全的
通过在源程序中定义段来进行内存空间的获取(p123)
在程序中,段名就相当于一个标号,它代表了段地址,一个段中的数据的段地址可由段名代表,偏移地址就看它在段中的位置(p131)

data segment
'
data ends
,
mov ax,data
mov ds,ax
mov bx,ds:[6]

cpu若要访问data段中的数据,则用ds指向data段,用其他寄存器存放data段中的偏移地址(如bx)(p132)

  • 在没有寄存器存在的情况下,用 (Word byte 、ptr)指明内存单元的长度
  • push指令对字操作
  • ax div除法指令隐含(被除数在ax中,(如果除数是8位)结果al存商,ah存余数)(如果除数是16位,结果ax存商,dx存余数)
  • ax/al/eax 用作累加器,指令有(in,out,XLAT)
  • 一个汇编语言源程序中有哪三种基本语句:)指令语句-----有与其对应的机器指令
    (2)伪指令-----没有与其对应的机器指令,只是指示汇编程序如何处理
    (3)宏指令---
  • mov al,5(al是目的操作数(src),5是源操作数(drs))
  • SHL(逻辑左移),SAL(算术左移),SHR,SAR-----》SAL ax,1(左移一位,如果是俩位或更多位,用CL表示)
  • 一个代码段的起始偏移地址是0.



debug的常用命令

DEBUG命令有很多,介绍一些经常使用的DEBUG命令。

(1) 反汇编命令 U

格式: a. U [ 段地址 ]:[ 偏移地址 ]

b. U [ 地址范围 ]

功能:将指定范围内的代码以汇编语言形式显示,同时显示该代码位于内存的地址和机器码。若在命令中没有指定地址,则以上一个 U 命令的最后一条指令地址的下一个单元作为起始地址;若没有输入过 U 命令,则反汇编32个字节;即为代码段的起始32个字节单元内容。如下图所示:

[图片上传失败...(image-225540-1555939749851)]

图2-10 DEBUG中U命令的使用

其中反汇编中的第一行内容的含义如下:0CF2:0000为代码段的段地址和偏移地址;B8F10C为第一条有效指令的机器码;MOV AX,0CF1为反汇编后的指令形式。

范围可以由起始地址、结束地址(只能包含地址偏移量)或起始地址及长度来指定。其命令格式如:U 0CF2:0000 0008或U 04BA:0000 L7 。

(2)显示内存命令 D

格式: a. D [ 地址 ]

b. D [ 地址范围 ]

c. D

功能:显示指定内存范围的内容。

显示的内容为两种形式:一种为十六进制内容,一种为与十六进制相对应的 ASCII 码字符,对不可见字符以“·”代替。对于格式a 、 c 每次显示 128 个字节内容, 格式b 显示的字节数由地址范围来决定。

若命令中有地址,则显示的内容从指定地址开始,若中中无地址(如格式 c )则从上一个 D 命令所显示的最后一个单元的下一个单元开始。若以前没有使用过 D 命令,则从代码段的起始单元开始显示。 若格式中的地址只有偏移地址,则段地址为 CS 的内容。其命令格式如:D 0CF1:0000 或 D 或 D 0080 ,其使用如图2-10所示。

[图片上传失败...(image-b6e012-1555939749851)]

图2-11 DEBUG中D命令的使用

(3)修改存储单元内容命令 E

格式: a. E [ 地址 ] [ 内容表 ]

b. E [ 地址 ]

功能: 格式a用命令所给定的内容表去代替指定地址范围的内存单元内容。

格式b一个单元一个单元地连续修改单元内容。

其中:内容表为一个十六进制数,也可以是用单引号括起的一串字符。其命令格式如:

E 0CF1:0000 ‘*******’ 或 E 0CF1:0010 ,其使用如图2-11所示。

[图片上传失败...(image-7db1b8-1555939749850)]

图2-12 DEBUG中E命令的使用

(4) 检查和修改寄存器内容命令 R
格式: a.R 例如-r

b.R [ 寄存器名] 例如:-r ax 显示ax中的内容。再输入数据x,将ax的值改为x。

功能: a. 显示 CPU 内部所有寄存器的内容和全部标志位的状态。

b. 显示和修改一个指定寄定器的内容和标志位的状态。

让cpu执行段地址是1500,偏移地址是1300的地址所在的指令。则:

1-r cs 显示cs值。再输入1500.

2 然后-r ip 显示ip的值。输入1300即可。

3可以-r查看

其中对状态标志寄存器 FLAG 以位的形式显示,显示时,8个状态标志的显示次序和符号如表 2-1 所示。 其使用如图2-12所示。

图2-13 DEBUG中R命令的使用

(5) 跟踪与显示命令 T

格式: a. T[ =地址 ] 或 T [ 地址 ] (必须有****=

b. T[ =地址 ][ 条数 ] 或 T [ 地址 ][ 条数 ]

功能: a. 执行一条指定地址处的指令,停下来,显示 CPU 所有寄存器内容和全部标志位的状态,以及下一条指令的地址和内容。

b. 为多条跟踪命令,从指定地址开始;若命令中用 [ 地址 ] 给定了起始地址,则从起始地址开始,若未给定,则从当前地址( CS:IP )开始,执行命令中的 [ 条数 ] 决定一共跟踪几条指令后返回 DEBUG 状态。

 [图片上传失败...(image-c308ab-1555939749850)]

图2-14 DEBUG中T命令的使用

上图中第一次输入T =0000 2 代表从偏移地址0000开始执行2条指令,其后分别显示了两条指令执行后的寄存器及下一条将要执行的指令,其地址分别为0CF2:0003和0CF2:0005;

第二次输入T命令后,接着上面的指令继续执行下一条指令,即地址为0CF2:0005的指令,并显示其执行后的寄存器内容,最后一行显示下一条将要执行的指令,其地址为0CF2:0009。

(6) 运行命令 G

格式: G [ =地址 ][ 地址 [ 地址… ]]

功能:执行用户正在调试的程序。

其中地址为执行的起始地址,以 CS 中内容作为段地址,以等号后面的地址为偏移地址。再后面的地址为断点地址。在命令行中只有起始地址,没有断点地址,则程序在执行时不中断。 DEBUG 规定最多设置 10 个断点地址。设置多个断点用于调试较大的程序,即程序中有多个模块、多个通路时用,比较方便,在执行时不论走哪条通路,程序都可以在断点处停下来,以便调整程序。

断点地址为程序中断处的偏移地址,段地址在 CS 中。

当执行在 DEBUG 状态下汇编的小段程序时,只用 G 命令即可。例1-1执行的效果如下图所示:

[图片上传失败...(image-c0cc61-1555939749849)]

图2-15 DEBUG中G命令的使用

(7) 汇编命令 A

格式: a. A [ 段寄存器q名 ]:[ 偏移地址 ]

b. A [ 段地址 ]:[ 偏移地址 ]

c. A [ 偏移地址 ]

d. A

功能:用该命令可以将汇编语言程序直接汇编进入

若在调试目标程序的过程中,要求改写或增添一段目标程序,则可以用A命令直接在Debug下实现。

当键入 A 命令后,显示段地址和偏移地址等待用户键入汇编指令,每键入一条汇编指令回车后,自动显示下一 条指令的段地址和偏移地址,再键入下一条汇编指令,直到汇编语言程序全部键入,又显示下一地址时可直接键入回车返回到提示符“-”为止。

其中 a 的段地址在段地址寄存器中,因此在使用该命令时必须将段地址寄存器送入段地址, c 的地址在 CS 中, d 的段地址在 CS 中,偏移地址为 100H 。

[图片上传失败...(image-cda818-1555939749849)]

‘’

图2-16 DEBUG中A命令的使用

从上图可以看到我们可以直接输入汇编指令,并且常用的数据定义指令也可以通过A命令直接写入。

(8)结束 DEBUG 返回到 DOS 命令 Q

格式: Q

功能:程序调试完退出 DEBUG 状态,返回到 DOS 状态下。

五、汇编程序提示的常见错误

1、在MASM编译时产生警告错误“out of memory”能够忽略吗?

答: 这种问题一般是程序中的标点符号用的全角状态的输入,或是中文状态的输入;把程序中的标点在英文半角状态下重新输入一遍,就可以了。

2、在MASM编译时产生警告错误“Operand types must match”能够忽略吗?

答: 不能,如语句:MOV AL, BX就会产生上述错误信息,原因是AL和BX两个操作数的字长不匹配。

3、在MASM编译时为什么产生警告错误“Operand must have size”?

答:如果有类似:MOV [SI+1], 10H的语句会产生此类错误,应改为:MOV BYTE PTR[SI+1],10H。因为目标操作数为存储器,源操作数———立即数应指明字长是8位还是16位,若目标操作数为寄存器则不需要。

4、在编译时为什么产生警告错误“Reserved word as symbol:XXXXXX”?

答:指的定义数据或定义符号的名字时使用了保留字。如在数据段中出现了:LENGTH DW 256 这样的定义时就会产生警告,因 LENGTH 是取值运算符,作为保留字不应标识名字。

5、在编译中指出某行产生“Immediate mode illegal”错误是什么原因?

答:指立即数出现在非法的指令形式中,举例来说,如果在数据段定义有:LENG EQU 1000H; 在代码段中有:LEA BX, LENG这样的语句即会出现这类错误,因为EQU伪指令使得编译时将代码中所有的LENG符号用立即数1000H替代,而指令:LEA BX, 1000H是非法的。

6、在程序中有语句:JC NEXT, 引起编译错误“Jump out of range by 18 byte(s)”,如何解决?

答:指条件转移语句超出范围,8088汇编规定条件转移语句的转移范围在:-128 ~ +127个字节以内,若转移距离超过这一范围,应配合使用无条件转移语句。原代码可改为:JNC L1 / JMP NEXT / L1: ……………./ 。

7、在程序中定义了数据段,并且以 VAR命名的表中设有0…..9十个数据,为什么开始的语句:MOV AL, VAR执行结果不正确?

答:如果代码段起始没有将数据段基址赋给DS寄存器,将会产生此类运行错误,因段基址不是所设定的数据段的基址。

8、有数据段定义:DATA SEGMENT / ………. / DATA ENDS /,语句

MOV AX , DATA 和 MOV AX, SEG DATA含义相同吗?

答: 不,前者是取得DATA 段的基地址,后者是指取DATA变量所在段的基地址。如果DATA已定义为数据段的名字,再定义为变量或表的名字会产生编译错误

9、在数据段中设定名为BUF1的表中存有字符串 ’Hello ctec!’,后设名为BUF2的表长度为11个字符,初始值设0,在代码段中使用串传送指令实现BUF1——BUF2的传送,没有发现语法和控制结构的错误,为什么结果不对?

答:如果控制结构和指令形式都没有错,就要检查是否定义ES段,MOVS指令要求源指针为DS : [SI],目的指针为ES : [DI],因此应定义ES段;当然,DS段和ES段可为同一个段。

10、实验程序中设有宏定义:

DOSF MACRO FUNNO / MOV AH, FUNNO INT 21H / ENDM / ,其中的参数FUN_NO代表什么含义?

答:FUN_NO是宏定义中的形式参数,宏应用时用实际参数替代,此例中实际参数可以是立即数。

11、在程序中有这样的语句:MOV AX, 8000H / MOV BL,4 / DIV BL / 运行时报告算术溢出,为什么?怎样解决?

答:除法指令DIV规定,如果除数字长为8位,商的字长超过了8位二进制数的表示范围则为溢出。上文中被除数为8000H,除数为4,结果:2000H 超过了8位二进制数,即产生溢出错误。为避免这种情况,可采用移位或减法指令替代除法指令。

12、为什么语句:LEA AX, ADDR 是正确的,而MOV BL, [AX]是错误的?

答:前者是取值语句,功能是将ADDR的偏移地址值送到寄存器AX;后者将AX寄存器作为间接寻址寄存器使用,这在8086/8088指令中是不允许的。

13、利用9号DOS功能调用显示一个字符串,为什么会显示乱码?

答:常见的情况是定义字符串缺少结尾标志“”,功能子程序执行时找不到结尾,更正办法是在定义的字符串后面加“”或ASCII码形式的24H。

14、在Windows2000和WIN_XP的运行程序窗口中不出现数字结果怎么办?

答:1.首先保证显示数字为标准ASCII码;

2.设置运行程序的属性为:全屏幕显示,退出时不关闭窗口。

15、实现两个BCD码表示的十进制数如34 和 56相加,要求输出BCD码结果;为什么输入数据应为34H和56H?

答:BCD码是由四位二进制数码表示一个十进制数字,十进制数34用BCD码表示为00110100B,写为十六进制数即34H; 而加法计算的实际结果为十六进制数34H与56H相加的结果,故需要调整指令DAA将其调整为预期结果的BCD码:90H。

16、 使用DOS功能调用2号功能显示数字,有语句:/ MOV DL, CL /MOV AH, 2 /INT 21H /

为什么显示不出结果?

答:参数DL应放置数字的ASCII码,而不是数字本身,以上程序中,若CL内是0 ~ 9的数值,应添加语句:ADD DL, 30H。

17、使用算术右移指令SAR移位一次,会影响OF吗?

答:在MASM宏汇编环境中不会,因为算术右移不改变符号位,符号位被复制到下一位,故最高位和次高位相等,而判断是否溢出的条件是双高位不相等,OF不会被置1。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。