直接定址表
(到106楼的时候,现在中文打字的速度早已经超过100字以上/每分钟了~:)
描述单元长度的标号
例程:将 code 段中的 a 标号处的 8 个数据累加,结果存储到 b 标号处的字中。
程序中,code、a、b、start、s 都是标号,它们仅仅表示了内存单元地址。
数据标号:除了表示内存单元的地址,还表示了内存单元的长度,即表示在此标号处的单元,是一个字节单元还是字单元,还是双字单元)。
使用这种包含单元长度的标号,可以使我们以简洁的形式访问内存中的数据。
它标记了存储数据的单元的地址和长度。
它不同于仅仅表示地址的地址标号。
反汇编上面代码:
下面程序将 code 段中 a处的8个数据累加,结果存储到b处的dword中,补全程序。
在其他段中使用数据标号
在其他段中,我们也可以使用数据标号来描述存储数据的单元和长度。
在后面加有 “:” 的地址标号,只能在代码段中使用,不能在其他段中使用。
将 data 段中 a 标号处的 8 个数据累加,结果存储到 b 标号处的字中。
如果想在代码段中,直接用数据标号访问数据,则需要用伪指令 assume 将标号所在的段和一个段寄存器联系起来。
否则编译器在编译的时候,无法确定标号的段地址在哪一个寄存器中。
seg 操作符,功能为取得某一标号的段地址。
将 data 段中 a 处的 8 个数据累加,结果存储到 b 处的字中,补全程序。
直接定址表
编写程序,以十六进制的形式在屏幕中间显示给定的 Byte 型数据。
利用表,在两个数据集合之间建立一种映射关系,可以用查表的方法根据给出的数据得到其在另一集合的对应数据。
1) 为了算法的清晰和简洁
2) 为了加快运算速度
3) 为了使程序易于扩充
程序入口地址的直接定址表
可以在直接定址表中存储子程序的地址,从而方便实现不同子程序的调用。
实现一个子程序 setscreen,为显示输出提供如下功能:
1) 清屏
2) 设置前景色
3) 设置背景色
4) 向上滚动一行
入口参数说明:
1) 用ah寄存器传递功能号:
0 表示清屏
1 表示设置前景色
2 表示设置背景色
3 表示向上滚动一行
2) 对2、3号功能,用al传送颜色值。(AL)={0,1,2,3,4,5,6,7}
各种功能的实现:
1) 清屏: 将显存中当前屏幕中的字符设为空格符
2) 设置前景色: 设置显存中当前屏幕中处于奇地址的属性字节:0、1、2位
3) 设置背景色: 设置显存中当前屏幕中处于奇地址的属性字节:4、5、6位
4) 向上滚动一行: 依次将第n+1行的内容复制到第n行处;最后一行为空。
编写包含多个功能子程序的中断例程
安装一个新的 int 7ch 中断例程,为显示输出提供如下功能子程序:
1) 清屏
2) 设置前景色
3) 设置背景色
4) 向上滚动一行
入口参数说明:
1) 用 ah 寄存器传递功能号:
0 表示清屏
1 表示设置前景色
2 表示设置背景色
3 表示向上滚动一行
2) 对于2、3号功能,用 al 传递颜色值,(al)={0,1,2,3,4,5,6,7}
遇到一个问题,在上面代码的 int 7ch 子程序的注解处。
暂时解决不了,不知道哪个宏指令可以让编译器认为 table 要从 200h 处为基址计算偏移(实际 table 应为 202h)。
关于数据标号与地址标号的区别分析
分析过程
当操作数据标号时,是在操作数据标号所示地址中的内容,它也代表长度。
如果 inc 它,则是在 inc 数据标号所示地址中的内容的值递增。
当操作地址标号时,是在操作它的偏移量。
[ Last edited by redtek on 2007-1-18 at 01:42 PM ]
(到106楼的时候,现在中文打字的速度早已经超过100字以上/每分钟了~:)
描述单元长度的标号
例程:将 code 段中的 a 标号处的 8 个数据累加,结果存储到 b 标号处的字中。
assume cs:code
code segment
a: db 1,2,3,4,5,6,7,8
b: dw 0
start: mov si,offset a
mov bx,offset b
mov cx,8
s: mov al,cs:
mov ah,0
add cs:,ax
inc si
loop s
mov ax,4c00h
int 21h
code ends
end start
程序中,code、a、b、start、s 都是标号,它们仅仅表示了内存单元地址。
数据标号:除了表示内存单元的地址,还表示了内存单元的长度,即表示在此标号处的单元,是一个字节单元还是字单元,还是双字单元)。
使用这种包含单元长度的标号,可以使我们以简洁的形式访问内存中的数据。
它标记了存储数据的单元的地址和长度。
它不同于仅仅表示地址的地址标号。
assume cs:code
code segment
a db 1,2,3,4,5,6,7,8
b dw 0
start: mov si,0
mov cx,8
s: mov al,a
mov ah,0
add b,ax
inc si
loop s
mov ax,4c00h
int 21h
code ends
end start
反汇编上面代码:
0B49:000A BE0000 MOV SI,0000
0B49:000D B90800 MOV CX,0008
0B49:0010 2E CS:
0B49:0011 8A840000 MOV AL,
0B49:0015 B400 MOV AH,00
0B49:0017 2E CS:
0B49:0018 01060800 ADD ,AX
0B49:001C 46 INC SI
0B49:001D E2F1 LOOP 0010
0B49:001F B8004C MOV AX,4C00
0B49:0022 CD21 INT 21
下面程序将 code 段中 a处的8个数据累加,结果存储到b处的dword中,补全程序。
assume cs:code
code segment
a dw 1,2,3,4,5,6,7,8
b dd 0
start: mov si,0
mov cx,8
s: mov ax,a
add word ptr b,ax
adc word ptr b,0
add si,2
loop s
mov ax,4c00h
int 21h
code ends
end start
在其他段中使用数据标号
在其他段中,我们也可以使用数据标号来描述存储数据的单元和长度。
在后面加有 “:” 的地址标号,只能在代码段中使用,不能在其他段中使用。
将 data 段中 a 标号处的 8 个数据累加,结果存储到 b 标号处的字中。
assume cs:code , ds:data
data segment
a db 1,2,3,4,5,6,7,8
b dw 0
data ends
code segment
start: mov ax,data
mov ds,ax
mov si,0
mov cx,8
s: mov al,a
mov ah,0
add b,ax
inc si
loop s
mov ax,4c00h
int 21h
code ends
end start
如果想在代码段中,直接用数据标号访问数据,则需要用伪指令 assume 将标号所在的段和一个段寄存器联系起来。
否则编译器在编译的时候,无法确定标号的段地址在哪一个寄存器中。
assume cs:code , ds:data
data segment
a db 1,2,3,4,5,6,7,8
b dw 0
data ends
seg 操作符,功能为取得某一标号的段地址。
将 data 段中 a 处的 8 个数据累加,结果存储到 b 处的字中,补全程序。
assume cs:code , ds:data
data segment
a db 1,2,3,4,5,6,7,8
b dw 0
data ends
code segment
start: mov ax,data
mov ds,ax
mov si,0
mov cx,8
s: mov al,a
mov ah,0
add b,ax
inc si
loop s
mov ax,4c00h
int 21h
code ends
end start
-d ds:0
0B49:0000 01 02 03 04 05 06 07 08-24 00 00 00 00 00 00 00
直接定址表
编写程序,以十六进制的形式在屏幕中间显示给定的 Byte 型数据。
assume cs:code
code segment
start: mov al,0abh
call showbyte
mov ax,4c00h
int 21h
showbyte: jmp short show
table db '0123456789ABCDE'
show: push bx
push es
mov ah,al
shr ah,1
shr ah,1
shr ah,1
shr ah,1
and al,00001111b
mov bl,ah
mov bh,0
mov ah,table
mov bx,0b800h
mov es,bx
mov es:,ah
mov bl,al
mov bh,0
mov al,table
mov es:,al
pop es
pop bx
ret
code ends
end start
利用表,在两个数据集合之间建立一种映射关系,可以用查表的方法根据给出的数据得到其在另一集合的对应数据。
1) 为了算法的清晰和简洁
2) 为了加快运算速度
3) 为了使程序易于扩充
程序入口地址的直接定址表
可以在直接定址表中存储子程序的地址,从而方便实现不同子程序的调用。
实现一个子程序 setscreen,为显示输出提供如下功能:
1) 清屏
2) 设置前景色
3) 设置背景色
4) 向上滚动一行
入口参数说明:
1) 用ah寄存器传递功能号:
0 表示清屏
1 表示设置前景色
2 表示设置背景色
3 表示向上滚动一行
2) 对2、3号功能,用al传送颜色值。(AL)={0,1,2,3,4,5,6,7}
各种功能的实现:
1) 清屏: 将显存中当前屏幕中的字符设为空格符
2) 设置前景色: 设置显存中当前屏幕中处于奇地址的属性字节:0、1、2位
3) 设置背景色: 设置显存中当前屏幕中处于奇地址的属性字节:4、5、6位
4) 向上滚动一行: 依次将第n+1行的内容复制到第n行处;最后一行为空。
assume cs:code
code segment
start: mov ah,0 ; 调 segscreen 子程序的 0 号功能 - 清屏
call segscreen
mov ah,1 ; 调 segscreen 子程序的 1 号功能 - 设前景
mov al,1
call segscreen
mov ah,2 ; 调 segscreen 子程序的 2 号功能 - 设背景
mov al,7
call segscreen
mov ah,3 ; 调 segscreen 子程序的 3 号功能 - 上滚一行
mov al,4
call segscreen
mov ax, 4c00h
int 21h
segscreen: jmp short set ; 所有子功能调用索引表 (入口)
table: dw sub1, sub2, sub3, sub4
;----------------------------------------------------
; 0清屏 1设前景 2设背景 3上滚一行
;----------------------------------------------------
set: push bx
cmp ah,3 ; 判断功能号是否大于3
ja sret
mov bl,ah
mov bh,0
add bx,bx ; 根据ah中的功能号计算对应子程序在table表中的偏移地址
call word ptr table ; 调用对应的功能子程序
sret: pop bx
ret
sub1: push bx ; 0号子功能: 清屏
push cx
push es
mov bx,0b800h
mov es,bx
mov bx,0
mov cx,2000
sub1s: mov byte ptr es:,' '
add bx,2
loop sub1s
pop es
pop cx
pop bx
ret
sub2: push bx ; 1号子功能: 设置前景色
push cx
push es
mov bx,0b800h
mov es,bx
mov bx,1
mov cx,2000
sub2s: and byte ptr es:,11111000b
or es:,al
add bx,2
loop sub2s
pop es
pop cx
pop bx
sub3: push bx ; 2号子功能: 设置背景色
push cx
push es
mov cl,4
shl al,cl
mov bx,0b800h
mov es,bx
mov bx,1
mov cx,2000
sub3s: and byte ptr es:,10001111b
or es:,al
add bx,2
loop sub3s
pop es
pop cx
pop bx
ret
sub4: push cx ; 3号子功能: 屏幕向上滚动一行
push si
push di
push es
push ds
mov si,0b800h
mov es,si
mov ds,si
mov si,160 ; 从第 n+1 行传送到第 n 行
mov di,0
cld
mov cx,24 ; 共传送屏幕 24 行数据
sub4s: push cx
mov cx,160
rep movsb
pop cx
loop sub4s
mov cx,80
mov si,0
sub4s1: mov byte ptr ,' '
add si,2
loop sub4s1
pop ds
pop es
pop di
pop si
pop cx
ret
code ends
end start
编写包含多个功能子程序的中断例程
安装一个新的 int 7ch 中断例程,为显示输出提供如下功能子程序:
1) 清屏
2) 设置前景色
3) 设置背景色
4) 向上滚动一行
入口参数说明:
1) 用 ah 寄存器传递功能号:
0 表示清屏
1 表示设置前景色
2 表示设置背景色
3 表示向上滚动一行
2) 对于2、3号功能,用 al 传递颜色值,(al)={0,1,2,3,4,5,6,7}
assume cs:code
code segment
;************************************************************
; int7ch 安装代码
;************************************************************
start: mov ax,cs
mov ds,ax
mov si,offset int7ch
mov ax,0
mov es,ax
mov di,200h
mov cx,offset int7ch_end - offset int7ch
cld
rep movsb
mov word ptr es:,200h
mov word ptr es:,0
mov ax,4c00h
int 21h
;************************************************************
; int7ch 中断例程
;************************************************************
int7ch: jmp short set
;table dw sub1,sub2,sub3,sub4 ; table = 202h
; 编译器在编译的时候认为 table 是上面(中断安装程序)的 cs 地址,
; 而无法定位 table 在 200h 的基础上的偏移,所以暂时先Debug出子程序偏移填入 :(
table dw 021dh, 0238h,0256h,0278h
set: push bx
cmp ah,3
ja sret
mov bl,ah
mov bh,0
add bx,bx
call word ptr cs:.202h
sret: pop bx
iret
sub1: push bx ; int 7ch 0 号子功能:清屏
push cx
push es
mov bx,0b800h
mov es,bx
mov bx,0
mov cx,2000
sub1s: mov byte ptr es:,' '
add bx,2
loop sub1s
pop es
pop cx
pop bx
ret
sub2: push bx ; int 7ch 1 号子功能:设置前景色
push cx
push es
mov bx,0b800h
mov es,bx
mov bx,1
mov cx,2000
sub2s: and byte ptr es:,11111000b
or es:,al
add bx,2
loop sub2s
pop es
pop cx
pop bx
ret
sub3: push bx ; int 7ch 2 号子功能:设置背景色
push cx
push es
mov cl,4
shl al,cl ; al=xxx0000b
mov bx,0b800h
mov es,bx
mov bx,1
mov cx,2000
sub3s: and byte ptr es:,10001111b
or es:,al
add bx,2
loop sub3s
pop es
pop cx
pop bx
ret
sub4: push cx
push ds
push es
push si
push di
mov si,0b800h
mov ds,si
mov es,si
mov si,160 ; 0-159 = 第1行, 160 = 第2行第0列
mov di,0
cld
mov cx,24 ; 处理 24 行
sub4s: push cx
mov cx,160 ; 要复制一行的内容,共160字节
rep movsb
pop cx
loop sub4s
mov cx,160 ; 清除最后一行内容,因其已复制到上一行了。
sub4s1: mov byte ptr ,' '
add si,2
loop sub4s1
pop di
pop si
pop es
pop ds
pop cx
ret
int7ch_end: nop
code ends
end start
遇到一个问题,在上面代码的 int 7ch 子程序的注解处。
暂时解决不了,不知道哪个宏指令可以让编译器认为 table 要从 200h 处为基址计算偏移(实际 table 应为 202h)。
;table dw sub1,sub2,sub3,sub4 ; table = 202h
; 编译器在编译的时候认为 table 是上面(中断安装程序)的 cs 地址,
; 而无法定位 table 在 200h 的基础上的偏移,所以暂时先Debug出子程序偏移填入 :(
关于数据标号与地址标号的区别分析
start: jmp short do0
top dw 0
top2: dw 0
do0: mov bx,top
mov ax,offset top2
分析过程
C:\Masm50>debug noname.exe
-r
AX=0000 BX=0000 CX=003D DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B49 CS=0B49 IP=0000 NV UP EI PL NZ NA PO NC
0B49:0000 EB04 JMP 0006
-u
0B49:0000 EB04 JMP 0006
0B49:0002 0000 ADD ,AL
0B49:0004 0000 ADD ,AL
0B49:0006 2E CS:
0B49:0007 8B1E0200 MOV BX,
0B49:000B B80400 MOV AX,0004
0B49:000E B001 MOV AL,01
0B49:0010 8800 MOV ,AL
0B49:0012 2E CS:
0B49:0013 FF060200 INC WORD PTR
0B49:0017 2E CS:
0B49:0018 8B1E0200 MOV BX,
0B49:001C B002 MOV AL,02
0B49:001E 8800 MOV ,AL
-t
AX=0000 BX=0000 CX=003D DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B49 CS=0B49 IP=0006 NV UP EI PL NZ NA PO NC
0B49:0006 2E CS:
0B49:0007 8B1E0200 MOV BX, CS:0002=0000
-t
AX=0000 BX=0000 CX=003D DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B49 CS=0B49 IP=000B NV UP EI PL NZ NA PO NC
0B49:000B B80400 MOV AX,0004
-t
AX=0004 BX=0000 CX=003D DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B49 CS=0B49 IP=000E NV UP EI PL NZ NA PO NC
当操作数据标号时,是在操作数据标号所示地址中的内容,它也代表长度。
如果 inc 它,则是在 inc 数据标号所示地址中的内容的值递增。
当操作地址标号时,是在操作它的偏移量。
[ Last edited by redtek on 2007-1-18 at 01:42 PM ]
Redtek,一个永远在网上流浪的人……
_.,-*~'`^`'~*-,.__.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._
_.,-*~'`^`'~*-,.__.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._
