汇编语言
- 汇编语言-基础知识01
- 汇编语言的组成-基础知识02
- 指令和数据-基础知识03
- 基础知识04
- 基础知识05
- 第三章 寄存器(内存访问)03
- mov add sub 指令
- 小结
- 字的传送
- 寄存器(内存访问)
- 引言
- 内存中字的存储
- 3.2 DS 和【address】
- 字的传送
- 课后题
- 问题3.8
- 3.9
- 问题3.10
- tips
- 栈的综述
- 3.10 栈段
- 问题3.11
- 问题3.12
- 第一个程序!!
- 一个源程序从写出到执行得过程
- 编写汇编源程序
- 可执行文件
- 源程序
- assume
- 源程序中的程序
- 程序返回
- dos中的程序运行
- 段结束,程序结束,程序返回
- 语法错误和逻辑错误
- 关于编译和链接
- 第四章第一个程序03
- 可执行文件中的程序装入内存并运行的原理
- 程序执行过程的跟踪
- 4.9 程序执行过程的跟踪
- 5.1[bx]
- 5.1【bx】
- 5.2 Loop指令
- 5.2 loop指令
- 在debug中跟踪用loop指令实现循环程序
- 温故而知新
- Debug和汇编编译器masm对指令的不同处理
- 示例
- loop和[bx]的联合应用
- 5.6 段前缀
- 一段安全的空间
- 5.8 段前缀的使用
- 改进的程序的分析
- 第六章 包含多个段的程序
- 引言
- 6.1再代码段中使用数据
- 解释dw
- 6.2 在代码段中使用栈
- 监测点6.1
- 6.3 将数据,代码,栈,放入不同的段
- 实验五, 编写,调试具有多个段程序
- 引言
- 没有目录的目录
- 7.1 and 和 or指令
- and指令的一点功能
- or指令
- or指令的一点功能
- ASCII码
- 关于ascii码表续
- 以字符形式给出的数据
- 大小写转换的问题
- 7.5[bx+idata]
- 问题7.1
- 7.6 用[bx+idata]的方式进行数组的处理
- SI和DI
- 问题7.2
- [bx+si] 和[bx+di]
- 问题7.4
- 7.9[bx+si+idata] [bx+di+idata]
- 问题7.5
- 7.10 不同的寻址方式的灵活应用
- 问题7.6
- 问题7.7
- 问题7.7 分析
- 问题7.8
- 问题7.9
- 第八章引言
- 8.1 bx si di bp
- 机器指令处理的数据所在位置
- 汇编语言中数据位置的表达
- 8.4 寻址方式
- 寻址方式总结
- 动画演示
- 指令要处理的数据有多长
- 在没有指明寄存器名存在的情况下,用操作符X ptr 指明内存单元的长度
- 其他方法
- 8.6 寻址方式的综合应用
- div 指令
- 8.8 伪指令dd
- 问题8.1
- dup
- 引言
- 操作符offset
- 问题9.1
- 9.2 jmp指令
- 9.3 依据位移进行转移的jmp指令
- 汇编指令与机器码的对应示例
- 9.4 转移的目的地址在指令中的jmp指令续
- 程序9.3
- 转移地址在寄存器中的jmp指令
- 转移地址在内存中的jmp指令有两种格式
- 监测点 9.1
- 9.7jcxz指令
- 监测点 9.2
- 9.8 loop指令
- 监测点9.3
- 第九章 04 失踪了QAQ
- 第十章 call和ret指令
- 10.1 ret 和 retf
- 分析源码
- 监测点10.1
- 10.2 call指令
- 监测点10.2
- 10.4 转移的目的地址在指令中的call指令
- 监测点10.3
- 10.5 转移地址在寄存器中的call指令
- 监测点10.4
- 10.6 转移地址在内存中的call指令
- 监测点 10.5
- 10.7 call和ret的配合使用
- 10.7 call和ret的配合使用 2
- 10.8 mul指令
- 10.9 模块化程序设计
- 10.10 参数和结果传递的问题
- 10.11 批量数据的传递
- 10.12 寄存器冲突问题
- 实验十 编写子程序
- 实验十讲解~
- 实验十 3
- 目录
- 引言
- ZF标志
- 11.2 PF标志
- 11.3 SF标志
- 监测点11.1
- 11.4 CF标志
- 11.5 OF标志
- 监测点11.2
- 11.6 adc指令
- 编程任务
- adc论调
- sbb指令
- cmp指令
- cmp指令 有符号数
- 检测比较结果的条件转移指令
- 编程训练
- 检测比较结果的条件转移指令
- 监测点11.3
- DF 标志 和串传动指令
- DF 标志和串传送指令
- pushf和popf
- 监测点11.4
- 第十二章 内中断 01
- 引言和简介
- 中断处理程序
- 中断向量表
- 监测点12.1
- 中断过程
- 中断处理程序
- 除法错误中断的处理
- 编程处理0号中断
- 编程处理0号中断(2)
- 单步中断
- 响应中断的特殊情况
汇编语言-基础知识01
因为他是在硬件上面的编程语言,效率高
比汇编更低级的就是i机器语言
MOV 把后面的传给前面
寄存器,是cpu中存储数据的器件,一个cpu有多个寄存器
汇编语言,对吧,给了编译器。
C语言先编汇编,再变成编
汇编语言的组成-基础知识02
只有与或非,只认识01
+ 一个与 一个 或
汇编的核心是汇编指令
jump 啦之类的
cpu和内存的关系
1.5 指令和数据
1.6 存储单元
1.7 cpu对存储器的读写
BUS 叫做总线
不单止内存条,网卡内存条,等等都行
写入
指令和数据-基础知识03
因为有三总线,所以就能把指令和数据很好的区分开来
我们拆开总线看看,
地址总线-------一定会被转成地址
64位的cpu,64位的操作系统,64位的软件,才能进行64位
要不然都会向下继承,变成32了
地址总线
他是 1011 看的时候肯定是从高位到低位对吧,
然后,他就会定位到1011这个地址去
宽度也就可以说他多少位
内存单元就是一个Byte
1 byte =8bit
一位就是一个数据
64位就能走8个字节喽,
数据总线
地址总线是来确定位置
数据总线越宽,高速公路越快呗
举个例子,这个89D8 数据如何传输?
8088cpu 每次传输8位
这个是D8
小的传过去,1101 1000
再把高位传过去 1000 1001
8086cpu 一次是16位
一次全部传输,
1101100010001001 数据宽度不断增加,使得cpu 越来越快
二级缓存,寄存器的增加,越来越快
控制总线
对吧,对越多端口进行控制
粗略理解一下,第一个,控制显示器,第二个控制内存之类的
小总结
基础知识04
每一个cpu都有自己的指令集,固定的几个就是处理什么的,他就不需要进行运算了,加快了速度
(3)有了cpu,必须要有数据交换的场所,也就是内存,也就是cpu的缓存,
怎么区分不同的数据呢?放在不同的总线上,就是不同的数据。/不同的指令
存储单元从0 进行存储
一个存储单元可以存储 8 位
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1yjFXNRx-1625713417928)(https://gitee.com/dingpengs/image/raw/master/imgmac//20210707225223.png)]
管脚都可以和总线相连
地址总线的宽度决定了cpu的寻址能力
数据总心啊的宽度决定了cpu与其他器件一次的数据传输量
控制线的宽度决定了cpu对系统中其他器械的控制能力
课后题
8kb ==8 *1024 B ==2^3. 2^10. 一共十三
第五题,二的十几次就完了,
1024 /4 除以他一次传输的即可
基础知识05
内存地址空间(概述)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QjGwMTPj-1625713456330)(https://gitee.com/dingpengs/image/raw/master/imgmac//20210708094603.png)]
主板
接口卡
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hjoLFdvz-1625713456334)(https://gitee.com/dingpengs/image/raw/master/imgmac//20210708095108.png)]
cpu不能直接控制外部设备,而是通过接口进行操控,
网卡,对吧cpu控制网卡,然后和网线进行交流
各类存储器的芯片
存储器就是四个轮胎,c pu是马达
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uyWto7oR-1625713456335)(https://gitee.com/dingpengs/image/raw/master/imgmac//20210708095246.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KEwHxsxO-1625713456336)(https://gitee.com/dingpengs/image/raw/master/imgmac//20210708102718.png)]
寄存器CPU工作原理
8086之后都是x86
cpu 概述
一个cpu由运算器,逻辑控制器,寄存器,器件构成,也是靠总线相连,有内部总线。
寄存器概述,
8086cpu 有14个寄存器,
他可以和存储器进行配合工作,x相加
把111放在 AX中
把2222 放在BX中
运算器,将ax bx相加,存在cx中
他有8个通用寄存器,他们增加的寄存器也就是对浮点数的优化,
通用寄存器不能修改,否则会影响系统。
x86 系列,的通用寄存器,都是16位,能存两个字节
32位CPU 的话就是 EAX 他的AX和上面还是一样的
16位寄存器的存放情况
00000000010010
因为是从0开始算的,所以,我们需要-1
16位是跨时代的产物,8位不行,
段地址+偏移量
他需要向下兼容,不然就会被淘汰
AX 可以分为AH和AL AH高位,AL低位
人分高低,【狗头】
只要是8位的,直接AH填0
兼容之前的系统,
全写0
这俩都是独立使用的
单独的需要一个一个看,
合起来的话就一起看
字在寄存器中的存储
一次读取16 位就是字
一个字节 8 位
一个字 就是 两个字节
如果是每个字节,他就是两个,
如果是字,他就是一个16位,也就是20000
关于数制的讨论
数制,只有01010101011010101 我们不喜欢二进制,
人类习惯于16进制
16进制 一个就能打四个
8进制的话 一个能打三个
bin 一般放的源码,源程序
binary
几条汇编指令
== 汇编指令不区分大小写 ==
mov AX,18
mov 78 送进ax的高位
add 增加,把8加到AX中,
逗号,是从后面往前面的,对吧
思考题
相加,满16进1对吧
但是他超了,超了16位,但是,还在,AX中只能存放044c
第二道思考题
分了al ah
不是 0185H
al 和ah没关系,就算超了也不会填到ah中
他只有0058
如果这里写成ax,这儿就是0158H
分开看的话,就会抛出去
,如果这么容易丢弃进制值,他就会很容易造成溢出
监测点2.1
F4A3h
31A3H
3123H
ax 6246h
6246
第二问:mov ax ,0002h
add ax,ax
add ax,ax
add ax,ax
2.4 物理地址
对,他访问物理地址,他就是一个一维,一直延申对把
16位结构的CPU
8086 外部又20个地址总线,能够寻址 1M
内部为16位,只能送16 2 ^16 = 64kb
16 位 段地址,16 位偏移地址,通过加法器,
地址加法器 工作原理
×16 就是向左移动一位
二进制移动4位 十六进制移动一位对吧
二进制左移一位,成2
十六进制左移一位,成16
十进制 成10
成16 是左移4 位
短地址*16+偏移地址=物理地址本质含义
第一个,直接给物理地址
第二个,放不下,闹成了,基础地质+偏移地址
因为放不下,所以这么干
2.8 段的概念
因为是无奈之举,内存并没有被分段!!
可以认为一个段,也可以认为两个段,他是强加给他的,
但是总体还是一个,
段时看需要而定,CPU的话,他就是整一个开始,
tips
一个段的长度最长就是2^16
能够偏移的最大也就是64k
CPU访问内存单元,必须向内存听过内存单元的物理地址
8086CPU在内部用段地址和便宜地址移位相加,最终形成物理地址。
思考小问题
一个物理地址是固定的,他有很多条路通向他
条条大路通罗马对吧
跟破解一些东西,有相似之处
偏移地址16 位,最多也就是64k对吧
对吧,也就是,定段地址,直接左移动一个,那就是1000h~1ffffh
没有小结的小结
同时还有两种描述方法
监测点2.2
第一个:
0010H +0000H
0010H + ffffH == 1000fh
第二个
SA * 16
20000H == x + SA *16
x最小0000 sa极最大,2000H
x最大ffff。 sa 就最小。 1001h
1001 因为,20000 -ffff /16。 有余数的话+1
第三问:
小于1000h
段寄存器
8086有四个段寄存器,
code sixx 代码段地址寄存器
data 数据段
si 堆栈段
extra 附加段地址寄存器
CS和IP
IP是cpu内部偏移地址寄存器
他俩特别关键,他俩指示了当前读取指令的地址。
CS和IP合成20位的地址,通过输出输入电路
地址总线输出,
找到内存20000
然后他这个地址包含了三个字节,
因为mov 指令需要有三个字节
拿到他的数据
B82301
B8 是 mov
从下往上看 0123H
放入指令缓冲器执行之后,就AX覆盖儿了
同时IP进行了修改+3
没有数据的,只要两个就能完成,
有数据的必须要三个
8080PC简要描述
如果,这样的话,我们可以将 木马,放在 内存 杀软之前,对吧,就可以先加载你的木马,再加载杀软
CS和IP
如果内存中有被执行过,肯定被csip指向过
我们只能对寄存器做手脚,对吧,通过修改寄存器中的内容,进行控制
通过控制csip
就能控制他执行的目标指令的地址
mov指令, 被称传送指令,mov可以改变csip的值?
当然不行,8086提供了更改好的修改csip值的指令
转移指令
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jlz7wL5y-1625821081806)(…/…/AppData/Roaming/Typora/typora-user-images/image-20210709161909016.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kZmk1QFV-1625821081806)(…/…/AppData/Roaming/Typora/typora-user-images/image-20210709161938449.png)]
想要同时修改csip的内容,
那就是
jmp 短地址:偏移地址
第一个 2AE33
第二个 0B46H
合法寄存器就是 通用寄存器
jmp ax
首先,mov ax , 200h
然后就是,jmp ax 也就是 jmp 200h的意思
jmp bx
答案
代码段
两个十六进制 可以代表一个字节
如何使得代码段中的指令被执行
csip指向,即能执行
不能拿ds来指定,因为他会被认为成数据
csip指向的就会被认为指令!
暴力破解
跳过注册阶段,csip指向之后
小截
cs,ds,ss,es,
或许,如果,指向 ,一个图片,他也是0101 他会认成其他的汇编指令,就会造成报错
监测点
实验一
debug,调试工具,也可以进行写程序
程序是调出来的,
win10 没有debug
有20多个个指令,本次实验就六个指令
R
R ax
1111
会改成 1111
修改 IP cs
-t 执行一条指令
怎么看呢?
1400 1111 0000 这四个没内容所以是0000
D命令查看内容
成功改值
修改ip,cs,查看内容,然后执行
b440
实验任务
E 和A
E: 改写内存的内容
A 以汇编格式 在内存中写一条机器指令
现在内存的情况
将这些写入,
mov很明现,他跳了三个,对把
没值,跳了两个
-d 找到我们输入的地方
-u展示成汇编
正如我们刚刚闹得地方
我们把csip指到程序的开始
用T 命令执行,看内存
很明显,ax覆盖了他
下一条,ax加了1416对吧
然后bx变成了2000
其他任务
发现直接指不行,我们用jmp跳过去
好像不用,直接
ax变8了
-a 直接改写
寄存器(CPU工作原理07)
-t 执行一条命令,对吧,需要先拿-r 修正一下cs 和ip
方便跳转过去
2^8
需要16禁制,
不断执行即可
试图改改看?
-d ffff0:0
直接看就可以,它翻译成了ASCII码
范围
-e 往内存里写数据,
-a 往内存里写指令
这俩其实是一样的,对应的一个地址对吧。
同时因为,rom bios 寄存器内,一般改写不了
。
09 年 1月 19 日
第四题
突然出现了一个红桃,砖块,
B8100 他是一个 显卡,显存的地址,改成啥他的屏幕就会变
一般用masm,别用ida,熟练了以后,可以用masm
宁可学windows api 编程,也别学mfc。他是工具!!!!
寄存器(内存访问)
第三章讲的是,寄存器和内存的互动
目录~
一个字就是两个字节,对吧,也就是8位
DS 数据段寄存器 和【address】 他是偏移地址
字的传送
mov, add, sub 相减的指令
数据段
栈:特别好的发明,(栈溢出),造成了不少漏洞
栈顶越界的问题么,~
push pop 指令,两个对栈的操作
引言
内存中字的存储
想要存放20000 这个数据
4e20
高位对应高地址
低位对应低地址
高地址,存放, 高地址对吧,存了4e
0地址单元,存放的字节型数据是多少?
以字节为单位,一个单元存放的一个字节,那就是20H他存的数据是32
0地址字单元中,存放的字型数据是多少?
(4E20)
2地址字单元中存放的字节型数据是多少?
**单元或者是字节单元,他说的是一个框,而,字单元,他说的是两个框 **
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hV7aZkQj-1626070563009)(https://gitee.com/dingpengs/image/raw/master/imgmac//20210711162920.png)]
一个结论
3.2 DS 和【address】
ds存放的是段地址
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dPEVWmzP-1626070563010)(…/Library/Application Support/typora-user-images/image-20210711163243734.png)]
mov al,【0】
ds只会读取地址,而不是数据
mov a l,[0]
就是把,偏移地址为0的内容送到al寄存器
我们这样做的话,
1000h 移动到bx
bx 移动到ds
ds中有了段地址,
然后mov al,「0」
他就会自动将 段地址的,第零个偏移地址,给了al
【0】。也就是上面那个
总体解释
那么问题来了,如何把1000H 送入ds
我们不能把地址,直接传给ds,我们必须要通过通用寄存器,才能将,地址传给ds,他CPU设了限制
不支持将数据直接存入段寄存器
硬件设计的问题
数据 -》 通用寄存器〉段寄存器
从,寄存器送入内存单元!!!
当然,图中是错的!!!!!!
mov。bx ,1000h
是将内存单元的内容送到寄存器了,现在是需要将寄存器的内容送到内存单元中
目测肯定需要一波ds喽~~
结论!!
字的传送
前两行,段地址,
那么,为什么不是么,字节类型呢?
因为ax是16位的啦
如果是ax 的话么,他【0】 默认存过去的就是16位的数据
那么高位存放到1001。
低位存放到1000
问题3.3
ax 填入 1000h
然后段地址改为了1000h
然后
将 10000h中的值给了ax
ax值为 1123
bx值为6622
cx值为2211
加到bx。 6622+2211
加到cx。 2211 +6622
主要是注意,ax 他是 两个 字节,一个字
字的传送
写一波例题
-e 直接存进来
把指令写进去
把值输入到里面
我来脑子调试一波
ax 1000h
ds 1000
ax 等于 11316(2c34)
11316 填入 1000 0
10000h 34
10001h 2c
bx == 2c34
bx = 2c34-1122
实际情况,如下
输入完成以后,来冲
bx 也是2C34
SUB 相当于 bx = bx -【2】
存储方式也是如上面所说
第三章 寄存器(内存访问)03
mov add sub 指令
mov的形式
mov 的五种形式 第六种如下,也可以的
推测
覆盖完成,可以
很多指令,用多了就会了,
汇编金手指 查就行了
em,我这里报错了,你们呢?
最早是8位,然后就是一个字节
出现了16位,就是出现了字(CPU)
出现了32位,就是出现了双字(cpu)
现在道乐64位,就出现了四字
和我想的一样对吧~
add ax,[0]
add ax,[2]
add ax,[4]
ax,0书上错了刚
小结
小甲鱼另一种形式报错了
但是这样可以
mov ax,2000,【x】
字的传送
写一波例题
-e 直接存进来
把指令写进去
把值输入到里面
我来脑子调试一波
ax 1000h
ds 1000
ax 等于 11316(2c34)
11316 填入 1000 0
10000h 34
10001h 2c
bx == 2c34
bx = 2c34-1122
实际情况,如下
输入完成以后,来冲
bx 也是2C34
SUB 相当于 bx = bx -【2】
存储方式也是如上面所说
寄存器(内存访问)
第三章讲的是,寄存器和内存的互动
目录~
一个字就是两个字节,对吧,也就是8位
DS 数据段寄存器 和【address】 他是偏移地址
字的传送
mov, add, sub 相减的指令
数据段
栈:特别好的发明,(栈溢出),造成了不少漏洞
栈顶越界的问题么,~
push pop 指令,两个对栈的操作
引言
内存中字的存储
想要存放20000 这个数据
4e20
高位对应高地址
低位对应低地址
高地址,存放, 高地址对吧,存了4e
0地址单元,存放的字节型数据是多少?
以字节为单位,一个单元存放的一个字节,那就是20H他存的数据是32
0地址字单元中,存放的字型数据是多少?
(4E20)
2地址字单元中存放的字节型数据是多少?
**单元或者是字节单元,他说的是一个框,而,字单元,他说的是两个框 **
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iPiCMqwA-1626169233338)(https://gitee.com/dingpengs/image/raw/master/imgmac//20210711162920.png)]
一个结论
3.2 DS 和【address】
ds存放的是段地址
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RLt8XFW7-1626169233340)(…/Library/Application Support/typora-user-images/image-20210711163243734.png)]
mov al,【0】
ds只会读取地址,而不是数据
mov a l,[0]
就是把,偏移地址为0的内容送到al寄存器
我们这样做的话,
1000h 移动到bx
bx 移动到ds
ds中有了段地址,
然后mov al,「0」
他就会自动将 段地址的,第零个偏移地址,给了al
【0】。也就是上面那个
总体解释
那么问题来了,如何把1000H 送入ds
我们不能把地址,直接传给ds,我们必须要通过通用寄存器,才能将,地址传给ds,他CPU设了限制
不支持将数据直接存入段寄存器
硬件设计的问题
数据 -》 通用寄存器〉段寄存器
从,寄存器送入内存单元!!!
当然,图中是错的!!!!!!
mov。bx ,1000h
是将内存单元的内容送到寄存器了,现在是需要将寄存器的内容送到内存单元中
目测肯定需要一波ds喽~~
结论!!
字的传送
前两行,段地址,
那么,为什么不是么,字节类型呢?
因为ax是16位的啦
如果是ax 的话么,他【0】 默认存过去的就是16位的数据
那么高位存放到1001。
低位存放到1000
问题3.3
ax 填入 1000h
然后段地址改为了1000h
然后
将 10000h中的值给了ax
ax值为 1123
bx值为6622
cx值为2211
加到bx。 6622+2211
加到cx。 2211 +6622
主要是注意,ax 他是 两个 字节,一个字
课后题
段地址,是害羞的!
问题3.8
Mov ax,1000h
Mov ss,ax
Mov sp,0010H
mov ax,001Ah
mov bx,001Bh
push ax
Push bx
Mov ax,0
mov bx,0
pop bx
Pop ax
如果是系统中,他比较喜欢xor ax,ax。异或 一样为0 不一样为1
相当于放到栈里,保存了一下,然后取出来接着用~
出入栈顺序相反~
3.9
mov ax,1000
mov ss,ax
Mov sp 0010h
mov ax,002a
mov bx,002b
Push ax
push bx
Pop ax
Pop bx
这不就交换了吗~
问题3.10
push 分为两个步骤
先➖2在放进去
高级语言,这些事情都是由编译器来做的(防止栈溢出)
tips
sp 修改的是偏移地址,~
一个栈最大是64kb喽~
栈的综述
也就是写内存
也就是读内存
所以我们可以骗他对吧~
栈,非常重要~~~
3.10 栈段
根据需要,自己定义段 就数据段,代码段一样
我们能讲 一段,起始地址为16的倍数,ji的内存单元 当栈
CPU只认识 ss:sp 栈顶,cpu 其他不管!
他只认push pop
问题3.11
ss=1000h
sp=ffffh
也不是+2,而是指向他下一个单元
sp=0000
就比如 10000h-----1000fh
栈顶~~~~·0010h
他最底部的字单元,就是ffffeh
问题3.12
栈段最大多少?
64kb么
2^16
超了64kb就会覆盖原来的内容
早期,堆栈用来保存返回的地址
(栈 临时存放东西)
方便函数调用
调用完以后,局部变量就不见了,被释放了
cpu 一条线
|
|
|
|
|
|
都是我们自己安排的
相当于10000 -----10001f
栈和他代码段重复了!!!1
数据段也重复了!!!!!1
监测点3.2
首先,数据段寄存器变成了1000
mov ax,2000h
mov ss,ax
mov sp,10h
第二题
mov ax,1000h
mov sp,ax
mov ss,0000h
第一个程序!!
运行exe
一个源程序从写出到执行得过程
编写汇编源程序
nodepad就行啦~
可执行文件
连接之后就会生成可执行文件
首先都是初始化,对吧,把机器码和数据载入内存,然后初始化,(比如设置cs:ip指向第一个要执行的指令,然后cpu执行
首先,写源代码,程序
然后 编译链接起来
然后再由我们执行
源程序
assume cs:codesg
codesg(代码 段)segment
start 开始
codesg ends
end
h
除了汇编指令其他就是伪指令
最终不被cpu执行
编译器是识别伪指令的,
segment和ends 是成对使用的伪指令。是必须要用到的一对伪指令
如果足够小的话,可以把点exe改成点com,(只有一个段那种,也是可以执行的)
end 是真正的没了
最后的伪指令
不要记混这几个!!!!
assume
假如,假设,(含义为假设)
assume 假设,代码段寄存器,叫 codesg,当然也可以改名字!
源程序中的程序
也就是,由计算机最终执行的指令或者结果
伪指令: 编译器处理的,那里结束哪里开始,哪里指向cs,哪里指向栈段
汇编指令 可以直接编译为机器码
编译后的,哪些程序是程序
源程序经过编译,变成程序
编译完后成为PE文件
如果不确定pe头,那他肯定估计就一堆机器码,啥也找不到
中间灰色是编译器
## 标号
这个段的名称,最终会被编译链接程序 处理为一个段的段地址
怎么命名无所谓,他是会成为一个唯一的地址,标识他的唯一一个段,叫标号
小任务~~
assume cs:abc
abc segment
mov ax,2
add ax,ax
add ax,ax
abc ends
end
我们假设,cs和abc关联,编译器会将,abc处理为一个地址,让cpu默认为是一个cs代码段
程序返回
dos中的程序运行
我们知道dos单任务操作系统,看电影不能聊qq
windows 实现了多任务系统~
p2 再可执行文件中,必须有一个正在运行的p1 将 p2哦菜呢个可执行文件中加载进内存,将cpu控制权给了p2 p2才能运行P2运行,p1暂停
现在,一个程序结束后,将CPU的控制权交还给使他运行的程序,
我们称之为 程序返回
如何返回呢?需要加上返回的程序段~
dos最出名的就是中断机制
消息机制是windows多任务的开始
段结束,程序结束,程序返回
语法错误和逻辑错误
asume 他就不认识,就是语法错误!
逻辑错误,是你打错的,编译器不会发现错误
!!!不容易发现!!!1
!!!masm!!!
后缀asm
选择,assmbly 汇编语言
粘贴过来~
有severe errors 有一些错误~
很难受= =兄弟盟
编译完成~!!
masm 1.asm
如果报错的话,就会提醒你哪儿错了!
编译完成,然后需要进行链接
obj都是机器码的信息
link 1.obj
他会提醒,没有代码段,没有一个入口地址,
运行完又会回来,因为他,中文字符,所以会乱码~
加了分号,他就不会有任何废话的确认!
我们使用masm 和link的缩写
ml.exe
自动生成~
编译:将伪指令,汇编指令转换为机器码
链接:
关于编译和链接
编辑器:notepad++ ue winhex
编译器:masm
连接器 :link
调试工具:debug
第四章第一个程序03
芜湖,复习一下
可执行文件中的程序装入内存并运行的原理
第一个:cmd
怎么让他知道是哪个程序呢?,设置csip 指向程序的入口
返回到cmd喽
操作系统的外壳
汇编程序从写出到执行的过程
单步调试,执行一次,中断一次
我们编译一个有入口的
他不提示了,说明有入口了!!
这样都可以,并不是一定需要写成start,他只是认为,end 之后的叫入口的地址
我们进入 2.exe
通用寄存器,存放的是 程序的长度
第一条对吧 mov ax ,0123
我们该查看哪个寄存器?ds,cs?
程序执行过程的跟踪
exe程序加载的过程
按理说,cs,ds应该指向同一个地方,对吧,但是实际上不是
加多一个0 相差100
首先,她找到一个段地址,称之为SA,肯定够加载的,在前256字节中
也就是16进制的100H
创建一个PSP 一段空间,这段空间存放dos利用他和加载程序之间的通讯
这段内存,反而是从SA+10H开始的
SA+10H:0
SA:100H
他这两个,就是同两个段,方便程序员理解存放的不同的内容
csip还是从程序真正开始的地方
前256个字节,存放的是psp的内容
我们看段寄存器开始指向,他就是,psp
我们看csip,就是我们程序的指令
小总结
4.9 程序执行过程的跟踪
用p命令来结束
执行啦
相加
相加
执行mov ax,4c00
要使用P命令执行int21
5.1[bx]
loop指令,循环呗~
【bx】是什么呢?
编译器中!并不是 debug的命令
你看 mov a1,【0】 等于mov a1,0
mov al,[2] 等于 mov al,02
debug和编译器是不一样的!!!!!!‘
编译器不会这么认为对吧,
ax一次一个字的传输
al一次一个字节的传输
【bx】就是用来给masm看的
不能mov ax,[0】对吧
那如果我们想给他东西怎么办
mov ax,[bx]
先给bx赋值,然后再传
loop
这个不就是
ax寄存器中的值,等于 ds中寄存器值左移一位,然后偏移两个,
两个值相等了
push/pop相反的哟
约定符号idata表示常量
5.1【bx】
这个是讲课采用的,不能这么写得哟
mov [bx],ax
问题5.1
inc是自增1,相当于i++
ax赋值2000
给了ds
然后bx 给了1000
然后21000的值给了ax
bx自增
bx自增
然后把ax值给了后两个的地方,210002
然后自增自增 又来一次 210004
然后自增
把高位给了
自增
把高位给了
两次自增
倒着看才差不多
32个字节一个单位~~~
od来看内存的话,找到多大,在倒着看
直接 p
5.2 Loop指令
指令的格式是:loop标号,cpu执行loop指令的时候,要进行两步操作
就像pop push 一样,有两步操作
loop和cx有关系,~!!!!!
如果为0就接着,向下执行
cx中存放循环的次数!
我们来看loop的作用
任务1 编程计算2^2
结果存放在ax中
任务二
任务三
这个是标号,随便闹
说明他要执行循环11次
不为零会跳转到标号
首先,直接,给他ax赋值,cx默认是程序的大小
cx赋值为b了
loop 0006 就相当于一个开始的地址,不管你叫啥,但是最后都会变成循环开始)
0 了,该接着走了
5.2 loop指令
loop和cx配合的三个要点~
cx存放循环次数
loop指令中的标号,所标识地址要在前面;
要循环的程序段,要卸载标号和loop指令中间
循环体的内容~~·
loop s
我们肯定不会这么干,
236 加123次多香呀
在debug中跟踪用loop指令实现循环程序
我们当然可以存在dx中,那么,如果我们存储的数据超过这个会怎么样?!
位数,只是让他,数据大小相等就行,管你听没听到·~~
为什么会,多一个零呢?
如果给[bx] 值的话 因为一个是8位,一个是16位,会发生奇奇怪怪的问题
两句合成一句
如果删掉,会发生什么
按理说是不能改的,因为改了的话,他这里只用读取8位,改了的话,不能保证ah高位一定是0
这儿为什么要加0呢’?
因为,汇编源程序,他不能以字母开头@!!!!!
当场报错
!
如果有字母,直接就填一个0
跟进一下,也就三个循环
更能熟悉了loop的过程
当调试很多次的时候,
我们可以使用G命令,P命令
占了25个字节
al ah要分开赋值
不能直接写
书上是对的
我们可以通过-g 直接执行到循环结束,
循环,这里,-p直接回跳过,然后下一条语句,
温故而知新
Debug和汇编编译器masm对指令的不同处理
这里,他是根据源指令去取数据的,ax,【0】 就会从【0】开始去一个字16位
但是汇编源程序中,mov ax [0]===mov ax 0
示例
debug中
mov ax,2000
mov ds,ax
mov al,[0]
mov bl,[1]
mov cl,[2]
mov dl,[3]
汇编语言
assume cs:codesg
codesg segment
wuhu:
mov ax,2000h
mov bs,ax
mov bx,0
mov al,[bx]
mov ax,4c00h
int 21h
codesg ends
end wuhu
-r 查看(改),-t 执行,-u 机器码翻译汇编
-d 查看ascii转码后的内容 -e 修改值
-a 写入指令
是否可以像debug一样简单?
可
这样就可以啦~~~
-p 跳过循环
-g 随便挑到哪一个地址,中间都会执行
讲al 值给0
将0位置的值给al
将【bx]内容,给了al
将【bx]内容,给了al
loop和[bx]的联合应用
超了就会损失精度
0-b是12个字节类型~
范围是0-255
12个相加,255*12 不可能大于65535 所以可以放存
可不可以这样呢?
!! 类型匹配 结果不越界
这俩不行
需要找中介
当然我们需要适用loop~
我们需要变量对吧
打完了,调试一下
偏移地址只能使用bx哟
使用cx什么的都不可以!
如果给常量,就不能进行递增了!
5.6 段前缀
这就是段前缀,如果前面没写,就默认放在ds中
一段安全的空间
不能随便覆盖东西,不负责任!!
覆盖到人家数据,就会报错,欺负到操作系统了
就像这样报错!
a
我们要更好的进行变成,理解系统底层
操作系统把一切都封装好了,一个又一个的虚拟机,一个又一个的虚拟空间,
dos下,确实不会被操作系统所干扰
可能会改写系统数据,不安全
这段空间中,百分之百没有任何代码,
从0:200~0:2ff 的256个字节的空间,这段空间是安全空间
我们就写到这儿,不会被干扰
5.8 段前缀的使用
这样的话就可以统一偏移地址~
12次可以忽略,2亿次就不行了呀
我们的es 附加段
每次循坏改两次,太麻烦了
这种优化策略,是十分重要的
改进的程序的分析
使用es,优化,就不用重复设置ds
第六章 包含多个段的程序
我们为了编程简单,编程方便,我们就会分段
引言
C语言,一个一个函数,一个一个段~
面向对象:一个功能,一个类一个类的调用
函数的封装
封装使得变成更简单~
系统会给的~
我要200个字节零花钱,他就会给~~
6.1再代码段中使用数据
好歹放在一个地方一块而加
解释dw
如果说定义字节数据,也就是db 对吧就是define Byte
分别为16个字节,每个都是16字节
英文逗号~
8个数据在哪儿呢?
codesg在代码段,cs段
因为dw定义的数据处于代码段的开始,所以偏移地址为0
我们编译,先不要运行,debug加载一下
开始可不行,start不能在dw上
我们查看内存
当然,查看的是段的开始
确实是存放的数据
偏移16个字节后,真的就是开头
要运行,必须要入口
然后结束
当然我们早打了
当然,我们不能拿这个-u来看,因为,CPU他是把机器码识别成指令,所以都把他翻译成了指令,,csip没指向正确,肯定会执行错误
end还会寻找编译器入口
6.2 在代码段中使用栈
逆序存放,一般就要想到栈
首先,你定义了dw 0,0,0,0,0,0
腾出了8个字的空间
监测点6.1
mov cs:[bx],ax
mov ax,cs
36
pop cs:[bx]
6.3 将数据,代码,栈,放入不同的段
怎么做呢
一个封装的思路~
他将,数据定义为数据段,代码定义了代码段,栈定义了栈段
data相当于是一个地址,相当于是一个段地址
cpu是看不懂的
当然不会,他只是编译器知道的而已
end start 这个他会把start指向的当作代码段执行,
实验五, 编写,调试具有多个段程序
首先
debug加载,
数据段,栈段,代码段
end 后是开始标识
执行到21h,程序都加载完了, 那么就来查看一下值
好,没变
stacksg segment stack 这样才可以指定栈段
,否则的话需要在代码段中指定
第二题
调试完成
0B3D
0042
0B3E
0B3D
没有发生改变
0123 0456
第一题,第二题,他的字型数据不同,数据量不同对吧,但是呢,第一题第二题地址一样!,奇奇怪怪的,
因为计算机是以16的倍数分配空间的,段总是16的倍数
16 *(N/16 +1)
比如,n 是 17 个,他肯定给两个,
因为我们写的不同,所以,code data stack 三个的顺序大小不同噢,在程序中位置发生了改变
编译器从上往下编译的
只有第三个可以执行,他不知道从哪儿开始,他就会从头开始执行,
第五题
MOV AX,A
MOV DS,AX
MOV AX,B
MOV ES,AX
MOV BX,0
MOV AX,C
MOV XS,AX
MOV CX,8
S: ADD DS:[BX],EX:[BX]
MOV CX[BX],DS:[BX]
LOOP S
MOV AX 4C00H
INT 21H
也可以A先放C,然后c+b
第六题
MOV SS,B
MOV AX,A
MOV DS,AX
MOV SP,16
MOV BX,0
PUSH DS:[BX]
引言
没有目录的目录
7.1 and 和 or指令
and指令 逻辑与指令,按位进行与运算
两个为1 ,其他为零
两个1 才为1。只要有0 就是0
and al,00111011b
将后面的数据和前面进行与运算,
按位进行与运算
and指令的一点功能
and 可以将相应位数设置成0
or指令
逻辑或指令,按位进行或运算
0|1 = 1
零零相或才为0,其他全是1
or指令的一点功能
可以将相应的位设为1
其他位置不变
ASCII码
全世界统一的 ascii。(8位)
unicode 也是(包含中文,韩文,日文)
unicode 包含 ascii
61 h表示。 97。 也就是a
关于ascii码表续
以字符形式给出的数据
单引号,
db 相当于是 字节
大小写转换的问题
大小写,相差32 也是相差20H
大写在前小写在后
这个是16 jingzhi
小写字母在二进制中,第五位多了一个1
程序必须要能够判断
大写字母的第五位,都是为0
小写字母的第五位都是 1
大写改小写,or
小写该大写 and
7.5[bx+idata]
更为灵活的方式
这三个从实质意义上来说是一样的
问题7.1
21000h给了ax
+1 给了cs
+1加到cx
方便的对加一减一进行操作
7.6 用[bx+idata]的方式进行数组的处理
原版代码
变第五位,是优化的重点~
改进后的程序
记住,四种写的方式
如果我们使用C,写出来就是这样的
C和汇编,有类似之处
SI和DI
这两个通用寄存器,si和di和bx功能相近
这俩一样~
bx不够用,所以我们补充si di
使用复制啦,循环啦,si di不够用
问题7.2
.。。。。。。 替换为字符
个人代码如下
start:codesg segment
mov ax,datasg
mov ds,ax
mov si,0
mov di,16
mov cx,8
s:mov 0[si],0[di]
add si,2
add di,2
loop s
mov ax,4c00h
int 21h
codesg ends
end start
问题7.2 分析嘘嘘嘘表
si原始空间,di复制空间,这个是他答案
他只用了一个寄存器,
一次循环解决所有问题
[bx+si] 和[bx+di]
两个寄存器,我门自己凑
这都可以
问题7.4
ax先00be
si+1
cx先0600
si+1
di变成06的位置
ax变成0006
si,di 可以当变化偏移地址
bx当起始偏移地址
7.9[bx+si+idata] [bx+di+idata]
到底有什么方便之处
只要常数在后面的,我们都要加点
问题7.5
先ax 2000
给了ds
bx起始偏移1000
si 0
ax为0006
si+1
cx 6a00
si+1
di变为2
ax变为 226a
7.10 不同的寻址方式的灵活应用
本次解决例题
idata debug才认
【bx】 masm认
第三个相当于数组
问题7.6
datasg中的数据结构图
后面都是空格填充!!!!!
要定位具体的大写
六行循环
一次处理一个大写
问题7.7
每个单词改为大写,怎么办呢?
问题7.7 分析
嵌套循环
他的cx,两个,很明显,错了,
问题7.8
昨天的程序
他会进入死循环,
内层也会改变cx
这儿直接溢出了,直接死循环
loop 一定要配cx,而且不能多用一个寄存器
先保存,出来的时候,再恢复
所以猜测可以用栈?
汇编中,dx临时存储cx
在进行外层循环的时候,恢复cx的值
CPU中寄存器毕竟是有限的
我觉得可以栈~
我们不能用寄存器了,我么可以用内存~
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O0nwkEJr-1626778558355)(…/…/AppData/Roaming/Typora/typora-user-images/image-20210720172111774.png)]
我们先看vc编译器 的做法
好,最后用栈,开心
他相当于,里面的东西没改
使得我们的栈,非常必要,使得有漏洞可循!
问题7.9
数据分布如下
第八章引言
处理的数据,放在内存里面
要处理的数据有多长?
reg 表示寄存器,sreg表示段寄存器,
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ykk1g5Lv-1627282741131)(https://gitee.com/dingpengs/image/raw/master/imgmac//20210720223519.png)]
8.1 bx si di bp
前三个用过了,总结一下
只有四个,8086里面
【a x】这种就是错误的
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tIvoMZVs-1627282741135)(https://gitee.com/dingpengs/image/raw/master/imgmac//20210720223644.png)]
这四个寄存器,可以单个出现,也可以进行四种组合的出现
bx和si bx和di。 bp 和si。 bp 和di
bp相当于sp,帮忙sp减轻负担的
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YKzeyLx9-1627282741140)(https://gitee.com/dingpengs/image/raw/master/imgmac//20210720225950.png)]
bp 和bx不能在一起,因为会混乱
一个指向ss 一个指向ds 会产生歧义
机器指令处理的数据所在位置
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gg5hNEGD-1627282741142)(https://gitee.com/dingpengs/image/raw/master/imgmac//20210720230618.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Rvgbqfvx-1627282741143)(https://gitee.com/dingpengs/image/raw/master/imgmac//20210720230739.png)]
汇编语言中数据位置的表达
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qEEwhS2W-1627282741146)(https://gitee.com/dingpengs/image/raw/master/imgmac//20210720230856.png)]
段地址:SA
偏移地址 :EA
立即数(idata)
直接包含在机器指令中的数据,执行前在cpu的指令缓冲器中!
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hhbq3l5u-1627282741148)(https://gitee.com/dingpengs/image/raw/master/imgmac//20210720231236.png)]
2 寄存器
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cTNOdwKa-1627282741150)(https://gitee.com/dingpengs/image/raw/master/imgmac//20210720231323.png)]
3.段地址(SA)和偏移地址(EA)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rCdo95fe-1627282741152)(https://gitee.com/dingpengs/image/raw/master/imgmac//20210720231355.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FrHED7qZ-1627282741153)(https://gitee.com/dingpengs/image/raw/master/imgmac//20210720231435.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wiwy4j0r-1627282741155)(https://gitee.com/dingpengs/image/raw/master/imgmac//20210720231443.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0rwTMeny-1627282741156)(https://gitee.com/dingpengs/image/raw/master/imgmac//20210720231611.png)]
0的话没有问题,其他就会报错
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PfWfR924-1627282741160)(https://gitee.com/dingpengs/image/raw/master/imgmac//20210720231710.png)]
bp为什么会跟着ds了呢?
因为没有声明,他默认ss而已
这儿强制给出了
8.4 寻址方式
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZXoLbZgp-1627282741163)(https://gitee.com/dingpengs/image/raw/master/imgmac//20210720231824.png)]
寻址方式总结
动画演示
1、直接寻址
指令要处理的数据有多长
通过寄存器名 指明要处理的数据的尺寸
因为是 bx 16 位,他会取值 ds:【0】ds:[1]
都是16位的寄存器,1就是0001H
如果这里是al
就是低8位
也就是 1===01h、
在没有指明寄存器名存在的情况下,用操作符X ptr 指明内存单元的长度
x在汇编中可以为word 或者 byte
规定字型,可以强制
双字行,就是double word
如果是 字节型数据的情况下
他的数据是(FFH) +1 会溢出
00ffh +1 0100h
如果是字的话,就不会溢出
修改的不一样噢
其他方法
有些指令默认访问的是字单元你还是字节单元
push 栈 默认只对字进行操作
sp=sp—2
8.6 寻址方式的综合应用
我们来一个实例
如上相当于伪代码
字符串 在内存里面就是字符型的数组
这个 p 就是后续的改变,位置的变化
他占了三个字节~
相对寻址~
相对基址变zhi寻址
C语言~
这种叫做数据结构~~~~
div 指令
div是除法~
除数,:8位,16位,在寄存器或者内存单元中
被除数默认放在AX 或者 DX和AX中
都是用加法来模拟的
用乘法模拟除法,如何?
如果除数是 8 位的话,
如果除数是16 位的话
div示例
注意这里
编程
1000
1 存放在dx 86A1 存放在ax中
编程程序2
可以用ax寄存器存放
8.8 伪指令dd
32 位
示例,定义按个数据
问题8.1
assume data:segment
dd 100001
dw 100
dw 0
data ends
start:
mov ax,data
mov ds,ax
mov ax,ds:[0]
mov dx,ds:[2]
div word ptr ds:[4]
mov ds:[6],ax
mov ax,4c00h
int 21h
data ends
end start
dup
这不是指令,只有编译器认识
dup的使用格式如下
我们要定义栈段~,如果不用dup就很难受
引言
无条件转移指令 如 jmp
条件转移指令
循环指令
过程(就是c语言的函数,函数也称为过程)
中断(例如,中断,原来的东西停下来,突然干其他事儿,cpu只能处理一件事情)
操作符offset
伪指令,
功能是取得标号的偏移地址
s是三开始,所以相当于mov ax 3
问题9.1
mov bx,0
mov di:[bx],si:[bx]
上面是我写的,猜测可以结果不行
1- 地点,2-长度
9.2 jmp指令
jmp为无条件跳转,
暴力破解
9.3 依据位移进行转移的jmp指令
jmp short 标号
这个是短转移
对 ip 修改为1B的范围,-128----127
负数往上跳
正数往下跳
汇编指令与机器码的对应示例
立即数会出现
他并没有08 为什么会这样呢?
因为 执行的时候,他并不知道 s的具体位置
我们添加了一个axax
发现这里改变了
!!
03 变成了 05
只是在中间添加了 2字节
机器指令中 并不包含转移的目的地址
CPU不需要目的地址就可以进行IP的修改
他的s存的是偏移地址
、
段内近转移
这儿是成了16位,之前是8位
EB 是jmp的机器码,
刚刚,ip指向了BB
走完jmp。ip指向了 2000A
因为笨,只会把EB 后面的数加到ip上
0A + F6
加上 F6 变成了20000
F6 是负数才对,-10
F6+10 正好是FF,补码简单的运算
向上要减少,向下要增加,
补码计算负数
源码 变反码 +1 变补码
9.4 转移的目的地址在指令中的jmp指令续
上节课是相对地址,的转移
这个是远转移,会给你具体的地址~
程序9.3
010b就是跳了的s的地址
机器码需要 倒着看,EA是远转移
转移地址在寄存器中的jmp指令
转移地址在内存中的jmp指令有两种格式
(1)
jmp word ptr 内存单元地址(段内转移)
也相当于 jmp ax
(2)
段间跳转,
目标段地址,和目标偏移地址
ds【2】ds【3 】取值0000
0 1 取值 0123H
监测点 9.1
因为他跳的地方是取出了 data段的值
那我存0就可以
d 5 dup(0)
相当于跳到1234段 5678ip对吧,
第一空 offset start我觉得可以,但是还是写0比较好,直接填入bx,因为没有内存和内存的通道
第二空 cs
0006 00be
9.7jcxz指令
之前讲的是无条件跳转指令,
这个有条件跳转指令
所有的有条件跳转都是短转移,都是相对偏移地址,
修改范围-128—127
loop 也是有条件跳转指令
cx为0
cx不等于0的时候,什么也不做
监测点 9.2
mov ch,0
mov cl,[bx]
jcxz ok
inc bx
因为这里是去找一个字节,所以要ch cl份开
9.8 loop指令
监测点9.3
inc cx
第九章 04 失踪了QAQ
第十章 call和ret指令
引言
程序之间加载返回过程
cmd调用debug,然后退出,然后返回
段内转移 之用修改ip
段间转移。需要修改csip
10.1 ret 和 retf
第一步,他把栈顶的值取出来,然后sp向下移动一个
分析源码
亚栈,第一个为0
然后ret,他应该ip自动改为了0
跳到了结束,代码段的开始
retf指令
多了一个push cs
retf 先改ip,再改cs,还是回到了结束
监测点10.1
1000h
0000
10.2 call指令
call不能实现短转移
call指令实现转移的方法和jmp原理相同,可实现近转移或者段转移
call 标号
压栈,
有负数 补码
监测点10.2
call s 会将 6 存入栈中,然后,pop ax,将栈中的值出栈给了寄存器ax
所以ax的值为6
10.4 转移的目的地址在指令中的call指令
我们需要给相对地址,
我们本次学习 call far ptr 标号
call和jmp差不多,只是,call保存了当前的位置,
监测点10.3
ax设置为0
远跳,1000,0008
0008+0008,然后pop bx,bx等于1000
然后就是1010h
10.5 转移地址在寄存器中的call指令
格式指令:call 16位寄存器
监测点10.4
call 6
相当于跳到了6
然后把IP 5 存入栈中
然后你sp给了bp,就是把栈顶的指针拿了出来,【bp】 把栈顶的值取出来了
然后相加5+6 =11
10.6 转移地址在内存中的call指令
word 段内跳转
dword 段间跳转
sp从何而来?栈顶指针么,10-2 0EH
第二种
可以放两个通用寄存器~
高位cs,低位ip的吧(我自己假设)
因为你是出栈,执行的话,cs先0,ip后0123h
sp。0ch。
相对高位字节存放的cs,相对低位的字节是低寄存器
监测点 10.5
第一题,前面不对ax有影响,应该是ax=3
offset 相对于 代码段0地址的偏移量,
call 会push cs,push ip,然后
0ch存放的是,nop的ip
然后,就是 s ip减去 nop ip,,就相当于是1
0eh 的话,就是cs-cs肯定是0
10.7 call和ret的配合使用
问题10.1
call 是 push ip,他把紧接着的一条指令的ip push到了栈
ret pop ip,相当于重新定位 到了mov bx,ax
bx = 8
小例题~
请大家从栈的角度,分析一下call s
10.7 call和ret的配合使用 2
我们看一下程序的主要执行过程
上节课的例题
ip = ip +0005 = 0013h
为什么是5 呢
因为相对偏移地址
这样的话,正好是偏移五个
ret 执行完后,ip指向 16
一个call 对应一个ret。 不能多个
子程序调用对吧~
反汇编看一下
这么长一堆就是初始化,
他把 字符串 push 进去,然后去找到printf这个函数
add esp,4
这个是用来恢复栈的,因为push,把栈压低了,所以可以通过这个来恢复
后续会讲
我们去调用这个函数,call这个地址
然后会初始化函数对吧
然后打印
然后把push的恢复出来
最后ret,通过ret
返回主函数
这里是,main函数的恢复阶段,然后我们继续ret,谁调用main函数,返回谁
控制台控制,就返回控制台呗
什么语言都一样~
ret到上一层,ret上一层
10.8 mul指令
乘法命令
都是8位,都是16 位
8✖️16 的话,可以把8位高位全天写0
al 乘数,ax结果
例如
必须要做 16 位乘法
mov ax 100 放在ax中,高位他会自动补0
10.9 模块化程序设计
庞大的程序,拆成小的方便修改
这个是面对过程的思想
可以用参数存到寄存器中
默认16位乘,肯定没啥问题
我们需要进行注释,分号为注释
10.10 参数和结果传递的问题
代码块
第二个是double word
10.11 批量数据的传递
我们多个参数怎么办呢?
8086cpu 寄存器有限哟
例题
神奇~
最好使用栈来传递参数
栈的性质和内存差不多
10.12 寄存器冲突问题
他看的是cx寄存器,
将高把位设置0。低8位设置位字符串
jcxz 检测cx为0 则结束
套上一个循环即可
问题 10.2
需要调试一下~明天拿下
我觉得是因为cx的问题,
只有一个变量,应该放在栈中
实验十 编写子程序
实验十讲解~
showstr是我们的编写子程序
实验一,放弃
实验二,读懂一下看看
相当于普通除法, 余数是肯定不会比原来的大,所以不会溢出
子程序开始,先把ax存起来,说明后面ax会用到
ax是低16位
16 位除法,默认dx为高16位,ax为低16位
实验十 3
输出show 和实验一一样
结束程序之前都ok弹出栈
怎么将12666取出来呢?
除以10 得余数
这里用了jcxz,判断商
数字加上30h就能得到对应的ascii码
目录
引言
标志寄存器,就是
每一位都有特别的信息
0246789 10 11 都有特殊意义
ZF标志
flag的第六位是ZF,零标志位
他记录相关指令执行后
结果位0 ZF=1
结果不为0,ZF=0
例如:
0表示否定
他们的运算会影响到标志寄存器
有条件性的跳转,就需要拿这个来判断
11.2 PF标志
查看二进制中1的个数
11.3 SF标志
结果为负数,sf=1
结果为正 sf=0
有符号数,补码
有符号数,第一位为负数,然后变成补码,
补码。反码+1,我们先-1然后变源码,
1 1111111 肯定127
结果既可以是130 又可以-126
SF标志记录数据的正负
、
都是约定好的
监测点11.1
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fTrrHfS6-1627456441904)(…/…/AppData/Roaming/Typora/typora-user-images/image-20210727151348810.png)]
ZF 是否为0
PF 1个数是否为偶数
SF 是否为负数
1,1,0
1,1,0(传送标志不影响)
push 传送标志不应i想
pop 不影响
al bl哪儿来的值??
确实 al为1,也就是
000
010
11.4 CF标志
之前 8位的话是无法处理的,当然不能这样草率的处理,
我们需要假象一个高位,当作进位
这些就是标志寄存器的特殊情况
OF(overflow flag)溢出寄存器 NV(not overflow)
DF(direction flag)方向寄存器 UP(up)DN(dowm)向上下下
SF(sign flag)符号寄存器 NG(negtive)PL(plus)负数正数
ZF(zero flag)零标志 ZR(zero) NZ(not zero)
PF(parity flag)奇偶标志 PE(parity even) PO(partity odd) 偶数奇数
CF(carry flag) 进位标志 CY(carried) NC(not carried) 进位 不进位
这里表示游进位
标志位是表示上一条指令的,时时刻刻会在变化
这个也是借位的体现
11.5 OF标志
overflow 溢出 有符号可能产生的结果,进位是无符号可能产生的结果
如果针对于无符号数而言,这两个无所谓
如果阵对有符号位,这两个就会产生溢出
示例二
这俩都是负数
对于有符号位发生了溢出
对于无符号位,产生了进位
因为计算机啥也不知道
监测点11.2
11.6 adc指令
关键是cf的值被谁设置的
这里是16进制相加减,这个1就是相当于cf加
提供adc就是为了加法第二步运算的
大家如果不理解adc的话
就来看这里
书中的adc求ax例子狗屁不通
adc就是用在高位加法,
比如这样
add al,al
如果产生了溢出,势必会导致cf为1
那么ah+ah的时候,
adc ah,ah,就会使得他进位被加上
编程任务
这个是24位加减
我们需要把他拆开,
然后我们把高16位存在ax,低16位存在bx
加低的,然后产生进制
然后高位加
adc论调
先加cx,adc bx,adc ax
adc指令实践
如果加的不够了,就可以放到内存/栈
这样是不行的,add指令会影响cf值,inc 不会影响
sbb指令
带借位减法指令
先减低位,再减高位,能保证数据的完整性
cmp指令
只对标志寄存器产生影响,
相当于减法指令,但是不会保存结果
仅影响flag的各个位
只是改变了flag
使用这个,我们可以进行爆破,不必进行运算,直接看flag,然后jmp或者jcmz跳
cmp的设计思路
刚刚比较的都是无符号运算,
cmp指令 有符号数
判断是否相等,只看ZF就可以
一个正数一个负数,会产生溢出错误
小的减去大的得到负数
我们需要先加一个判断,判断大小?还是判断是否溢出呢?
加一个判断溢出
有符号 考虑 sf,of
这样就可以是相反的
只要产生溢出,结果就是相反的
32位都不存在段了
检测比较结果的条件转移指令
cmp指令配合je
编程训练
cmp ah,bh
je s
add ah,bh
jmp short ok
s:add ah,ah
ok ret
检测比较结果的条件转移指令
没有cmp,我们仍然可以进行gank
课堂练习
第二种方案
方法一比较精简
我们使用jna
改成jnb
有符号和无符号只是对比的有一点不同而已
监测点11.3
jb s0
ja s0
jna s0
jnb s0
DF 标志 和串传动指令
方向标志位
串传送指令 以字节的形式移动
段地址为ds,偏移地址为si的内容 字节内容
把它放到,段地址为es,偏移地址为di的地址
df=1 被枪毙就是负数,不会混的
movsw
和rep指令配合使用
设置目标内存,来源内存,
可以循环实现cx个字符的传送,
cl :clear
st:set 对吧
DF 标志和串传送指令
因为我们传输字符串,我们使用串传输指令
从哪来,到哪儿去,方向,长度
DF =1的时候,就是负的
确实复制过来了
编程二
DF设置成1也行哟
反方向存储u
照搬,实现了
pushf和popf
监测点11.4
本题关键在于OF 标志的判断。另一个关键点是and 0000 0100 1100 0101 起到了屏蔽未学习位的作用!
mov ax,0 将ax置0
push ax,ax入栈
popf 将栈中的数据弹出道标志寄存器中,
00000000000000000000000000
mov ax,0fff0h
add ax,0010h
(ax) = fff0h+0010h
显然,10000 H flag 会发生改变
CF:假设为无符号计算,发生进位,CF=1
PF ax = 0000h pf标志为1
and 与运算,有0则0
assume cs:code
//奇怪之处ax的值为47h?使用指令pushf,popf
code segment
start:
mov ax,0
push ax
popf //从栈中弹出数据,送入标志寄存器,易知PSW将会被置为0
mov ax,0fff0h
add ax,0010h //结果为0000h,并发生进位,不溢出,此时寄存器的状态为NV UP DI PL ZR NA PE CY(即PSW:00000000 01000111,如果默认第01位为0则是01000101结果为45)
pushf //将psw=47h值压入栈
pop ax //将之前压入的值赋给al=47h(01000111)ah=0h(00000000)
and al,11000101b //异与后al=45h(01000101)ah不变
and ah,00001000b //异与后ah=0h(00000000)al不变
mov ax,4c00h
int 21h
code ends //所以ax最后值为45h
end start
第十二章 内中断 01
引言和简介
这本书主要讲解硬件中断
外部中断主要是一i写,计算机外设发出的请求
就像int 21 就是软件中断
中断处理程序
除数为零,必须要来一个中断
为windows多任务,奠基
中断向量表
就相当于是一个索引
中断向量表,从0开始,8086pc机
之前说的安全内存是 0:200----0:300
监测点12.1
中断过程
他要保存csip
中断处理程序
调用中断一般都是用iret
除法错误中断的处理
这个就是0号中断
编程处理0号中断
他修改了0号中断
我们可以存放到安全的内存
这个存放的非常重要
他是溢出的时候才会执行
编程处理0号中断(2)
我们把do0拷贝到安全区域,但是也不能执行,没有注册到中断向量表
设置好后才能叫中断处理程序
上面有减号,
求出它们之间的距离
编译器还可以处理其他的表达式
0b800 就是显存~
看似合理,其实是错的
数据段可能会被覆盖
welcome 同ficshc 也许要放在安全的地方
完整的程序实现
单步中断
单步中断,为了控制
debug却能停下来
TF位,就是单步中断
指定了中断向量表
原因就是为了实现单步跟踪
响应中断的特殊情况
发生中断他也不会响应??