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

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

前言


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


一、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



总结


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

目录
打赏
0
1
0
0
61
分享
相关文章
|
4月前
|
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
70 1
|
2月前
|
【C++数据结构——栈与队列】顺序栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现顺序栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 1.初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储
174 77
|
26天前
|
STL——栈和队列和优先队列
通过以上对栈、队列和优先队列的详细解释和示例,希望能帮助读者更好地理解和应用这些重要的数据结构。
28 11
☀☀☀☀☀☀☀有关栈和队列应用的oj题讲解☼☼☼☼☼☼☼
### 简介 本文介绍了三种数据结构的实现方法:用两个队列实现栈、用两个栈实现队列以及设计循环队列。具体思路如下: 1. **用两个队列实现栈**: - 插入元素时,选择非空队列进行插入。 - 移除栈顶元素时,将非空队列中的元素依次转移到另一个队列,直到只剩下一个元素,然后弹出该元素。 - 判空条件为两个队列均为空。 2. **用两个栈实现队列**: - 插入元素时,选择非空栈进行插入。 - 移除队首元素时,将非空栈中的元素依次转移到另一个栈,再将这些元素重新放回原栈以保持顺序。 - 判空条件为两个栈均为空。
|
2月前
|
【C++数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】
【数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】初始化队列、销毁队列、判断队列是否为空、进队列、出队列等。本关任务:编写一个程序实现环形队列的基本运算。(6)出队列序列:yzopq2*(5)依次进队列元素:opq2*(6)出队列序列:bcdef。(2)依次进队列元素:abc。(5)依次进队列元素:def。(2)依次进队列元素:xyz。开始你的任务吧,祝你成功!(4)出队一个元素a。(4)出队一个元素x。
78 13
【C++数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】
|
2月前
|
【C++数据结构——栈与队列】链栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现链栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储整数,最大
58 9
|
2月前
|
C++
【C++数据结构——栈和队列】括号配对(头歌实践教学平台习题)【合集】
【数据结构——栈和队列】括号配对(头歌实践教学平台习题)【合集】(1)遇到左括号:进栈Push()(2)遇到右括号:若栈顶元素为左括号,则出栈Pop();否则返回false。(3)当遍历表达式结束,且栈为空时,则返回true,否则返回false。本关任务:编写一个程序利用栈判断左、右圆括号是否配对。为了完成本关任务,你需要掌握:栈对括号的处理。(1)遇到左括号:进栈Push()开始你的任务吧,祝你成功!测试输入:(()))
52 7
数据结构的栈
栈作为一种简单而高效的数据结构,在计算机科学和软件开发中有着广泛的应用。通过合理地使用栈,可以有效地解决许多与数据存储和操作相关的问题。
149 21
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
117 5
|
4月前
|
数据结构之购物车系统(链表和栈)
本文介绍了基于链表和栈的购物车系统的设计与实现。该系统通过命令行界面提供商品管理、购物车查看、结算等功能,支持用户便捷地管理购物清单。核心代码定义了商品、购物车商品节点和购物车的数据结构,并实现了添加、删除商品、查看购物车内容及结算等操作。算法分析显示,系统在处理小规模购物车时表现良好,但在大规模购物车操作下可能存在性能瓶颈。
86 0