10.17汇编
今天看了将近三章,效率还算不错
第四章过的很快,没什么特别的。
编译链接的过程
再强化一次,masm.exe:编译源代码,产生目标文件(.obj),link.exe:链接目标文件,产生可执行文件(.exe)。
注:通过debug .exe
可以实现调试
程序的加载过程
分配一段有足够空间的内存地址,前256B为PSP区段,用以与DOS交互,之后为程序区段。两区段连续,但是段地址不一样。
当前未解释的问题
代码段末尾要添加:
mov ax,4c00h
int 21h
目的是实现程序的返回,让shell可以继续执行。
PSP区段,用以与dos交互。
第五章主要是[..]到[bx]的转变和段前缀的使用,以及最主要的loop指令。
[bx]和段前缀
首先我觉得[bx]没什么特别的,不过是[..]中的立即数变成了寄存器,8086中只有bx这一个通用寄存器可以用来寻址,[ax]这样的会报错。当然在degug中可以[立即数]这样用,而汇编程序里面[立即数]会被转成立即数本身,达不到目的,需要使用cs:[立即数]才行。而[bx]则可以直接用,等价于ds:bx。
段前缀即指ds:
这样的显式指明段寄存器的代码。
这里有引入了新的段寄存器ES(extra segment),这是一个额外的段寄存器,没有特殊用途,在需要的时候使用即可。
关于实模式的一些危险
实模式下,cpu可以直接执行所有代码,若对存放了其他程序数据的内存进行修改,会造成系统出现问题,dos中00200h-002ffh中往往不存放数据,可以暂时使用这些。
loop
loop指令主要用来进行循环。
mov cx,10
s:inc bx ;inc指令可以使寄存器中的值自加一
loop s
这段代码中,loop s
指明了循环标识符,每一次到loop时会执行两个操作,
1、cx=cx-1;2、判断cx是否为零,若为零则跳出循环,执行下一条语句,否则跳至标识符处
也就是说cx在这里扮演了for里的i的角色。
在debug中,用指令p可以直接执行玩循环,g address可以直接使ip指向address并执行玩之前所有的指令。
一个细碎的点,在汇编程序中,不能以字母作为数字的第一位,如a000h是不合法的,这时要使用0a000h。
实验中的一个点:CX在初始化时会初始化为程序所占字节大小
至此第五章完成:)
代码段中使用数据
可以使用dw
(define word)指令来向代码段中添加数据,这些数据会直接存储到内存中,遗憾的是,编译器并无法智能地改变IP的值,所以会把数据段当作指令来执行,这样肯定会出现问题,所以就有了end start
指令
....
codesg segment
dw 1342h,1324h,1242h
start: .... ;注意
codesg ends
end start ;注意!
这样IP就会指向第一条指令了。
注意这里的start并不是必须的,写成stat之类的也有一样的效果。
分段
显然,数据代码和栈混用一段是非常不明智的,不仅难以管理,使程序混乱,还会造成段空间不足的情况(8086中,一个段最大只能有64KB)
因此,我们可以用与代码段类似的方法,来定义栈和数据段。
assume cs:code,ds:data,ss:stack
stack segment
;栈段
stack ends
data segment
;数据段
data ends
code segment
;代码段
code ends
从这里我有了新的理解,即一个段的作用,只需要通过与对应的段寄存器assume就可以了,其本质是人为对段寄存器的控制。
一个反(我的)直觉的部分
虽然assume了ds和data,但是ds并不会指向数据段,对ss也是同理,一下的代码在debug中运行的结果证实了这一点。
assume cs:code,ss:stack,ds:data
stack segment
dw 0,0,0,0,0,0,12h
stack ends
data segment
dw 3521h,1256h
data ends
code segment
start:
mov ax,data
mov ax,stack
mov ax,ss
mov ax,4c00h
int 21h
code ends
end start
所以要通过
mov ax,data
mov ds,ax
来实现