前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >汇编干货第三章

汇编干货第三章

作者头像
天钧
发布2019-07-25 10:34:36
5710
发布2019-07-25 10:34:36
举报
文章被收录于专栏:渗透云笔记渗透云笔记

包含多个段的程序

前面说道,如果要使用安全的内存空间,0:200~0:2FF是相对安全得内存空间,可是这段空间只有256字节,如果需要的空间大于256字节该怎么办呢?

在操作系统允许的情况下,程序可以取得任意容量的空间。

取得空间的方法有两种。

  • 加载程序时为程序分配
  • 执行过程中向系统申请(这里不讨论)

若要一个程序在加载时取得所需的空间,则必须在源程序做出说明。

上面是从内存空间获取的角度上,谈定义段的问题。为了可读性、功能设计,一般一额定义不同的段来存放。

关于段的问题,我们将以这样的顺序讨论多个段的问题:

  • 在一个段中存放数据、代码、栈;
  • 将数据、代码、栈放入不同的段中。

在代码段中使用数据

我们可以在程序中,定义我们希望处理的数据,数据作为程序的一部分一同被编译、链接写到可执行文件中。

考虑这样一个问题,编程计算8个数据的和,结果存放在AX寄存器中,下面是用我们前面知识写出的代码。

这里出现了一个新的指令dwdw即“define word”,在这里,定义了8个字型数据,占用16字节的内存空间。

使用Debug调试程序,不运行,发现一个问题,程序所在的内存区为075C:0(DS=075C),前256字节存放着PSP,程序的存放位置应为076C:0,使用U指令查看确发现有点不对。

实际上,看到其实是有dw定义的数据,从第16字节开始才是汇编指令对应的机器码。

怎样执行程序中的指令呢?在Debug中,可以手动修改IP寄存器的值,从而使CS:IP指向程序的另一条指令。

这样一来,在系统运行时就会出现问题,程序的入口不是我们希望执行的指令。

借助伪指令可以通知编译器程序的入口。

有了这个指令,可以仿照这个模板写出更多的程序,start上面安排数据,startend start之间安排代码。

在代码段中使用栈

这里的检测点没做出来,看视频才想通的,后来发现这个题目第一眼没看懂。

检测点考察dw定义的数据在内存空间的位置,理解了这一点,题目就可以做出来了。

注释未知的指令,在debug模式中运行可以直观的感受到到这一点。

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

前面的内容中,我们将数据、栈和代码都放到了一个段里面,编程的时候需要注意何处是数据,何处是栈,何处是代码。显然这样有问题:

  • 程序混乱
  • 8086的段空间限制只有64KB

下面的程序用不同的段实现了上面的功能

  • 对于不同的段,使用不同的段名联系不同的段寄存器。
  • 注意红线的部分,段名相当于一个标号,代表了段地址,8086CPU不允许将一个数值送入段寄存器,因此使用其它寄存器中转
  • “代码段”、“数据段”、“栈段”完全是我们的安排 CPU如何处理定义的段的内容,取决与程序中具体的汇编指令。
    • 段名只是为了阅读性
    • cs:code等代码将段名和寄存器联系起来
    • end start指明了程序的入口,CS:IP指向这个入口,从而执行程序的第一条指令

编写、调试具有多个段的程序

这里是两个检测点,为了理解不同段在内存空间中的排列,一个段在内存空间中最小单位为16字节。

限于篇幅原因,我这里介绍比较最后的一个实验。

程序如下,编写code段的代码,用push指令将a段中的前8个字型数据逆序存储在b段中。

写出程序很容易,不过这不是我要说的重点。

程序运行完之后,查看内存空间,注意我这里查看的DS。

从数据对应关系不难判断,76C:00~76C:1F是我们定义的数据段, 076C:20~76C:2E是我们定义的栈段,76C:30之后是代码段。

查看对应的寄存器,也验证了这一点,

$076C \times 10H+0=76C0H=76C \times 10H+0$

$076C \times 10H+20=76E0H=76E \times 10H+0$

$076C \times10H+30=76F0H=76F \times 10H+0$

这里主要涉及到了一些段编译的规则,编译的规则影响了内存的分配。我们在使用SSD格式化的时候,有一个选项为4K对齐,4K对齐是为了让操作系统的最小分配单元和闪存的一个页对应,提高读写效率,实际使用过程中,即使文件没有那么大,实际占用的均为4KB的倍数,在这一点上和编译规则有些相似。

更灵活的定位内存地址的方法

前面,我们用[0]、[bx]的方法,定位内存单元的地址。本章介绍更为灵活的定位内存地址和相关的编程方法。

and和or指令

代码语言:javascript
复制
;and指令:逻辑与指令,按位进行与运算
mov al,00001111B
and al,11110000B
;执行后AL=00000000B  相应位设为0
;or指令:理解与指令,按位进行或运算
mov al,00001111B
or  al,11110000B
;执行后 AL=11111111B 相应位设为1

以字符形式给出的数据

计算机中所有的信息都是二进制,而人能理解的信息是具有约定意义的字符。将字符存储在计算机中,就要对其进行编码。计算机存储的信息展示给我们看时,就要对其进行解码。

ASCII是基于拉丁字母的一套编码系统。例如,文件编辑过程中,按一下按键的“a”键,计算机用ASII码规则编码为61H存储在内存中;文件编辑器从内存中取出61H,送入显卡上的显存中;显卡用ASII码的规则解释显存的内容,显卡驱动显示器,我们在显示器看到了字符“a”。

我们可以在汇编程序中,用‘……‘的方式指明数据是以字符的形式给出,编译器将转化为相对应的ASCII码。

大小写转换的问题

在codesg中填写代码(我这里写好了),将datasg中的第一个字符串转化为大写,第二个字符转化为小写。

查看字母的ASCII表。

可以发现,大写字母到小写字母在于寄存器中第5个字符的不同(我没说错,从右往左数,从0到7),那么这道题的关键在于将第5个字符置0的转换了,写出上面的代码就很简单了。

[bx+idata]

前面使用[bx]的方式来指明一个内存单元,还可以使用[bx+idata]来表示内存单元,他的偏移地址为[bx]+idata。

有了这个特性,前面我们做过一道将a段和b段的内容相加到c段中的题目,可以将代码优化。

可以看出灵活的内存访问方式,减少了指令,加快的程序运行速度。

SI+DI

SI和DI是8086CPU中和BX功能相近的寄存器,SI和DI不能分成两个8为寄存器来使用

[bx+si]和[bx+di]

在前面,我们用[bx]和[bx+idata]的方式来指明一个内存单元,还可以使用更为灵活的方式:[bx+si]和[bx+di]

[bx+si]表示一个内存单元,它的偏移地址为(bx)+(si)(即bx中的数值加上si的数值)

[bx+si+idata]和[bx+di+idata]

[bx+si+idata]表示一个内存单元,偏移地址为(bx)+(si)+(idata)。

不同的寻址方式的应用

  • [idata]用一个常量表示内存地址,可直接定位一个内存单元
  • [bx]用一个变量表示内存地址,可间接定位一个内存单元
  • [bx+idata]用一个变量和常量表示内存地址,可在一个起始位置的基础上用变量间接定位一个内存单元
  • [bx+si]用两个变量表示地址
  • [bx+si+idata]用两个变量和一个常量便是地址。

如下图,将datasg段中的每个单词改为大写字母

db指令和dw指令类似,不过他定义的是字节型数据

总共数据有4行,每行有3个字母需要更改,也就是$4\times3$此二重循环,有限的循环可以使用loop指令,这里需要存储两个循环次数,经过艰苦的思考(并没有,我想不出来,看书上思路了),可以使用空寄存器DX暂存,循环完成后又拿回(下图左)。

程序中进场需要进行数据的暂存,寄存器的数量有限,如果不适用寄存器,只能使用内存了,我们开辟了新的一块内存,先存放在内存中,需要的时候在从内存单元中恢复(下图中)。

我们使用内存来暂存数据,这是比较聪明的选择,但是值得推敲的是,我们用怎样的结构来保存这些数据,从而使程序更为清晰。

一般来说,在需要暂存数据的时候,都应该使用栈。

我们使用栈暂存数据,采用相关的指令将数据入栈,需要时在出栈(下图右)。

为什么要用[bx+si+data]的形式来表示?

  • 为了可阅读性,理解数据的起始,体现了偏移的思想

程序如何改进?

  • 更多的数据入栈,比如上面的BX进行入栈

数据处理的两个基本问题

  • 处理的数据在什么地方
  • 要处理的数据有多长

reg和sreg

定义描述性的符号reg和sreg,reg表示一个寄存器,sreg表示一个段寄存器。

reg:x、bx、cx、dx、ah、al、bh、bl、cx、bl、dh、dl、sp、bp、si、di;

sreg:ds、ss、cs、es

bx、si、di和bp

  • 8086CPU中,只有这4个寄存器可以用在[…]中进行内存单元寻址
  • […]可以单个出现,或只能以4中组合出现:bx和si、bx和di、bp和si、bp和di.
  • 指令没有显性给出段地址,段地址就默认在SS中。

处理的数据在什么地方

机器指令不关心数据的值多少,而关心指令执行前一刻,它将要处理的数据所在的位置。指令执行前,处理的数据可以在3个地方:CPU内部、内存、端口(后面介绍)

汇编语言中数据的表达

  • 立即数:直接在包含在机器指令中的数据(执行前在CPU的指令缓冲器中),称为立即数(idata)
  • 寄存器:数据在寄存器中,给出寄存器名使用
  • 段地址(SA)和偏移地址(EA):段地址默认在DS中,若BP做为有效地址的一部分,段地址默认在SS中,可以显性给出段寄存器

寻址方式

数据存放在内存中的时候,可是用多种方式给定这个内存单元的偏移地址,这种定位内存单元的方法一般被称为寻址方式。

指令的数据有多长

8086CPU中,可以处理两种尺寸的数据,byte和word。所以在机器指令中要指明,指令进行的是字操作还是字节操作。

  • 通过寄存器指明要处理的数据的尺寸,mov ax,1mov al,1
  • 没有寄存器时,用操作符指明:X ptr指明内存单元长度,X可以为word或byte

顺便说一下,[bx].10h[si]=[bx+16+si]

div指令

div是触发指令

  • 除数:有8位和16位两种,在一个reg或内存单元中
  • 被除数:默认放在AX或DX和AX中
    • 如果除数为8位,则被除数则为16位,默认在AX中存放
    • 如果除数为16位,被除数为32位,在DX和AX中存放,DX存放高16位,AX存放低16位
  • 结果
    • 如果除数为8位,AL存储除法操作的商,AH存储除法操作的余数
    • 如果除数为16位,AX存储除法操作的商,DX存储除法操作的余数

单纯看这段话容易看懵,在debug模式中试验下。

说明,这里演示的是$\frac{16}{3}=5\cdots\cdots1 $,其中16的部分在指令中我使用的是十六进制”10H“。

伪指令dd

前面使用dbdw定义字节型数据和字型数据。dd用来定义dword(double word,双字)型数据

伪指令dup

dup是一个操作符,同db、dw、dd等一样,也是由编译器识别处理的符号。配合db、dw、dd等数据定义伪指令使用,用来进行数据的重复。

使用的格式如下

代码语言:javascript
复制
db 重复的次数  dup (重复的字节型数据)
dw 重复的次数  dup (重复的字型数据)
dd 重复的次数  dup (重复的双字型数据)

实验七

这里基本将所有的知识都运用起来了,笔者自己做的时候感觉自己好渣,想不出来。还是需要进行分析,理解数据从哪里来,到哪里去,中间做了什么。

题目是将data中的年、收入、计算的人均收入写到table段中。直接给代码。

  • 年份的传递,可以使用寄存器,使用栈明显是更好的选择
  • 使用相应的寄存器存储偏移量,可以使用[bx+idata]访问数据节省寄存器
  • 除法运算中被除数为双字,使用AX、DX分别存储低16位和高16位,将AX中的商传递到Table段
实验的反思

这个实验的段名仿佛在暗示什么,回顾我们做了什么,我们将零散的数据结构化,使数据阅读性提升,使用偏移地址访问非常遍历。换句话说,如果编写程序时,将数据结构化,程序效率也将提升。程序的效率与数据组织的合理不合理有关,有一门课程叫数据结构,讲的就是这么个问题。

本质上可以归纳为对数据的组织,而下一章转移指令的原理,本质上是对代码的组织。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-07-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 渗透云笔记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 包含多个段的程序
    • 在代码段中使用数据
      • 在代码段中使用栈
        • 将数据、代码、栈放入不同的段
          • 编写、调试具有多个段的程序
          • 更灵活的定位内存地址的方法
            • and和or指令
              • 以字符形式给出的数据
                • 大小写转换的问题
                  • [bx+idata]
                    • SI+DI
                      • [bx+si]和[bx+di]
                        • [bx+si+idata]和[bx+di+idata]
                          • 不同的寻址方式的应用
                          • 数据处理的两个基本问题
                            • reg和sreg
                              • bx、si、di和bp
                                • 处理的数据在什么地方
                                  • 汇编语言中数据的表达
                                    • 寻址方式
                                      • 指令的数据有多长
                                        • div指令
                                          • 伪指令dd
                                            • 伪指令dup
                                              • 实验七
                                                • 实验的反思
                                            相关产品与服务
                                            对象存储
                                            对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
                                            领券
                                            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档