王爽 汇编语言第三版 第9章 转移指令的原理

 

 

 

第九章  转移指令的原理

 

汇编代码:

assume cs:codesgcodesg segments:  mov ax,bx  ; mov ax,bx 的机器码占两个字节mov si, offset smov di, offset s0mov ax, cs:[si]mov cs:[di], axs0:nop  ; nop 机器码占一个字节nopmov ax, 4c00hint 21h
codesg ends
end s

 

 

 

 

9.3 依据 位移 进行 转移的 jmp 指令

 

 

 

 

 

9.5 转移地址寄存器 中的 jmp 指令

 

 

 

9.6 转移地址在内存中的 jmp 指令

 

检测点 9.1 

 

分析:jmp word ptr [bx+1] 为段内转移,要CS:IP指向程序的第一条指令,应设置ds:[bx+1]的字单元(2个字节)存放数据应为0,则(ip)=ds:[bx+1]=0。简单来说就是,只要 ds:[bx+1] 起始地址的两个字节为 0 就可以了。

答案 1:db 3 dup (0)。 答案 2:dw 2 dup (0)。 答案 3:dd 0。 答案 4:dd 16 dup (0)

验证代码:

assume cs:codesg, ds:datasgdatasg segmentdb 16 dup (0)
datasg endscodesg segment
start:	mov ax, datasgmov ds, axmov bx,0jmp WORD ptr ds:[0]mov ax,4c00hint 21h
codesg ends
end start

验证结果截图:

 

程序 2:

第一空参考答案:

mov [bx], bx            ; 因为 bx 为 0,所以可以把 寄存器 bx 值赋值给 内存[bx]
mov [bx], word ptr 0    ; 指定 0 是一个 字类型 0000h,  
mov [bx], offset start  ; 取得 标号 start 相对 cs 段的偏移地址,即 0 

第二空参考答案:

mov [bx+2], cs
mov [bx+2], codesg

验证代码:

; jmp 段 间 转移。转移到 cs:ip 的第一条指令
; 高地址 : 转移的目的段地址
; 低地址 : 转移的目的偏移地址assume cs:codesg, ds:datasgdatasg segmentdd 12345678H
datasg endscodesg segmentstart:mov ax, datasgmov ds, axmov bx, 0mov [bx], WORD ptr 0mov [bx+2], csjmp DWORD ptr ds:[0]mov ax, 4c00hint 21h
codesg ends
end start

运行结果截图:

 

 

 

 

 

实验 8 分析一个奇怪的程序:

https://www.jianshu.com/p/7e5dfea72b65

assume cs:code
code segmentmov ax, 4C00Hint 21Hstart:mov ax, 0000H
s:nopnopmov di, offset smov si, offset s2mov ax, cs:[si]mov cs:[di], ax
s0: jmp short s
s1: mov ax, 0000Hint 21Hmov ax, 0000H
s2: jmp short s1nop
code ends
end start

分析 :

程序的执行流程是这样的 :

; 从 start 标号开始
1. mov ax, 0000H
2. nop
3. nop
4. mov di, offset s
5. mov si, offset s2
6. mov ax, cs:[si]
7. mov cs:[di], ax
8. jmp short s
9. jmp short si ; 这句 jmp short s1 , 根据我们之前的分析 , 指令是用相对偏移来表示的
; 因此执行的操作并不是真的跳转到 s1 这个标号 , 而是跳转编译时确定的 该指令到 s1 标号的偏移
; 所以我们要分析接下来程序的流程的话 , 就必须先编译程序 , 然后要知道到底偏移是多少
; 然后再根据这个偏移确定程序下一步应该执行哪里的指令
; 根据下图的编译结果 , 可以发现 , jmp short s1 在编译后得到的指令是 : 
; 偏移是 : EB F6
; 这个数据是使用 补码 来表示的 , 也就是说 , 是一个负数 , 然后符号位不变 , 其他位取反 , 然后加 1
; 然后 , 我们现在就知道了 , 这条指令是将 ip 的值加上 -10
; 我们再看看 ip - 10 指向的地址是哪里 ? 
; 对 , 刚好就是 code segment 开始的位置
10. mov ax, 4C00H
11. int 21H
; 这样程序就实现了正常的返回

反编译结果 :

注意这里使用 debug 的 u 命令进行反汇编的时候要指定代码段的偏移地址为 0
否则 debug 会自动从 start 标号的地方开始反汇编

可以看到 : 
jmp short s1 ; 这句汇编指令被翻译成了 : EB F6 , 其中 EB 表示的是跳转 , F6 表示偏移
F6 怎么理解呢 ? 
1111 0110 (使用补码来表示)
补码转换成原码 , 符号位不变 , 其他位取反 , 然后加 1
1000 1001
1000 1010 ; 也就是 -10
也就是上面我们分析的让 (ip) = (ip) - 0x0A
然后 , 这句指令被复制到 s 标号的开头处
由于 nop 只占一个字节 , 因此两个 nop 被完全替代
然后程序执行到 s0 , 又跳转到 s 开始的地方
这个时候就要执行 : (这个时候 ip = 8)
EB F6
首先读取这条指令到指令缓存器里
接下来 , (ip) = (ip) + len(EB F6) = (ip) + 8 = 10
然后执行这条指令 , 即为 (ip) = (ip) - 10 = 0
这样 ip 就回到了 code segment 的起始处
这样继续执行 
mov ax, 4C00H
int 21H
就实现了程序的正常返回

说明:这题要是把 s 当成 jmp short s1 那就错了,如果是那样的话 ,你就会想当然的跳到 s1,但其实不是的,前边复制的 是内存里的内容 ,也就是说复制的是 jmp short s1 的机器码 假如机器码是这样的: EB -10(十进制负数先理解嘛~) 也就是向上走10字节, 那么 现在复制到 s 那 也是向上走10 个字节,所以是跳转到 mov ax, 4c00h。

这道题主要理解:程序 只是 复制 内存里面的数据。

 

 

汇编语言是按行一条一条指令进行执行的,可以按高级语言进行缩进来写汇编程序 ( 例如可以按照 Pyhton 的空格缩进 )最后再把缩进给去掉这样可以更好的理解汇编的逻辑和层级关系

 

 

实验 9 

每一个字符占用两个字节 , 低地址为 ASCII 码 ,高地址为属性

示例代码 1:

assume cs:code,ds:data; 显存地址 : B8000H - BFFFFH
; 显示尺寸 : 80 x 25 个字符
;   其中每一个字符占用两个字节 , 低地址为 ASCII 码 , 高地址为属性
;   也就是说 每一个字符 可以设置的属性有 256 种
;   属性 : 
;       是否闪烁 背景色R 背景色G 背景色B 是否高亮 前景色R 前景色G 前景色B
; 因此一个屏幕总共有 80 x 25 = 2000 个字符 , 需要 4000 个字节来存储 (约为4K)
; 然后系统的显存总共是 32K , 也就是说可以储存 8 个页面 , 默认显示第一个页面data segmentdb 'Hello world', 33 ; 33 是感叹号的 ASCII 码 
data endscode segmentstart:mov ax, datamov ds, axmov ax, 0B800Hmov es, ax    ; 保存显存的段地址mov si, 0000H ; 数据段偏移地址mov di, 10*160+80 ; 显存偏移地址mov cx, 000CH     ; 设置循环次数 , "Hello world!" 长度为 12print_green:mov al, ds:[si]   ; 读取数据段中的数据mov ah, 00100000B ; 设置字体的属性 (黑底绿字)mov es:[di], ax   ; 写入显存inc si        ; 数据段偏移地址自增 1 add di, 0002H ; 显存偏移地址自增 2loop print_greenfinish:mov ax,4c00Hint 21Hcode endsend start

运行截图:

示例代码 2:

assume cs:codesg, ds:datasgdatasg segmentdb 'welcome to masm!' ; 显示的字符db 2,24h,71h  ; 字符属性
datasg endscodesg segment
start:; 设置 ds 段mov ax, datasgmov ds, ax; 设置 es 段 为 显存地址段mov ax, 0b800hmov es, ax; 设置循环次数 mov cx, 16mov si, 0         ; 字符的偏移量mov di, 10*160+80 ; 显存的偏移量s:mov al, ds:[si]mov ah, 2        ; 设置字符的属性 为 2mov es:[di], ax  ; 往显存里面写数据inc si     ; 字符向后偏移 1 位add di, 2  ; 显存向后偏移 2 位loop smov ax, 4c00hint 21h
codesg ends
end start

运行截图:

 

实验 9 代码 1:

http://blog.sina.com.cn/s/blog_171daf8e00102xcbv.html

assume cs:codesgdata segmentdb 'welcome to masm!'db 02H,24H,71H        ;字符显示的属性值
data endsstack segmentdb 16 dup(0); 也可以是下面的定义法:; dw 8 dup(0)
stack endscodesg segment
start:  ;初始化data数据段,es:di指向datamov ax, datamov es, axmov di, 0;初始化显示缓冲区,ds:bx指向显示缓冲区。mov ax, 0b800Hmov ds, ax;25行取中是12、13、14行,80列取中开始是61列;12行的偏移量是12*160=1920  (1行总共80个带属性的字符,即 160个字节);总偏移量为(偏移地址)1920+60=1980?mov bx, 1980      mov si, 16    ;字符的属性在数据段中的偏移量                mov ax, stack ;建栈,并初始化栈顶,熟悉栈结构。其实这里都不用人工建栈,有系统自动的。mov ss, axmov sp, 16    ;指向栈顶         mov cx, 3     ;计数器初始化为3(循环显示3次)s:  push cx      ;入栈保护 CX,在stack中       mov cx, 16   ;内循环为16次,16个字符output:      ;将字符写入显存中mov al, es:[di]mov [bx], al;将字符属性写入显存中mov ah, es:[si]mov [bx+1], ah      inc diadd bx, 2loop outputadd bx, 128  ;每行输出的偏移量为128字节 mov di, 0inc sipop cx       ;出栈恢复cx计数器值loop s           mov ax,4c00Hint 21H
codesg ends
end start

运行截图:

总结:

  • 1. 合理利用栈结构保存寄存器变量的值。
  • 2. 熟练掌握[bx+idata]这种CPU寻址的方式。
  • 3. 在显存中,甚至是内存中,它们都是线性存储的,以列的形式存储的。不存在行的概念的,只不过在计算机屏幕上,还有debug中有行的概念,为了显示方便。

示例代码:

https://www.cnblogs.com/nojacky/p/9497704.html

assume cs:code
data segmentdb 'welcome to masm!'db 02h,24h,71h  ; 要求的三个颜色对应的16进制代码
data endsstack segmentdb 16 dup(0); 也可以是下面的定义法:; dw 8 dup(0)
stack endscode segmentstart:  ; 设置data段,以及ds:bx指向data段的第一个单元,; 即ds:[bx]的内容就是data段第一个单元的内容  mov ax,datamov ds,ax;设置显示缓存区段mov ax,0b800h ;设置起始缓存mov es,ax       ;设置栈段mov ax,stackmov ss,axmov sp,10h  ;指向栈顶;初始化三个寄存器mov bx,780h ; 行 从12-14行(注意:从第1行开始计数)mov si,10h ; 颜色的偏移量,三次循环每次; 增加 1h 指向下一个颜色mov cx,3    ; 三次循环改变行s:  mov ah, ds:[si] ;颜色事先存放在ah中push cx     push simov cx, 16  ; 16次循环改变列        mov si, 64  ; 这里的si的意义是多少列,; 为什么从64列开始呢?; (1)字符串为32字节,16字节ASCLL码,16字节属性; (2)每一行有160列,那么余下有 160-32=128列为空白;    要使得字符串居中显示,那么字符串的左边和右边;   都应该是64字节(128/2),而列数是从0开始计数,; 所以左边的64字节为0-63,所以这里偏移量为64mov di,0  s0: mov al,ds:[di] ;将date段中的字符一个一个传入es中mov es:[bx+si],al ; 低位存放字符mov es:[bx+si+1],ah ; 高位存放颜色        add si,2  ;显示缓存区字符ASCII码偏移量为2add di,1  ;data段字符的偏移量,每次加 1         loop s0pop si  pop cx  ;后进先出,先出栈si,再出栈cxadd si,1h  ;指向下一个颜色add bx,0a0h ;指向下一行 160=0a0hloop smov ax,4c00hint 21h
code endsend start

示例代码:

https://www.cnblogs.com/zhenzhenhuang/p/6898813.html

assume cs:codedata segmentdb 'welcome to masm!'db 2,24h,71h
data endsstack segmentdb 16 dup(0)
stack endscode segment
start:mov ax,stackmov ss, axmov sp, 16mov ax,datamov ds,axmov cx,3mov ax,0B800Hmov es,axmov si,10hmov ax,0s:mov ah,ds:[si]push cxpush simov cx,16mov si,0add si,160*10+80mov bx,0mov di,1add di,160*10+80s1:mov al,[bx]mov es:[bx+si],almov es:[bx+di],ahinc bxinc siinc diloop s1pop siinc sipop cxmov dx,esadd dx,0ahmov es,dxloop sfinish:mov ax,4c00hint 21h
code ends
end start

 

实验9 代码 2:

http://www.cppblog.com/Tim/archive/2012/06/04/177420.html

datasg segment ;对80*25的屏幕,每行的字节数为80*2=160.;要求显示在屏幕中间,先计算行和列的偏移;行偏移:(25-3)/2=11.所以显示在第11,12,13行。偏移值分别为1760,1920,2080。计算方法为 行数*160(每行的字节数) 。;列偏移:由于要显示的字符数为16个,所以开始显示的列偏移为(80-16)/2*2=64。dw 1760,1920,2080,64;要显示的字符 16个db 'welcome to masm!';字符属性:第11行显示绿色字,第12行显示绿底红色,第13行显示白底蓝色;在全屏模式下能看到字符的闪烁效果db 82h,0ach,0f9h
datasg endscodesg segment assume cs:codesg, ds:datasg
start:mov ax, datasg ; 设置ds段为datasg数据段mov ds, axmov ax,0b800h ; 设置es段为显存段mov es,ax   mov cx,3 ; 设置外循环3次mov di,0s1: ; 外循环开始, 循环 行  mov ax, dimov bl, 2div bl  ; 16被除数,ax 的高位是余数,低位是商。mov si, axmov ah, [24+si] ;取颜色属性mov si, ds:[6] ;列 ,对应 64mov bp, [di]   ;行 ,分别 对应 1760,1920,2080mov dx, cxmov bx, 0  ; 遍历每一行的字符mov cx, 16   s2:mov al, [bx+8]       ;取字符mov es:[bp+si], al   ;写字符mov es:[bp+si].1, ah ;设置颜色属性inc bxadd si, 2loop s2mov cx,dxadd di,2loop s1mov ax, 4c00Hint 21H
codesg endsend start

运行结果截图:

示例代码:

https://www.lscx.org/2718.html

assume cs:codesg,ds:datasg,ss:stacksgdatasg segmentdb 'welcome to masm!'db 82h,0a4h,0f1h
datasg endsstacksg segmentdb 8 dup (0)
stacksg endscodesg segment
start:mov ax,datasgmov ds,axmov ax,0B86Ehmov es,axmov cx,3mov si,0s1: push cxmov bx,0mov bp,0mov cx,16s:  mov al,ds:[bp]mov es:[bx].40h,almov al,ds:16[si]mov es:[bx].40h[1],alinc bpadd bx,2loop spop cxmov ax,esadd ax,10mov es,axinc siloop s1mov ax,4c00hint 21h     
codesg ends 
end start

 

 

实验9 代码 3:

assume cs:codesg, ds:datasg, ss:stacksgdatasg segmentdb "welcome to masm!"db 2,24h,71h
datasg endsstacksg segmentdb 16 dup(0)
stacksg endscodesg segment
start:mov ax,datasgmov ds,axmov si,10hmov di,1824mov ax,0b800hmov es,ax    mov cx,3
s1:mov bx,0push cxmov cx,16
s:mov al,[bx]mov ah,[si]mov WORD ptr es:[di],axadd bx,1add di,2    loop sinc siadd di,128pop cxloop s1    all:jmp short allmov ax,4c00hint 21h
codesg ends
end start

实验9 代码4:

https://blog.csdn.net/Ryannn_/article/details/84190330

assume cs:code,ds:datadata segment ;在数据段定义字符串db 'Welcome to masm!'
data endscode segment
start:  mov ax,datamov ds,axmov ax,0b800hmov es,ax    ; 使用ds和es寄存器作为段寄存器mov si,0mov bx,0mov bp,07b0h ; 由计算出的字符串所在位置给bp赋值mov cx,16    ; 16个字符数据故loop16次s:  mov al, [bx]                  ; 以下采用相对基址变址寻址方式mov es:[bp+si], al            ; 经计算得第1行偏移地址应为b87b0h至b87cfhmov es:[bp+si+0a0h], al       ; 第2行偏移地址应为b8850h至b886fhmov es:[bp+si+140h], al       ; 第3行偏移地址应为b88f0h至b890fhmov al, 00000010b             ; 分别给三行设置属性字节mov es:[bp+si+1], almov al, 00100100bmov es:[bp+si+0a0h+1], almov al, 01110001bmov es:[bp+si+140h+1], alinc bxadd si,2      ; 每个字符占2个字节loop s     	   mov ah,4chint 21h
code ends
end start

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/495744.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

触摸心灵-触觉感知和发展的模型

来源:计算机触觉触觉感知和发展的模型触觉感知模型是数学结构,试图解释触觉积累关于环境中的物体和试剂的信息的过程。 由于触觉是一种主动的感觉,即感觉器官在感觉过程中被移动,所以这些模型经常描述优化感知结果的运动策略。 触…

MFC 最详细入门教程

From:https://blog.csdn.net/wang18323834864/article/details/78621633/ Visual Studio 2019:https://visualstudio.microsoft.com/zh-hans/ 鸡啄米 ----- VS2010/MFC编程入门教程之目录和总结:http://www.jizhuomi.com/software/257.html …

没中、美这么大的统一市场,欧盟人工智能发展面临双重挑战

来源:澎湃新闻 作者:胡逸涵为在人工智能领域追赶中美两国,近日,欧盟将2020年前对人工智能(AI)的投资额增加约70%,至15亿欧元。欧盟希望到2020年底,整个欧盟在AI技术领域&#xff0…

人生的闲言碎语

1.人的一生 选对老师,智慧一生;选对伴侣,幸福一生;选对环境,快乐一生;选对朋友,甜蜜一生;选对行业,成就一生。 2.头头是道 人生一世,要起好头:…

error LNK2019: 无法解析的外部符号 WinMain,该符号在函数 int __cdecl invoke_main(void)”中被引用

From:https://blog.csdn.net/u012570056/article/details/74639894 一,问题描述 MSVCRTD.lib(exe_winmain.obj) : error LNK2019: 无法解析的外部符号 WinMain,该符号在函数 "int __cdecl invoke_main(void)" (?invoke_mainYAHXZ…

德国人工智能研究中心波尔特:人工智能与工业4.0并驾齐驱

来源:科技日报摘要:2013年德国政府提出的“工业4.0”战略就涵盖了人工智能。“工业4.0”战略着重在制造业等领域相互利用。以深度学习、自我升级为主要特征的人工智能有望将人类各方面智能拓展到极限,从而在各领域做到极致。人工智能的研发在…

C++ 基本数据类型 的 字节数

From:https://www.cnblogs.com/qiumingcheng/p/7824919.html C语言入门经典——基础知识(数据类型):https://blog.csdn.net/weixin_42167759/article/details/80404815 闲聊c/c: 各平台下基本数据类型的字节长度:htt…

协作机器人的江湖:把人放在首位

来源:机器人创新生态 作者:张有凤远离硅谷及亚洲电子产业中心的地方,一个拥有许多灵魂的小创业公司正在掀起波澜。在伊利湖东端,一个由丹麦移民创办的公司正在布法罗市中心的所有地方建造移动计算机。在美国平板制造厂商Bak的厂…

Visual Assist X 安装、使用 和 快捷键

Visual Assist 官网地址:https://www.wholetomato.com visual Assist 快捷键大全:https://blog.csdn.net/dddd0216/article/details/80082885 Visual Assist X的使用:https://jingyan.baidu.com/article/380abd0a4844111d90192c9a.html Vi…

盘点丨毕业年薪34万,高校人工智能研究哪家强?

来源:亿欧网摘要:人才短缺已经成为了制约人工智能技术发展和应用落地的一大短板,为了弥补这一短板,加强人才培养,近日教育部发布了《高等学校人工智能创新行动计划》此前有报道显示,2017年AI工程师平均年薪…

第1章 Hello MFC

微软 MFC 官方文档:https://docs.microsoft.com/zh-cn/cpp/mfc/mfc-desktop-applications?viewvs-2019 MFC 层次结构图以及下载地址:https://docs.microsoft.com/zh-cn/cpp/mfc/hierarchy-chart?viewvs-2019 VC6.0/VS2005/VS2010/VS2012/VS2013/VS201…

产业|MIR睿工业:2018年机器人市场分析报告

来源:Robot未来智能实验室是人工智能学家与科学院相关机构联合成立的人工智能,互联网和脑科学交叉研究机构。未来智能实验室的主要工作包括:建立AI智能系统智商评测体系,开展世界人工智能智商评测;开展互联网&#xff…

用 Python 和 werobot 框架开发公众号

From:用 Python 和 werobot 框架开发公众号:https://www.jianshu.com/p/a517746a900f WeRoBot 官方文档 :https://werobot.readthedocs.io/zh_CN/latest/ Github :https://github.com/offu/WeRoBot Python — WeRobot&#xff0…

专家:智能芯片国际竞争愈发激烈,应尽快制定国家标准

来源: 科技日报摘要:近日,十三届全国政协第一次双周协商座谈会在京召开。会议聚焦的话题是人工智能的发展与对策。夯实基础,提升原始创新能力中科院计算所智能处理器中心主任陈云霁做的就是智能芯片,作为智能芯片公司寒…

easyExcel 使用指南详解

来源:easyExcel 使用指南详解 - 知乎 easyExcel简介 Java领域解析、生成Excel比较有名的框架有Apache poi、jxl等。但他们都存在一个严重的问题就是非常的耗内存。如果你的系统并发量不大的话可能还行,但是一旦并发上来后一定会OOM或者JVM频繁的full g…

(转)Web Services使用多态(XmlInclude) ,支持自定义类型

Web Services使用多态(XmlInclude) 在Web Services方法中,往往使用的都是一个具体类型的参数,这个参数一般就是一个数据对象。ASP.NET Web Services通过声明XmlIncludeAttribute可以实现Web Services方法中运用多态。 XmlIncludeAttribute允许XmlSeriali…

激光破解太空通信难题

来源:新浪科技摘要:虽然目前而言无线电天线仍然是太空通信的支柱,但目前未来发展方向是激光通讯系统。在太空中,没有人会听到你的尖叫——因为声音不会在真空中传播,而且你需要某种类型的无线电波中继携载这些信息&…

Docker 原理、学习教程

Docker 官网 :https://www.docker.com/ Docker Hub:https://registry.hub.docker.com/search?qkali Docker 容器超详细讲解:https://www.linuxidc.com/Linux/2018-08/153712.htm Docker Compose:https://www.runoob.com/docker…

从自动驾驶到基因编辑,这15项发明专利改变了世界

来源:资本实验室近期,中兴通讯受美国制裁的事件戳中了国人心中的“痛”,也对我们长期受制于人的芯片核心技术与产业敲响了警钟。我们近乎被动地发现,在科技创新,尤其是技术驱动型创新方面,我们的差距到底有…

org.dom4j.DocumentFactory cannot be cast to org.dom4j.DocumentFactory

引入cryptofront-2.1.6.jar后dom4j执行异常 解决方案,强制在cryptofront-2.1.6.jar加载前,加载dom4j dom4j引入不完整