【汇编语言】直接定址表(一)—— 「从单元标号到跨段数据:解锁汇编语言的隐藏技巧」

news/2025/1/19 12:08:08/

在这里插入图片描述

文章目录

  • 前言
  • 1. 描述了单元长度的标号
    • 1.1 旧的示例代码
    • 1.2 新的示例代码
    • 1.3 将标号当作一个段中的内存单元
    • 1.4 注意事项
  • 2. 在其他段中使用数据标号
    • 2.1 前提说明
    • 2.2 示例代码
    • 2.3 段与段寄存器的关联
    • 2.4 将标号当作数据来定义
      • 2.4.1 示例1—— 字型数据
      • 2.4.2 示例2——双字型数据
  • 结语

前言

📌

汇编语言是很多相关课程(如数据结构、操作系统、微机原理)的重要基础。但仅仅从课程的角度出发就太片面了,其实学习汇编语言可以深入理解计算机底层工作原理,提升代码效率,尤其在嵌入式系统和性能优化方面有重要作用。此外,它在逆向工程和安全领域不可或缺,帮助分析软件运行机制并增强漏洞修复能力。

本专栏的汇编语言学习章节主要是依据王爽老师的《汇编语言》来写的,和书中一样为了使学习的过程容易展开,我们采用以8086CPU为中央处理器的PC机来进行学习。

这一章,我们讨论如何有效合理地组织数据,以及相关的编程技术。

1. 描述了单元长度的标号

本章中,我们要用到这种标号,先进行如下介绍。

前面的内容中,我们一直在代码段中使用标号来标记指令、数据、段的起始地址。

1.1 旧的示例代码

比如:下面的程序将code 段中的a标号处的8个数据累加,结果存储到b标号处的字中。

assume cs:code
code segmenta : db 1,2,3,4,5,6,7,8b : dw 0start:	 mov si,offset amov bx,offset bmov cx,8s :  mov al,cs:[si]mov ah,0add cs:[bx],axinc siloop smov ax,4c00hint 21hcode ends
end start

程序中,code、a、b、start、s都是标号这些标号仅仅表示了内存单元的地址

1.2 新的示例代码

但是,我们还可以使用一种标号,这种标号不但表示内存单元的地址,还表示了内存单元的长度即表示在此标号处的单元,是一个字节单元,还是字单元,还是双字单元

上面的程序我们还可以写成这样:→→→→

assume cs:code
code segmenta db 1,2,3,4,5,6,7,8b dw 0start:    mov si,0mov cx,8s:    mov al,a[si]mov ah,0add b,axinc siloop smov ax,4c00hint 21hcode ends
end start

我们在code 段中使用的标号a、b后面没有“:”,因此它们是可以同时描述内存地址和单元长度的标号

  • 标号a,描述了地址code:0,和从这个地址开始,以后的内存单元都是字节单元

  • 而标号b描述了地址code:8,和从这个地址开始,以后的内存单元都是字单元

1.3 将标号当作一个段中的内存单元

因为这种标号包含了对单元长度的描述,所以,在指令中,它可以代表一个段中的内存单元。

比如,对于上面程序中的“b dw 0”:

  • 指令:mov ax,b —— 相当于:mov ax,cs:[8]

  • 指令:mov b,2 —— 相当于:mov word ptr cs:[8],2

  • 指令:inc b —— 相当于:inc word ptr cs:[8]

在这些指令中,标号b代表了一个内存单元,地址为code:8 ,长度为2字节。

1.4 注意事项

下面的指令会引起编译错误

mov al,b

为什么?

没错啦,聪明的你肯定意识到了。

因为b代表的内存单元是字单元,而al是8位寄存器。

因此,如果我们将程序中的指令:add b,ax ,写为 add b,al,将出现同样的编译错误。

对于程序中的“a db 1,2,3,4,5,6,7,8”:

  • 指令:mov al,a[si] —— 相当于:mov al,cs:0[si]

  • 指令:mov al,a[3] —— 相当于:mov al,cs:0[3]

  • 指令:mov al,a[bx+si+3] —— 相当于:mov al,cs:0[bx+si+3]

可见,使用这种包含单元长度的标号,可以使我们以简洁的形式访问内存中的数据

以后,我们将这种标号称为数据标号。它标记了存储数据的单元的地址和长度。它不同于仅仅表示地址的地址标号

2. 在其他段中使用数据标号

2.1 前提说明

一般来说,我们不会在代码段中定义数据,而是将数据定义到其他段中。在其他段中,我们也可以使用数据标号来描述存储数据的单元的地址和长度。

❗注意:在后面加有“:”的地址标号,只能在代码段中使用,不能在其他段中使用。

2.2 示例代码

下边程序将data段中a标号处的8个数据累加,结果存储到b标号处的字中。

assume cs:code,ds:data
data segment          a db 1,2,3,4,5,6,7,8b dw 0
data ends
code segment
start:    mov ax,datamov ds,axmov si,0mov cx,8
s:        mov al,a[si]mov ah,0add b,axinc siloop smov ax,4c00hint 21hcode ends
end start

2.3 段与段寄存器的关联

❗注意,如果想在代码段中,直接用数据标号访问数据,则需要用伪指令assume 将标号所在的和一个段寄存器联系起来

否则编译器在编译的时候,无法确定标号的段地址在哪一个寄存器中。

当然,这种联系是编译器需要的,但绝对不是说,我们因为编译器的工作需要,用 assume 指令将段寄存器和某个段相联系,段寄存器中就会真的存放该段的地址。

比如:在上面的程序中,我们要在代码段code中用data段中的数据标号 a、b 访问数据,则必须用 assume 将一个寄存器和data 段相联。

在程序中,我们用ds寄存器和data段相联,则编译器对相关指令的编译如下:

  • 指令:mov al,a[si] —— 编译为:mov al,[si+0]

  • 指令:add b,ax —— 编译为:add [8],ax

因为这些实际编译出的指令,都默认所访问单元的段地址在ds中,而实际要访问的段为data,所以,若要访问正确,在这些指令执行前,ds 中必须为 data 段的段地址。

则,我们在程序中使用指令:

mov ax,data
mov ds,ax

设置ds指向data段。

2.4 将标号当作数据来定义

我们可以将标号当作数据来定义,此时,编译器将标号所表示的地址当作数据的值。

2.4.1 示例1—— 字型数据

比如:

data segmenta db 1,2,3,4,5,6,7,8b dw 0c dw a,b
data ends

数据标号c处存储的两个字型数据为标号a、b 的偏移地址

相当于:

data segmenta db 1,2,3,4,5,6,7,8b dw 0c dw offset a, offset b
data ends

2.4.2 示例2——双字型数据

再比如:

data segmenta db 1,2,3,4,5,6,7,8b dw 0c dd a,b
data ends

数据标号c处存储的两个双字型数据为标号a的偏移地址和段地址、标号b 的偏移地址和段地址

相当于:

data segmenta db 1,2,3,4,5,6,7,8b dw 0c dw offset a, seg a, offset b, seg b
data ends

seg操作符,功能为取得某一标号的段地址

结语

今天的分享到这里就结束啦!如果觉得文章还不错的话,可以三连支持一下。

也可以点点关注,避免以后找不到我哦!

Crossoads主页还有很多有趣的文章,欢迎小伙伴们前去点评,您的支持就是作者前进的动力!

在这里插入图片描述


http://www.ppmy.cn/news/1564404.html

相关文章

FIDO2密码钥匙与无密码认证:打造安全便捷的数字世界

在数字化时代,密码曾被视为网络安全的基石,但随着网络攻击手段日益复杂,传统的密码认证方法越来越无法抵御这些挑战。对于用户来说,登录密码不仅繁琐易忘,而且一旦泄露,往往会导致数据泄露,造成…

PDF工具箱 PDF24 ,免费下载,非常好用

这是一套免费无限制的PDF 处理工具合集。 包含了 27 个 PDF 工具。涵盖了PDF 合并、分割、编辑、压缩、格式转换(Word、Excel、图片等)、OCR 文本识别、添加水印等诸多功能! 而且所有功能都可以免费使用,没有文件大小等任何限制…

C# 获取PDF文档中的字体信息(字体名、大小、颜色、样式等

在设计和出版行业中,字体的选择和使用对最终作品的质量有着重要影响。然而,有时我们可能会遇到包含未知字体的PDF文件,这使得我们无法准确地复制或修改文档。获取PDF中的字体信息可以解决这个问题,让我们能够更好地处理这些文件。…

Java线程全解析:从创建到同步的终极指南

哈喽,各位小伙伴们,你们好呀,我是喵手。运营社区:C站/掘金/腾讯云/阿里云/华为云/51CTO;欢迎大家常来逛逛 今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流,互…

在 Go语言中一个字段可以包含多种类型的值的设计与接种解决方案

在 Go 中,如果你希望一个字段可以包含多种类型的值,你可以使用以下几种方式来实现: ### 1. **使用空接口 (interface{})** Go 的空接口 interface{} 可以接受任何类型的值,因此,你可以将字段定义为一个空接口&#x…

【代码随想录】刷题记录(104)-不同的二叉搜索树

题目描述: 给你一个整数 n ,求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。 示例 1: 输入:n 3 输出:5示例 2: 输入:n …

Ubuntu VPS 上 Docker 部署 Nginx 服务器详细教程

引言 本文将详细介绍如何在 Azure 100 学生订阅中创建一台 Ubuntu VPS,并在其上利用 Docker 部署 Nginx 服务器。我们将涵盖 Docker 和 Nginx 的基础概念,以及部署过程中所需的每个步骤。 Docker 简介 Docker 是一个开源的容器化平台,它可…

个人vue3-学习笔记

声明:这只是我个人的学习笔记(黑马),供以后复习用 。一天学一点,随时学随时更新。明天会更好的! 这里只给代码,不给运行结果,看不出来代码的作用我也该进厂了。。。。。 Day1 使用create-vue创建项目。 1.检查版本。 node -v 2.创建项目 npm init vue@latest 可…