跟我一起学《汇编语言》——包含多个段的程序

▲汇编语言经典教材,《汇编语言》,王爽著,清华大学出版社。后续关于汇编语言的所有讲解都是基于这本教材。

全文共2306字,阅读大约需要6分钟。

汇编语言的重要性不言而喻,如果读者想从事计算机科学方面的工作的话,汇编语言的基础是必不可少的。

汇编语言是人和计算机沟通的最简单的方式,它描述的是人和计算机沟通的最简单的方式。汇编语言不容易学习,就连简明扼要的介绍都很难找到。

那么最近一段时间,就请大家跟着我一起慢慢学习汇编语言。

本文首发于 秦巴布衣清风徐来未经授权 不得转载

大多数有用的程序,都需要处理数据,使用栈空间,当然也都必须有指令,为了程序设计上的清晰和方便,我们一般也定义不同的段来存放它们。

1

在代码段中使用数据

任务1:编程计算以下8个数据的和:

0123h,0456h,0789H,0abch,0fedH,0cbah,0987h

结果存在ax寄存器中

我们当然可以将这些数据一个个加到寄存器中,但在这里,我们希望可以用循环的方法进行累加。

所以在累加前,我们要把这些数据存到一段地址连续的内存单元中。

上一讲中,我们提到有一段安全的内存空间,但这段空间毕竟只有256个字节,如果我们需要的空间超过256个字节呢?具体做法如下:

assume cs:code

code segment

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

mov cx,8

mov ax,0

mov bx,0

s: add ax,cs:[bx]

add bx,2

loop s

mov ax,4c00h

int 21h

code ends

end

首先需要解释的是dwdwdefine word。在这里我们用dw定义了8个字型数据,它们所占的存储空间为16个字节。

进而你也许会问,这8个数据存在哪儿?

由于它们在代码段中,所以它们的段地址为CS。又因为dw定义的数据在代码段的最开始,因此偏移地址为0。每个数据占用1个字,因此bx每次加2。

让我们尝试着在DOS中将程序编译一下,结果如下图所示。

我们可以看到,CS:IP=2B28:0000,因此程序应该是从2B28:0开始执行的。然而,执行的第一条指令不是“mov cx,8”,而是一条让人看不懂的指令“and ax,[bx+di]”。

其实,因为我们在2B28:0~2B28:F中存储了dw定义的数据,因此,从2B28:10开始,才是我们真正希望执行的程序。

我们可以先用d命令来查看一下2B28:0开始的内存单元中都有什么数据。再用u命令,从2B28:10开始查看要执行的指令,结果和我们预想的一致。

可是这样就出现了一个问题,程序是从2B28:0开始执行的,而因为里面存储了一些数据,于是编译器认为这些数据是新的指令,就会造成误操作。

我们当然可以把IP设成10h,使程序从0B28:10开始执行,但这样每次都得在debug模式下执行程序,很不方便。那么有更好的解决方案么?

具体做法如下:

assume cs:code

code segment

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

start: mov cx,8

mov ax,0

mov bx,0

s: add ax,cs:[bx]

add bx,2

loop s

mov ax,4c00h

int 21h

code ends

end start

在上述程序中,我们加入了一个标号start。在编译连接后,由“end start”指明程序的入口,并把它转化为入口地址“10H”,也就是说,加载者知道了“mov cx,8”是程序的第一条指令。

再来看一下,程序就直接从2B28:10开始执行了。

2

在代码段中使用栈

任务2:利用栈,将任务1中的数据逆序存放。实现过程如下:

上述这段程序的思想大致如下:

首先,我们把数据定义在cs:0~cs:15中,再开辟一段内存空间cs:16~cs:31为栈。设置栈顶ss:sp=cs:32,我们先把数据挨个入栈,然后再依次出栈,把数据存放到cs:0~cs:15中,从而实现数据的逆序存放。

至于对设置栈顶为cs:32存在疑惑的同学,建议复习一下第一讲《寄存器》。

3

将数据、代码、栈放入不同的段

在前面的编程中,我们只有一个代码段。我们把数据、栈和代码都放在了一个段里,这样做会使程序比较混乱。

更合适的做法是,我们用多个段来存放数据、代码和栈。程序如下:

assume cs:code,ds:data,ss:stack

data segment

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

data ends

stack segment

dw 0,0,0,0,0,0,0,0

stack ends

code segment

start:mov cx,8

mov ax,cs

mov ss,ax

mov sp,32

mov bx,0

s: push cs:[bx]

add bx,2

loop s

mov bx,0

mov cx,8

s0: pop cs:[bx]

add bx,2

loop s0

mov ax,4c00h

int 21h

code ends

end start

通过第一条伪指令,我们段寄存器cs、ds、sscode、data、stack段相连。而程序的入口,通过“end start”,定位到了“mov cx,8”这一句指令处。

那么怎样才能找到一段安全的内存空间呢?在一般的PC机中,0:200~0:300的256个字节是安全的,所以当我们需要直接向内存中写入数据时,可以直接使用这段空间。

拜托了,诸位,关注一下,让我冲一冲流量主(5000人)。只要有人头数就好,觉得内容不好可以后台留言,可以不看,甚至可以屏蔽。再一次感谢!

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180625G0F13F00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券