多个段的程序

Reverse

有了多个段之后,程序会变得更加有条理、舒服🍺

产生的问题

将 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h 以下8个数据的和的结果放入寄存器 ax 中

直接上代码进行分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
assume cs:codesg
codesg segment

dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h

mov bx,0
mov ax,0

mov cx,8
s:add ax,cs:[bx]
add bx,2
loop s

mov ax,4c00h
int 21h

codesg ends
end

其中的 dw 含义是定义字型数据,即“define word”。在这里定义了8个字型数据,它们所占用的空间大小为16个字节。

再对程序进行编译和链接并查看一下基本的情况image-20220521102904789

关注图中 -d 后的第一行,我们可以发现我们所想要写入的数据已经被连续地存放在了代码段的最开始处。

关注图中 -r 中显示的所要执行的下一条命令,可以发现是and ax,[bx+di]并不是我们所想要的mov bx,0

产生这种情况的原因在于,计算机认为我们程序执行的开始是 076a:0000 处,但是在此处之后的16个字节已经被我们用来存放我们所定义的字型数据了,而and ax,[bx+di]就是我们所存放的数据变成汇编语言的结果。

**所产生的问题就是:**当我们的程序包含有自定义的数据时,由于计算机自动将 cs:ip 中的内容当程序执行的第一句话,我们所定义的数据会被当成命令来执行。

我们也可以推理出来,我们所希望计算机开始执行语句的地方是 076a:0010 处

image-20220521104517384

解决方式

修改代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
assume cs:codesg
codesg segment

dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h

start: mov bx,0
mov ax,0

mov cx,8
s:add ax,cs:[bx]
add bx,2
loop s

mov ax,4c00h
int 21h

codesg ends
end start

我们通过标识符 start 来告诉计算机我们的代码段所要开始执行语句的位置

image-20220521112016184

start 标识符是我们可以进行自定义的,只要是符合规定的名称都可以,其次就是保证两处的标识符要保持一致

image-20220521112326335

**end 的作用:**end 不但通知计算机程序的结束之处,还告诉了编译器程序的入口之处。

代码段中使用栈

栈的初体验

**什么是栈:**是一种数据结构,里面的数据会按照先进后出的原则进行存放使用。

问题体验:

将这些数据0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h按照逆序存放

源码:

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
27
assume cs:codesg
codesg segment

dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h
dw 0,0,0,0,0,0,0,0 //定义栈段

start: mov ax,cs
mov ss,ax //修改栈段
mov sp,20h //修改栈偏移指针,将其指向栈底-1处

mov bx,0
mov cx,8
s0: push cs:[bx]
add bx,2
loop s0 //数据入栈

mov bx,0
mov cx,8
s1: pop cs:[bx]
add bx,2
loop s1 //数据出栈

mov ax,4c00h
int 21h

codesg ends
end start

debug 后的初始状态

image-20220521120016998

执行完第一个 loop 后的状态

image-20220521120323872

执行完第二个 loop 后的状态

image-20220521120530973

**小结:**以上是我们通过在代码段中自定义数据段和栈段来实现我们的功能,但当我们的程序变得复杂是,将这些段都糊在一起会显得很杂乱且容易出错。

多个段

为了解决上面的问题,我们使用多个段。所谓的多个段就是:将数据、代码、栈放入不同的段中。

使用多个段的程序

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
27
28
29
30
31
32
33
34
35
36
assume cs:codesg,ds:data,ss:stack

data segment
dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h
data ends

stack segment
dw 0,0,0,0,0,0,0,0
stack ends

codesg segment

start: mov ax,stack
mov ss,ax
mov sp,10h

mov ax,data
mov ds,ax

mov bx,0
mov cx,8
s0: push cs:[bx]
add bx,2
loop s0

mov bx,0
mov cx,8
s1: pop cs:[bx]
add bx,2
loop s1

mov ax,4c00h
int 21h

codesg ends
end start

观察初始状态的寄存器情况

image-20220522141627231

一般来说寄存器中 DS 和 CS 的数值应当是相差 10h 的,但是这里它们相差了 12h,再观察图中的汇编语句我们可以知道我们所定义的 stack 段的段地址是 076b。

查看内存中的情况

image-20220522142509794

我们所申请的数据段和栈段被安排了代码段之前,并且每一段的空间大小都为16个字节,这也就是为什么 DS 和 CS相差了12h的原因。

对多个段的顺序进行改变

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
27
28
29
30
31
32
33
34
35
36
37
assume cs:codesg,ds:data,ss:stack

codesg segment

start: mov ax,stack
mov ss,ax
mov sp,10h

mov ax,data
mov ds,ax

mov bx,0
mov cx,8
s0: push cs:[bx]
add bx,2
loop s0

mov bx,0
mov cx,8
s1: pop cs:[bx]
add bx,2
loop s1

mov ax,4c00h
int 21h

codesg ends

data segment
dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h
data ends

stack segment
dw 0,0,0,0,0,0,0,0
stack ends

end start

当我们在程序中改变各个段的次序时,可以发现在内存中它们的位置也发生了改变

image-20220522143433185

寄存器中的 DS 和 CS 的数值相差为10h,而所申请的栈段的段地址变成了 076e,我们也可以大致推断出计算机运行我们程序的顺序是从上到下的

image-20220522144132555

本文作者:GhDemi

本文链接: https://ghdemi.github.io/2022/05/24/%E5%A4%9A%E4%B8%AA%E6%AE%B5%E7%9A%84%E7%A8%8B%E5%BA%8F/

文章默认使用 CC BY-NC-SA 4.0 协议进行许可,使用时请注意遵守协议。