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

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

前言


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


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



总结


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

相关文章
|
1月前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
165 9
|
1月前
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
30 1
|
19天前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
42 5
|
1月前
|
存储 算法 Java
数据结构的栈
栈作为一种简单而高效的数据结构,在计算机科学和软件开发中有着广泛的应用。通过合理地使用栈,可以有效地解决许多与数据存储和操作相关的问题。
|
1月前
|
存储 JavaScript 前端开发
执行上下文和执行栈
执行上下文是JavaScript运行代码时的环境,每个执行上下文都有自己的变量对象、作用域链和this值。执行栈用于管理函数调用,每当调用一个函数,就会在栈中添加一个新的执行上下文。
|
1月前
|
存储
系统调用处理程序在内核栈中保存了哪些上下文信息?
【10月更文挑战第29天】系统调用处理程序在内核栈中保存的这些上下文信息对于保证系统调用的正确执行和用户程序的正常恢复至关重要。通过准确地保存和恢复这些信息,操作系统能够实现用户模式和内核模式之间的无缝切换,为用户程序提供稳定、可靠的系统服务。
51 4
|
1月前
|
算法 安全 NoSQL
2024重生之回溯数据结构与算法系列学习之栈和队列精题汇总(10)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第3章之IKUN和I原达人之数据结构与算法系列学习栈与队列精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
26天前
|
算法
数据结构之购物车系统(链表和栈)
本文介绍了基于链表和栈的购物车系统的设计与实现。该系统通过命令行界面提供商品管理、购物车查看、结算等功能,支持用户便捷地管理购物清单。核心代码定义了商品、购物车商品节点和购物车的数据结构,并实现了添加、删除商品、查看购物车内容及结算等操作。算法分析显示,系统在处理小规模购物车时表现良好,但在大规模购物车操作下可能存在性能瓶颈。
42 0
|
2月前
数据结构(栈与列队)
数据结构(栈与列队)
23 1
|
2月前
【数据结构】-- 栈和队列
【数据结构】-- 栈和队列
19 0