扯话
开始啃汇编啦,看过CSAPP第三章后,感觉上手还是比较友好的
准备顺序大概是
王爽汇编语言 -> x86汇编语言:从实模式到保护模式 -> 操作系统
实验
准备工作
书上的环境是在windows下,由于我是使用的linux发行版deepin,所以选择了一些工具代替
试了一下,现在用win10去使用DOS估计也不是特别简单,干脆就用LINUX了
使用dosemu模拟DOS环境
安装dosemu
只需要一句简单的命令行即可安装dosemu
sudo apt-get install dosemu
安装MASM6.115.0
在下载完MASM6.11后,在HOME文件夹下解压,于是我们得到了MASM611的安装文件夹
后续安装后,使用过程出现了缺少dosxnt.exe文件的报错,google后折腾了一个小时左右,后面还是换版本了
使用的是MASM5.0
dosemu下看到的C盘和D盘只是虚拟出来的,对应的目录在~/.dosemu/drives 下。
下载解压后,将link.exe和masm.exe放到C盘下,直接使用就可以了
具体使用书上有解释,就不赘述了.
实验1 查看CPU和内存,用机器指令和汇编指令编程
- 使用Debug,将下面的程序段写入内存,逐条执行,观察每条指令执行后,CPU中相关寄存器的变化。
| 机器码 | 汇编指令 | 执行后相关寄存器变化 |
|---|---|---|
| b8 20 4e | mov ax, 4E20H | AX=4E20H |
| 05 16 14 | add ax, 1416H | AX=6236H |
| bb 00 20 | mov bx, 2000H | BX=2000H |
| 01 d8 | add ax, bx | AX=8236H |
| 89 c3 | mov bx, ax | BX=8236H |
| 01 d8 | add ax, bx | AX=046CH |
| b8 1a 00 | mov ax, 001AH | AX=001AH |
| bb 26 00 | mov bx, 0026H | BX=0026H |
| 00 d8 | add al, bl | AX=0040H |
| 00 dc | add ah, bl | AX=2640H |
| 00 c7 | add bh, al | BX=4026H |
| b4 00 | mov ah, 0 | AX=0040H |
| 00 d8 | add al, bl | AX=0066H |
| 04 9c | add al, 9CH | AX=0002H |
提示,可用E命令和A命令以两种方式将指令写入内存。注意用T命令执行时,CS:IP的指向。
2.将下面3条指令写入从2000:0开始的内存单元中,利用这3条指令计算2的8次方。
1 | 1 |
一个循环,很好理解
3.查看内存中的内容。
PC机主板上的ROM写有一个生产日期,在内存FFF00H~FFFFFH的某几个单元中,请找到这个生产日期并试图改变它。
提示,如果读者对实验的结果感到疑惑,请仔细阅读第1章中的1.15节。
用D命令能看到储存在FFF0:00F5-00FC之间,xx/xx/xx ,模拟器是可以改的,然后真实情况应该是不可以改的(猜测),应该是写死了,无写权限
实验二
- 使用Debug,将下面的程序段写入内存,逐条执行,根据指令执行后的实验运行情况填空。
1 | mov ax, ffff |
结果1
2
3
4
5
6
7
8
9
105bea
00e0
32f0
2f32
00FE 220FE 25EE
00FC 220FC 5F37
00FE 5F37
0100 25EE
00FE 220FE 3002
00FC 220FC 2F35
2.仔细观察图3.19中的实验过程,然后分析:为什么2000:0~2000:f中的内容会发生改变?
在使用T命令时,产生了中断,为了保护现场,CPU将CS和IP,此时的位置,入栈,导致了内存相关位置内容的改变。
实验三
- 将下面的程序保存为t1.asm文件,将其生成可执行文件t1.exe。
1 | assume cs:codesg |
这个没什么好说的….
- 用Debug跟踪t1.exe的执行过程,写出每一步执行后,相关寄存器中的内容和栈顶的内容。
| 结果 |
|---|
| ax 2000H |
| ss 2000H |
| sp 0000H |
| sp 000AH |
| ax 0 sp 000cH |
| bx 0 sp 000EH |
| sp 000cH |
| sp 000AH |
| ax 0 sp 000cH |
| bx 0 sp 000EH |
| ax 4c00H |
| empty |
- PSP头两个字节为CD 20,用debug加载t1.exe.查看PSP内容:
PSP区域地址范围为:ds:0~ds:ff.用d命令查看即可
实验四
- 编程,向内存0:200~0:23F依此传送数据0~63(3FH)。
见下
- 编程,向内存0:200~0:23F依此传送数据0~63(3FH),程序中只能使用9条指令,9条指令中包括“mov ax, 4c00h”和“int 21h”。
1 | assume cs:code |
- 下面的程序的功能是将“mov ax, 4c00h”之前的指令复制到内存的0:200处,补全程序,上机调试,跟踪运行结果。
下面的程序的功能是将“mov ax, 4c00h”之前的指令复制到内存的0:200处,补全程序,上机调试,跟踪运行结果。
1 | assume cs:code |
程序入口为cs:0(ip=0),所以第一空处传递段地址为cs
而程序总代码长度可通过debug加载后通过u命令看出.先将第二空位随便设为1,加载后观察mov ax,4c00h之前代码为0000~0016h,总长度为23.
实验5 编写、调试具有多个段的程序
1.将下面的程序编译连接,用Debug加载、跟踪,然后回答问题。
答案:
data段中的数据不变。
07f3、07f4、07f2(答案不唯一)
X-2、X-1
2.将下面的程序编译连接,用Debug加载、跟踪,然后回答问题。
答案:
data段中的数据不变。
07f3、07f4、07f2(答案不唯一)
X-2、X-1
可以知道:数据段空间大小为定义数据所需的16字节的最小整数倍
([N]+1) * 16 (字节对齐)
3.将下面的程序编译连接,用Debug加载、跟踪,然后回答问题。
答案:
(3) x+3 x+4
4.如果将1. 2. 3.题中的最后一条伪指令“end start”改为“end”(也就是说,不指明程序的入口),则哪个程序仍然可以正确执行?请说明原因。
答案:
程序3,在不指明程序入口的情况下,程序默认按照顺序从头开始执行.
5.程序如下,编写code段中的代码,将a段和b段中的数据依此相加,将结果存到c段中。
1 | start: |
6.程序如下,编写code段中的代码,用push指令将a段中的前8个字型数据,逆序存储到b段中。
1 | start: |
实验6 实践课程中的程序
1.将课程中所有讲解过的程序上机调试,用Debug跟踪其执行过程,并在过程中进一步理解所讲内容。
2.编程,完成问题7.9中的程序
解决方案有书上三种,用的是栈储存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
27start:
mov ax, codesg
mov ds, ax
moe ax, stacksg
mov ss, ax
mov sp, 16
mov bx, 0
mov cx, 4
s:
push cx
mov cx, 4
mov si, 0
s0:
mov al, [bx+si+3]
and al, 11011111b
mov [bx+si+3], al
inc si
loop s0
add bx,16
pop cx
loop s
mov ax,4c00H
int 21h
实验7 寻址方式在结构化数据访问中的应用
1 | assume cs:codesg, ss:stack |
实验8 分析一个奇怪的程序
分析下面的程序,在运行前思考,这个程序可以正确返回吗?
运行后再思考:为什么是这种结果?
通过这个程序加深对相关内容的理解。
1 | assume cs:codesg |
jmp short 标号、jmp near ptr 标号、jcxz 标号、loop 标号等几种汇编指令,它们对 IP的修改是根据转移目的地址和转移起始地址之间的位移来进行的。不包含转移的目的地址,而包含的是到目的地址的位移距离。方便了程序段在内存中的浮动装配。
能成功返回,通过ax将s2的地址传送到s,jmp short s实际跳转到s2,而s2中jmp short s1计算的是s1,s2之间的偏移量,然后加上s的地址,实际跳转到首地址,完成返回
实验9 根据材料编程
编程:在屏幕中间分别显示绿色、绿底红色、白底蓝色的字符串’welcome to masm!’。
编程所需的只是通过阅读、分析下面的材料获得。
1 | assume ds:data, cs:code |
实验10 编写子程序
1.显示字符串
注意事项:
1.计算偏移地址的时候,以bx作为偏移量,ax不行
例如 es:[bx+si] 而不是 es:[ax+si]
2.子程序开始的时候把所有的寄存器入栈,方便接下来使用,结束的时候出栈
3.计算数组偏移地址的时候,用mul
1 | assume cs:code,ds:data,ss:stack |