[078][汇编语言]实验16 另一种解法

实验16 简单解法

实验16 另一种解法

代码参考 :使用offset计算偏移地址

实际运行

实验16.png

完整源码

  • 安装程序
assume cs:code
code segment
    start:  ;------ 安装功能程序到 0000:0200H 开始 --------
            mov ax,cs
            mov ds,ax
            mov si, offset setscreen
            
            mov ax,0
            mov es,ax
            mov di,200H
            mov cx,offset setscreenend - offset setscreen
            cld
            rep movsb

            ;------ 在中断向量表 N = 7CH 号表项处写入 
            ;       中断处理程序的入口地址0000:0200h -----
            mov ax,0
            mov es,ax
            mov word ptr es:[7CH*4],200H
            mov word ptr es:[7CH*4+2],0
            
            
            mov ax,4c00H
            int 21H
         

            ;org 200h  
    ;---------- 7CH 号中断处理程序本身 ---------     

    ; 用ah传递功能号,0-清屏 1-设置前景色 2-设置背景色 3-向上滚动一行
    setscreen:  jmp short set
        table   dw offset sub1 - offset setscreen + 200H,offset sub2 - offset setscreen + 200H,offset sub3 - offset setscreen + 200H,offset sub4 - offset setscreen + 200H
        set:    push bx
                push si
                
                cmp ah,3
                ja sret
                mov bl,ah
                mov bh,0
                add bx,bx
                
                mov si,offset start - offset setscreen
                call word ptr table[si+bx+200H]
        
        sret:   pop si
                pop bx
                iret
                
    ; 清屏,将幸存中当前屏幕中的字符设为空格符
    sub1:   push bx
            push cx
            push es
            mov bx,0B800H
            mov es,bx
            mov bx,0
            mov cx,2000
    sub1s:  mov byte ptr es:[bx],' '
            add bx,2
            loop sub1s
            pop es
            pop cx
            pop bx
            ret
            
    ; 设置前景色 用al传送颜色值
    sub2:   push bx
            push cx
            push es
            
            mov bx,0B800H
            mov es,bx
            mov bx,1
            mov cx,2000
    sub2s:  and byte ptr es:[bx],11111000B
            or es:[bx],al
            add bx,2
            loop sub2s

            pop es
            pop cx
            pop bx
            ret
            
    ; 设置背景色 用al传送颜色值            
    sub3:   push bx
            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:[bx],10001111B
            or es:[bx],al
            add bx,2
            loop sub3s
            pop es
            pop cx
            pop bx
            ret
    ; 滚动一行:依次将第n+1行的内容复制到第n行;最后一行为空
    sub4:   push cx
            push si
            push di
            push es
            push ds
            
            mov si,0B800H
            mov es,si
            mov ds,si
            mov si,160      ; ds:si指向第n+1行
            mov di,0        ; es:di指向第n行
            cld
            mov cx,24
    sub4s:  push cx
            mov cx,160
            rep movsb
            pop cx
            loop sub4s
            
            mov cx,80
            mov si,0
    sub4s1: mov byte ptr [160*24+si],' '
            add si,2
            loop sub4s1
            
            pop ds
            pop es
            pop di
            pop si
            pop cx
            ret
                    
    setscreenend:   nop
    

    code ends
    end start
  • 测试程序
assume cs:code
code segment
begin:  
        mov ah,2
        mov al,00001001B    ;   闪烁 背景R G B 高亮 前景R G B
        int 7CH
        
        mov ax,4c00h
        int 21H
        
code ends
end begin

代码说明

  • 代码片段
    setscreen:  jmp short set
        table   dw offset sub1 - offset setscreen + 200H,
                   offset sub2 - offset setscreen + 200H,
                   offset sub3 - offset setscreen + 200H,
                   offset sub4 - offset setscreen + 200H
        set:    push bx
                push si
                
                cmp ah,3
                ja sret
                mov bl,ah
                mov bh,0
                add bx,bx
                
                  mov si,offset start - offset setscreen
                call word ptr table[si+bx+200H]
                
        
        sret:   pop si
                pop bx
                iret
  • 先说 table[X] 的含义
由于在安装程序里写了 assume cs:code
所以  table[X] 本质上是 cs:N[X] 

首先明确,执行中断程序时我们期望 cs=0000H,这样才能指向中断向量表,
但是安装程序本身执行时 cs 是什么我们并不知道,不妨假设安装时 cs = 076AH;

N是什么?
N 等于 076A:setscreen  减去  076A: start   所得的偏移量 + 2
这个2 来自于 setscreen标号后那一条jmp指令,这条jmp指令的机器码长度是2

用代码计算就是  = offset setscreen - offset start + 2
这里的 setscreen 和 start 都是安装程序的标号

【注意:为了和测试程序区分开来,我在测试程序用的是 begin】

对N而言,无论安装时cs=076AH 还是 cs=6666H,N的值都不变的,就是一个固定的偏移值
也是说,如果你要用table,你要知道 【它背地里给你多加了个N】
  • 再看 table 里存着什么? 答,子程序的入口地址。


    实验16 setscreen table 里存着什么.png

    table 本质上存的是子程序的入口地址
 table   dw offset sub1 - offset setscreen + 200H,
                   offset sub2 - offset setscreen + 200H,
                   offset sub3 - offset setscreen + 200H,
                   offset sub4 - offset setscreen + 200H

本质上存的就是 0222H 023DH 025BH 027DH 
这些都是后面子程序 sub1 sub2 sub3 sub4 的入口地址的偏移地址

  mov si,offset start - offset setscreen
  call word ptr table[si+bx+200H]
                

si 添什么乱? si 不是添乱,si 是用来中和背地里的N的
si = start - setscreen
N = setscreen - start + 2

si + N = 2

因为  table [X]  = CS:N[X] = CS:[N+X]
所以 table[X+si] = CS:N[X+si] = CS:[X+2]

在我们的代码里面用的是  table[si+bx+200H]
bx = 功能号 x 2 = ah的值 x 2
取值范围是{0,2,4,6}

结合上面的图表,我们可以看见
假设现在 ah = 2 要调用 sub3 子程序,
计算出来 bx = ah x 2 = 4

table[si+bx+200H] = cs:N[si+bx+200H] = cs:[2+bx+200H] 中和掉N
= cs:[2+4+200H] 
此时是执行中断处理程序,CS = 0000H,即 CS:[206H] = 0000:0206H
按照上面的图表,内存地址 0000:0206H 存着的一个字型单元是 025BH
接着CPU就转去执行CS:025BH了,这就实现了调用 sub3 子程序。

可见table[si+bx+200H] 里面的200H是为了寻址用的,
这个地址是子程序入口地址的内存单元地址

总结,table[si+bx+200H] 
(1)si 是为了中和看不见的 N ,带来结果 si + N = 2 (2源自jmp指令的2个机器码长度)
(2)200H 是为了寻找子程序入口地址的内存单元地址 。

那么为什么要用setscreen 减去 start

用标号start 本质上是想找到 code segment 之后的第一句代码,
计算看不见的N需要的本质不是start,
而是code segment之后的第一个机器码的偏移地址,也就是code段的开始。

因为assume cs:code是与code段关联的,
我们要找的N是相对于code段的开始。


如果start 之前还有东西,就还要加上那些东西占用的内存单元。

验证猜想

安装时,第一条指令 对应标号 start 偏移地址是 0000H.png

2、标号setscreen 与标号start 偏移地址的偏移量之差是002DH.png

3、table[bx+si+200H]被解读.png
  • table[si+bx+200H] 被解读成 CS:N[si+bx+200H]
table[si+bx+200H] 
= CS:N[si+bx+200H] 
= CS:[N+si+bx+200H]
= CS:[bx+022FH]

本程序中
N = 002D H + 2  = 002FH
= setscreen 距离 start的偏移量 + jmp指令的2个机器码

感想

之前写int 7ch中断处理程序,都是把完成安装的复制部分、中断处理本身割裂开来的,这次的实现则有一点不同,必须看到code段的首句以start标号开头,这就是代码段的开始,前方没有db dw dd 之类占着内存的东西了,这个影响着后面计算N,这次的代码是揉在一起的,受苦。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容