10.17汇编

Posted on Oct 17, 2020
November Rain

今天看了将近三章,效率还算不错

第四章过的很快,没什么特别的。

编译链接的过程

再强化一次,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

来实现