汇编语言学习笔记(三)

0x00 内存定址方法

and&or指令

  • and指令

    逻辑与指令,按位进行与运算。通过该指令可将操作对象的相应位设置为0,其他位不变。

  • or指令

    逻辑或指令,按位进行或运算。通过该指令可将操作对象的相应位设置为1,其他位不变。

以字符形式给出数据

用’……’的方式指明数据是以字符的形式给出的,编译器将把它们转化为相对应的ASCII码。对于用户输入或预先定义的字符,计算机采用ASCII码对其进行编码,将其转化为对应的十六进制信息存储在内存的指定空间中。文本编辑软件从内存中取出该十六进制信息,将其送到显卡的显存中。工作在文本模式下的显卡,用ASCII码的规则解释显存中的内容,显卡驱动显示器将对应字符显示在屏幕上。

大小写转换

一个字母,无论原来是大写还是小写,将其第5位置0,它将变为大写字母;将其第5位置1,它将变为小写字母。从而大小写转换对应的汇编语句如下:

1
2
and al, 11011111B ;将al中的ASCII码的第5位置为0,变为大写字母
or al, 00100000B ;将al中的ASCII码的第5位置为1,变为小写字母

SI&DI

si和di是8086CPU中和bx功能相近的寄存器,si和di不能够分成两个8位寄存器来使用

寻址方式

  • [bx+idata]

    [bx+idata]表示一个内存单元,它的偏移地址为(bx)+idata。指令mov ax,[bx+200]的数字化描述为(ax) = ((ds)*16+(bx)+200)。该指令也常用以下格式:

    1
    2
    3
    mov ax,[200+bx]
    mov ax,200[bx]
    mov ax,[bx].200
  • [bx+si]&[bx+di]

    [bx+si]和[bx+di]含义相似,以前者为例进行说明。[bx+si]表示一个内存单元,它的偏移地址为(bx)+(si)。指令mov ax,[bx+si]的数字化描述为(ax) = ((ds)*16+(bx)+(si))。指令常用格式为:

    1
    mov ax,[bx][si]
  • [bx+si+idata]&[bx+di+idata]

    [bx+si+idata]和[bx+di+idata]含义相似,以前者为例进行说明。[bx+si+idata]表示一个内存单元,它的偏移地址为(bx)+(si)+idata。指令mov ax,[bx+si+idata]的数字化描述为(ax) = ((ds)*16+(bx)+(si)+idata)。指令常用格式为:

    1
    2
    3
    4
    5
    mov ax,[bx+200+si]
    mov ax,[200+bx+si]
    mov ax,200[bx][si]
    mov ax,[bx].200[si]
    mov ax,[bx][si].200

经过对比我们可以得出以下结论:

  • [idata]用一个常量来表示地址,可用于直接定位一个内存单元;
  • [bx]用一个变量来表示内存地址,可用于间接定位一个内存单元;
  • [bx+idata]用一个变量和常量表示地址,可在一个起始地址的基础上用变量间接定位一个内存单元;
  • [bx+si]用两个变量表示地址;
  • [bx+si+idata]用两个变量和一个常量表示地址。

1

汇编语言循环嵌套

以下面的编程题目为例简要说明在汇编语言中如何处理循环嵌套功能。

现要求编写汇编程序,实现将datasg段中每个单词的前4个字母改为大写字母。

汇编语言中循环功能的实现需要cx寄存器的配合,因为该寄存器存放单层循环的循环次数。在多层循环这一情景下,我们可以使用寄存器或内存栈来保存cx中存放的外层循环次数,以便内层循环对该寄存器的重复利用。

完整程序如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
assume cs:codesg,ss:stacksg,ds:datasg

stacksg segment
dw 0,0,0,0,0,0,0,0
stacksg ends

datasg segment
db '1. display '
db '2. brows '
db '3. replace '
db '4. modify '
datasg ends

codesg segment
start: mov ax,stacksg ; 初始化栈相关指针
mov ss,ax
mov sp,16

mov ax,datasg ; 初始化数据段,方便寻址
mov ds,ax
mov bx,0
mov cx,4 ; 由于外层循环需要对4行字符串进行操作,故设置cx为4
s0: push cx ; 将外层循环次数压栈
mov si,0
mov cx,4 ; 由于内层循环需要对每行前4个字母实现大小写转换,故设置cx为4

s: mov al,[bx+3+si]
and al,11011111b ; 完成大小写转换
mov [bx+3+si],al

inc si
loop s ; 重复调用内层循环

add bx,16
pop cx ; 将外层循环次数弹栈
loop s0 ; 重复调用外层循环

mov ax,4c00h
int 21h
codesg ends
end start

0x01 数据处理的两个基本问题

数据处理的两个基本问题为处理数据位置处理数据长度。机器指令必须给出这两个问题明确或隐含的说明,否则计算机无法工作。

我们定义描述性符号regsreg,前者表示一个寄存器,后者表示一个段寄存器。

  • reg集合包括:axbxcxdxahalbhblchcldhdlspbpsidi
  • sreg集合包括:dssscses

bx&si&di&bp

  • 在8086CPU中,只有这4个寄存器可以用在[...]中来进行内存单元的寻址,其他的reg例如ax,bx,cx等出现在[...]中均会报错。

  • [...]中,这4个寄存器可以单独出现,或只能以4种组合出现:bx&sibx&dibp&sibp&di

  • 只要在[...]中使用寄存器bp,而指令中没有显性地给出段地址,段地址就默认在ss中。比如下面的指令:

    1
    2
    mov ax,[bp]          ;含义:(ax) = ((ss)*16+(bp))
    mov ax,[bp+si+idata] ;含义: (ax) = ((ss*16)+(bp)+(si)+idata)

数据位置

机器指令处理数据位置

绝大部分机器指令都是数据处理指令,处理大致可分为3类:读取、写入、运算。机器指令层不关心数据的值是多少,而关心指令执行前一刻,它将要处理的数据所在的位置。指令执行前所要处理的数据可以在3个地方:CPU内部内存端口

汇编语言中数据位置表达

汇编语言中使用3个概念来表达数据的位置。

  • 立即数(idata)

    对于直接包含在机器指令中的数据,在汇编语言中称为立即数,在汇编指令中直接给出。

  • 寄存器

    指令要处理的数据在寄存器中,在汇编指令中给出相应的寄存器名。

  • 段地址(SA)&偏移地址(EA)

    指令要处理的数据在内存中,在汇编指令中可用[X]的格式给出EA,SA在某个段寄存器中。

数据长度

8086CPU的指令,可以处理两种尺寸的数据,即byte和word。所以在机器指令中要指明,指令进行的是字操作还是字节操作。汇编语言采用以下方法处理这一问题:

  • 通过寄存器名指明要处理的数据尺寸。如对ax等16位寄存器执行的指令均为字操作,而对al等8位寄存器执行的指令为字节操作。

  • 在没有寄存器名存在的情况下,用操作符X ptr指明内存单元的长度,X在汇编指令中可以为word或byte。用法举例如下:

    1
    2
    mov word ptr ds:[0],1 ;word ptr指明指令访问的内存单元是一个字单元
    mov byte ptr ds:[0],1 ;byte ptr指明指令访问的内存单元是一个字节单元

    在没有寄存器参与的内存单元访问指令中,用word ptrbyte ptr显性地指明所要访问的内存单元的长度是很必要的。否则,CPU无法得知所要访问的单元是字单元还是字节单元。

  • 有些指令默认了访问的是字单元还是字节单元,例如push指令只进行字操作。

div指令

  • 除数:有8位和16位两种,在一个reg或内存单元中。

  • 被除数:默认放在AX或DX和AX中。

    • 若除数为8位,被除数则为16位,默认在AX中存放。
    • 若除数为16位,被除数则为32位,在DX中存放其高16位,AX中存放其低16位。
  • 结果:默认存放在AX或AX和DX中。

    • 若除数为8位,则AL存储除法操作的商,AH存放除法操作的余数。
    • 若除数为16位,则AX存储除法操作的商,DX存储除法操作的余数。
  • 格式:

    1
    2
    div reg
    div 内存单元
  • 应用举例

    利用除法指令计算100001/100

    1
    2
    3
    4
    mov dx,1
    mov ax,86A1H ; (dx)*10000H+(ax)=100001
    mov bx,100
    div bx

    利用除法指令计算1001/100

    1
    2
    3
    mov ax,1001
    mov bl,100
    div bl
  • 除法溢出

    当CPU执行div等除法指令的时候,如果结果的商过大,超出了寄存器所能存储的范围,将引发CPU的一个内部错误即除法溢出,我们可以通过以下计算方式排除溢出的情况。

    给出公式$ X/N = int(H/N)65536+[rem(H/N)65536+L]/N $,其中

    • X:被除数,范围:[0,FFFFFFFF]
    • N:除数,范围:[0,FFFF]
    • H:X高16位,范围:[0,FFFF]
    • L:X低16位,范围:[0,FFFF]
    • int():描述性运算符,取商。
    • rem():描述性运算符,取余数。

    这个公式将可能产生溢出的除法运算X/N转变为多个不会产生溢出的除法运算。公式中等号右边的所有除法运算都可以用div指令进行,肯定不会导致除法溢出。

mul指令

  • 两个相乘的数必须均为8位或16位。若均为8位,则一个默认放在AL中,另一个放在8位reg或内存字节单元中;若均为16位,则一个默认放在AX中,另一个放在16位reg或内存字单元中。

  • 若进行8位乘法,结果默认放在AX中;若进行16位乘法,结果高位放在DX中,低位放在AX中。

  • 格式

    1
    2
    mul reg
    mul 内存单元

伪指令dd

dd用来定义dword(double word,双字)类型的数据,该关键字定义的数据占两个字的大小。

dup

dup是一个操作符,在汇编语言中和db、dw、dd等数据定义伪指令配合使用,用来进行数据的重复。dup的使用格式如下:

1
2
3
db 重复的次数 dup (重复的字节型数据)
dw 重复的次数 dup (重复的字型数据)
dd 重复的次数 dup (重复的双字型)

0x02 实验7:寻址方式在结构化数据访问中的应用

汇编源程序如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
assume cs:codesg
data segment
db '1975','1976','1977','1978','1979','1980','1981','1982','1983'
db '1984','1985','1986','1987','1988','1989','1990','1991','1992'
db '1993','1994','1995'

dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514
dd 345980,590827,803530,118300,1843000,2759000,3753000,4649000,5937000

dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226
dw 11542,14430,15257,17800
data ends

table segment
db 21 dup('year summ ne ?? ')
table ends

codesg segment
start: mov ax,data
mov es,ax

mov ax,table
mov ds,ax

mov cx,21
mov bx,0 ;locate struct data, add 16 per time
mov si,0 ;locate employee number, add 2 per time
mov bp,0 ;locate year and wage, add 4 per time
s:
; input year data
mov ax,es:[bp+0]
mov ds:[bx],ax
mov ax,es:[bp+2]
mov ds:[bx+2],ax

; input wage data
mov ax,es:54H[bp+0]
mov ds:[bx+5],ax
mov ax,es:54H[bp+2]
mov ds:[bx+7],ax

; input employee data
mov ax,es:0A8H[si]
mov ds:[bx+10],ax

; calculate average wages
mov ax,ds:[bx+5]
mov dx,ds:[bx+7]
div word ptr ds:[bx+10]
mov ds:[bx+13],ax

add bx,16
add si,2
add bp,4

loop s
mov ax,4c00h
int 21h

codesg ends
end start

结果如下:

2

0x03 相关资料

屏幕显示相关

  • 内存地址空间中,B8000H~BFFFFH共32KB的空间,为$80 \times 25$彩色字符模式的显示缓冲区。向这个地址空间写入数据,写入的内容讲立即出现在显示器上。彩色字符模式下,显示器可以显示25行,每行80个字符,每个字符包含256种属性。

  • 每一行种,一个字符占两个字节的存储空间,低位字节存储字符的ASCII码,高位字节存储字符的属性。

  • 显示缓冲区中,偶地址存放字符,奇地址存放字符的颜色属性。

  • 属性字节的格式如下:

    4

补码

补码思想适用于有符号数的表示。首先使用00000000b~01111111b表示0~127,然后将它们按位取反加1后的数据表示负数。补码方案具有以下特点:

  • 最高位为1,表示负数;
  • 正数的补码取反加1后,为其对应的负数的补码;负数的补码取反加1后,为其绝对值;
  • 8位补码所表示的数的范围是-128~127。
请作者吃个小鱼饼干吧