汇编语言笔记6包含多个段的程序
汇编语言笔记6包含多个段的程序
0x00 为什么需要多个段
在操作系统环境中,有两种取得空间方式,一在加载程序时为程序分配,二是在程序执行过程中向系统申请,前者称为静态分配,后者称为动态分配。
我们通过在源程序中定义段来进行内存空间的获取。另外我们一般定义不同的段来分别处理数据 代码 栈空间
因此我们得在代码中定义多个段
0x01 只使用一个段得情况
1在代码段定义数据
我们可以在代码段定义数据,这样这些数据就随着代码一起被装入内存了
assume cs:code
code segment
dw 0123h,0456h,0789h
start: mov bx,0
mov ax,0
mov cx,3
mov dx,start
s: add ax,cs:[bx]
add bx,2
loop s
mov ax,4c00h
int 21h
code ends
end start
上述代码的作用是将三个数累加到ax中,在代码的最开始我们通过dw 定义了三个字型数据 数据之间用逗号分隔 同理db定义字节数据
由于定义在代码段的最开始,所以这三个字型数据的偏移地址分别是 0 2 4,段地址则是cs 所以bx初始为0
那么我们在代码段定义了数据 而ip初始为0 程序执行的指令会发生异常,因为指令的偏移地址不是0,那怎么办呢? 使用 start 和 end start标号,将ip初始到start对应的地址 ,表示指令从哪儿开始执行,哪儿结束
上述代码中 我们试着将start的内容mov到dx(这条指令在编译时被给了一个warning),因为我们知道标号在编译时会被解释为一个地址,让我们看看start的地址和ip是不是一致的
经过编译链接调试我们看到 ip 确实被初始化到start 6这里了,为什么第一条指令的偏移地址是6呢? 因为我们在代码段的开头定了三个字型,一共占6个字节 所以偏移地址是6
2在代码段使用栈
assume cs:codesg
codesg segment
dw 0123h,0456h,0789h
dw 0,0,0
start: mov ax,cs
mov ss,ax
mov ds,ax
mov sp,0ch
mov bx,0
mov cx,3
s: mov ax,ds:[bx]
push ax
add bx,2
loop s
mov ax,4c00h
int 21h
codesg ends
end start
上述代码和标准答案不一样 主要在 标答的数据是8个字型 栈空间也是8个字型,sp赋值30h 按道理说 我的代码只是标答的精简版应该也是对的,但是我的代码结果怎么都错,不能正常的将三个数据倒序赋值到 后面的三个字型的空间里,为什么呢
经过逐步执行,发现问题出现在栈的初始化执行中 设置 ss和sp这一步后,栈空间会被随机初始化,而把前面三个字型的数据空间也改了,所以错了,而标答对了大概是它给栈空间比较大,不会改到数据区
0x02 检测点
mov cs:[bx],ax
mov ax,cs
mov sp,24h//2020-6-26改正:栈的第一个元素起始地址是36-1=35,转换成16进制是22h,所以栈空则是+2 24h
pop cs:[bx]
0x03 将数据代码栈放入不同的段
在前面的内容中,我们将 数据 栈 代码放到一个段里,这样显得混乱,而且如果数据+栈+代码不能超过64k 十分受限
所以 我们通过定义多个段来解决这一问题
assume cs:code,ds:data,ss:stack
data segment
dw 0123h,0456h
data ends
stack segment
dw 0,0,0,0,0,0,0,0
stack ends
code segment
start: mov ax,stack
mov ss,ax
mov sp,20h
mov ax,data
mov ds,ax
mov bx,0
mov cx,8
s: push [bx]
add bx,2
loop s
mov ax,4c00h
int 21h
code ends
end start
上述代码的功能是将数据段的8个字型数据倒入push进栈
1 我们如同定义代码段一样的方法定义数据段和栈段
2 我们可以直接对段地址引用 如 mov ax,data 因为我们知道标号最红会被解释成一个idata地址,mov 不能直接将idata送入段寄存器 所以才先送入ax
3 这些段 是我们写程序时自己的安排,并不因 ss:stack 这样的写法就自动将stack的地址写入ss 还需要我们在代码段中改写ss (但是奇怪的时cs却能被cs:code 自动修改。。。。)