【汇编】在代码段使用数据,在代码段使用栈

简介: 【汇编】在代码段使用数据,在代码段使用栈

前言


汇编语言中,合理地管理数据和栈是编写高效程序的重要一环。本文将探讨在代码段使用数据和在代码段使用栈的两个关键概念。代码段是存储程序指令的地方,而数据段和栈则是用来存储程序运行时所需的数据和执行过程中的临时信息。通过深入了解这两者的使用方式,我们可以更好地优化程序的性能和可读性。


一、8086中的es寄存器


1.1 es寄存器是什么

在8086 CPU中,ES 寄存器是一个特殊的寄存器,全称为 Extra Segment Register(附加段寄存器)。它的主要作用是帮助CPU找到程序中一些特定数据的家庭地址。

想象一下你住在一个大公寓楼里。楼房号是段地址,而你的家门号是偏移地址。ES 寄存器就像是告诉你的朋友,你住在哪个大楼里。当你朋友来找你时,先知道了楼房号(段地址),然后再通过你提供的门牌号(偏移地址)就能准确地找到你的家。

在实际编程中,ES 寄存器通常用于在处理字符串、数组等数据时,指示这些数据所在的段地址。这样,CPU可以更方便地访问并处理这些数据。


1.2 ds和es寄存器

大家会不会疑惑,前面不是学过ds为段地址吗,为什么又来一个es,其实他们不一样

在8086 CPU中,DS 寄存器和 ES 寄存器都是段寄存器,但它们各自有不同的主要用途。

DS 寄存器(Data Segment Register)通常用于指向程序的数据段,存储程序中常用数据的地址信息。当程序需要访问变量、数组或其他数据时,DS 寄存器提供了这些数据所在段的地址。

ES 寄存器(Extra Segment Register)则是一个额外的段寄存器,通常用于协助处理一些特殊操作,比如在一些字符串操作中,ES 可以被用来指示额外的目标段地址,以便更便捷地进行数据传输或操作。

虽然 DS 和 ES 寄存器都是用来存储段地址,但它们的使用场景不同。DS 主要指向程序的数据段,而 ES 在一些特殊操作中提供了额外的段地址信息,帮助程序更有效地执行某些任务,比如字符串处理、内存操作等。


那么他们的操作是一样的


二、在代码段使用数据


2.1 一个危险的问题

例:将内存ffff:0~ffff:b中的数据拷贝到 0:200~0:20b单元中。

8ab7c2049632443498c4bb4eb1b186e0.png


问题

程序中直接写地址,危险!

“安全”位置存放数据,存哪里?

对策

在程序的段中存放数据,运行时由操作系统分配空间。

段的类别:数据段、代码段、栈段

各种段中均可以有数据

可以在单个的段中安置,也可以将数据、代码、栈放入不同的段中。

应用案例

问题:编程计算以下8个数据的和,结果存在ax 寄存器中

0123H,0456H,0789H,0abcH,0defH,0fedH,0cbaH,0987H

解决方案1:

assume cs:codesg
codesg segment
  dw 0123h,0456h,0789h,0abch,0defh,0cbah,0987h
  mov bx,0
    mov cx,8
    mov ax,0
    s:add ax,cs:[bx]
      add bx,2
      loop s
    mov ax,4c00h
    int 21h
codesg ends
end start


f97e97325edf4defa90971d15072f5f7.png

dw: define word,

定义字型数据

dw 定义一个字

db 定义一个字节

dd 定义一个双字

470579c5944b4a148489bb860a25c2b1.png

这个程序有问题!

但是很遗憾,这个程序还是有问题,

我们使用u命令查看他,发现第一个不是mov bx,0,而是变成其他的了,和我们之前学的不符

解决问题的关键:让数据从CS:0000开始,让代码从CS:0010开始


这样改进

解决方案2

定义一个标号,指示代码开始的位置。

效果:程序加载后,CS:IP指向要执行的第一条指令在start处!

assume cs:codesg
codesg segment
  dw 0123h,0456h,0789h,0abch,0defh,0cbah,0987h
start:  mov bx,0
        mov cx,8
        mov ax,0
        s:add ax,cs:[bx]
          add bx,2
          loop s
        mov ax,4c00h
        int 21h
codesg ends
end start


e3e0a41f60cb44369e1f460b3dde6782.png

start即是标号,在end后面加上标号

然后cs就会先指向start这里了,我们在程序中使用还是从0000:0开始使用

016867cc396f4759a8f9a6dae5b1970f.png


三、在代码段使用栈


3.1 在代码段中使用栈:以数据逆序存放为例

问题

完成下面的程序,利用栈,将程序中定义的数据逆序存放。

assume cs:codesg
codesg segment
dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h
?
code ends
end


e00f5e2bdfa64a1c96fe829abb3c3c60.png

程序的思路大致如下:

程序运行时,定义的数据存放在cs:0~cs:F单元中,共8个字单元。

依次将这8个字单元中的数据入栈,然后再依次出栈到这 8 个字

单元中,从而实现数据的逆序存放。

栈需要的内存空间,在程序中通过定义“空”数据来取得。


数据逆序存放程序

assume cs:codesg
codesg segment
  dw 0123H,0456H,0789H,0abcH,0defH,0fedH,0cbaH,0987H
  dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  start: mov ax,cs
    mov ss,ax
    mov sp,30h
    ; 入栈
    ; 出栈
    mov ax,4c00h
    int 21h
codesg ends
end start


c0a7961a9d9a4ba4b9e8ec217a01cfdf.png

我们可以写出上面这个程序,

ss和sp指定栈的段地址和偏移地址,因为一开始的8个字占了16个字节,所以把栈放到30h,不要重复了

入栈代码

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


出栈代码

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


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


4.1 评价这种方案

assume cs:codesg
codesg segment
  dw 0123H,0456H,0789H,0abcH,0defH,0fedH,0cbaH,0987H
  dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  start: mov ax,cs
    mov ss,ax
    mov sp,30h
    ; 入栈
    ; 出栈
    mov ax,4c00h
    int 21h
codesg ends
end start


这种方式固然是可以的,当数据量小的时候可以用,但是当数据量大的时候,我们就需要把他们放在不同的段里面。


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

我们使用下面这种格式声明一个段:

段的名称 segment
数据...
段的名称 ends


4.3 进行改进

逆序读取就可以变成下面这样

我们可以使用段的名称来告诉他段的地址

比如:mov ax,stack就是把stack的段地址放入ax中

assume cs:codesg
codesg segment
data segment
  dw 0123h,0456h,0789h,0abch,0defh,0cbah,0987h
data ends
stack segment
  dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
stack ends
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 bx,0
        mov cx,8
        s0: pop [bx]
        add bx,2
        loop s0
        mov ax,4c00h
        int 21h
codesg ends
end start



总结


在代码段使用数据和使用栈是汇编程序中的两个重要概念。合理地在代码段中存储常量和初始化数据,以及灵活地利用栈来管理函数执行过程中的数据,都是优化程序性能和可读性的有效手段。深入理解这两个概念,有助于编写更高效、清晰的汇编代码。希望本文能够帮助读者更好地理解在代码段使用数据和使用栈的原理和实践。

相关文章
|
3天前
|
算法 安全 测试技术
golang 栈数据结构的实现和应用
本文详细介绍了“栈”这一数据结构的特点,并用Golang实现栈。栈是一种FILO(First In Last Out,即先进后出或后进先出)的数据结构。文章展示了如何用slice和链表来实现栈,并通过golang benchmark测试了二者的性能差异。此外,还提供了几个使用栈结构解决的实际算法问题示例,如有效的括号匹配等。
golang 栈数据结构的实现和应用
01_设计一个有getMin功能的栈
01_设计一个有getMin功能的栈
|
3天前
|
前端开发
07_用队列实现栈
07_用队列实现栈
06_用栈来求解汉诺塔问题
06_用栈来求解汉诺塔问题
05_用一个栈实现另一个栈的排序
05_用一个栈实现另一个栈的排序
03_如何仅用递归函数和栈操作逆序一个栈
03_如何仅用递归函数和栈操作逆序一个栈
|
3天前
|
测试技术
02_由两个栈组成的队列
02_由两个栈组成的队列
|
7天前
|
存储
|
22天前
|
存储 人工智能 C语言
数据结构基础详解(C语言): 栈的括号匹配(实战)与栈的表达式求值&&特殊矩阵的压缩存储
本文首先介绍了栈的应用之一——括号匹配,利用栈的特性实现左右括号的匹配检测。接着详细描述了南京理工大学的一道编程题,要求判断输入字符串中的括号是否正确匹配,并给出了完整的代码示例。此外,还探讨了栈在表达式求值中的应用,包括中缀、后缀和前缀表达式的转换与计算方法。最后,文章介绍了矩阵的压缩存储技术,涵盖对称矩阵、三角矩阵及稀疏矩阵的不同压缩存储策略,提高存储效率。
|
5天前
|
安全 JavaScript 前端开发
栈溢出漏洞传播Worm.Delf.yqz
栈溢出漏洞传播Worm.Delf.yqz
下一篇
无影云桌面