【汇编语言】更灵活的定位内存地址的方法(二)—— 从 [bx+idata] 到 [bx+si+idata]:让你灵活的访问内存

文章目录

  • 前言
  • [1. [bx+idata]](#1. [bx+idata])
    • [1.1 更加灵活的访问内存](#1.1 更加灵活的访问内存)
    • [1.2 示例](#1.2 示例)
    • [1.3 问题一](#1.3 问题一)
    • [1.4 问题一的分析与求解](#1.4 问题一的分析与求解)
  • [2. 用[bx+idata]的方式进行数组的处理](#2. 用[bx+idata]的方式进行数组的处理)
    • [2.1 问题引入](#2.1 问题引入)
    • [2.2 原来的解决方案](#2.2 原来的解决方案)
    • [2.3 新的解决方案](#2.3 新的解决方案)
      • [2.3.1 改进后的程序](#2.3.1 改进后的程序)
      • [2.3.2 还可以写成这样](#2.3.2 还可以写成这样)
      • [2.3.3 用C语言来描述看看](#2.3.3 用C语言来描述看看)
    • [2.4 比较与总结](#2.4 比较与总结)
  • [3. SI和DI](#3. SI和DI)
    • [3.1 介绍两种寄存器](#3.1 介绍两种寄存器)
    • [3.2 问题二](#3.2 问题二)
    • [3.3 问题二的分析与求解](#3.3 问题二的分析与求解)
    • [3.4 问题三](#3.4 问题三)
    • [3.5 问题三的分析与求解](#3.5 问题三的分析与求解)
  • [4. [bx+si]和[bx+di]](#4. [bx+si]和[bx+di])
    • [4.1 更加更加灵活的访问内存](#4.1 更加更加灵活的访问内存)
    • [4.2 问题四](#4.2 问题四)
    • [4.3 问题四的分析与求解](#4.3 问题四的分析与求解)
  • [5. [bx+si+idata]和[bx+di+idata]](#5. [bx+si+idata]和[bx+di+idata])
    • [5.1 更加更加更加灵活的访问内存](#5.1 更加更加更加灵活的访问内存)
    • [5.2 问题五](#5.2 问题五)
    • [5.3 问题五的分析与求解](#5.3 问题五的分析与求解)
  • 结语

前言

📌

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

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

1. [bx+idata]

1.1 更加灵活的访问内存

在前面,我们用[bx]的方式来指明一个内存单元,还可以用一种更为灵活的方式来指明内存单元:[bx+idata]表示一个内存单元,它的偏移地址为(bx)+idata(bx 中的数值加上idata)。

1.2 示例

我们看一下指令 mov ax,[bx+200]的含义:

将一个内存单元的内容送入ax,这个内存单元的长度为2个字节(字单元),存放一个字,偏移地址为bx中的数值加上200,段地址在ds中。

数学化的描述为:(ax)=((ds)*16+(bx)+200)

该指令也可以写成如下格式(常用):

  • mov ax,[200+bx]
  • mov ax,200[bx]
  • mov ax,[bx].200

1.3 问题一

Debug 查看内存,结果如下:

2000:1000 BE 00 06 00 00 00 ...

写出下面的程序执行后,ax、bx、cx中的内容是什么。

assembly 复制代码
mov ax,2000H
mov ds,ax
mov bx,1000H
mov ax,[bx]
mov cx,[bx+1]
add cx,[bx+2]

思考后看分析。

1.4 问题一的分析与求解

assembly 复制代码
mov ax,[bx]   

访问的字单元的段地址在ds中,(ds)=2000H;偏移地址在bx 中,(bx)=1000H;指令执行后(ax)=00BEH。

assembly 复制代码
mov cx,[bx+1]    

访问的字单元的段地址在ds中,(ds)=2000H;偏移地址=(bx)+1=1001H;指令执行后(cx)=0600H。

assembly 复制代码
add cx,[bx+2]

访问的字单元的段地址在ds中,(ds)=2000H;偏移地址=(bx)+2=1002H;指令执行后(cx)=0606H。

2. 用[bx+idata]的方式进行数组的处理

有了[bx+idata]这种表示内存单元的方式,我们就可以用更高级的结构来看待所要处理的数据。我们通过下面的问题来理解这一点。

2.1 问题引入

在codesg 中填写代码,将 datasg 中定义的第一个字符串 转化为大写,第二个字符串转化为小写。

assembly 复制代码
assume cs:codesg,ds:datasg

datasg segment
	db 'BaSiC'
	db 'MinIX'
datasg ends

codesg segment
 start: ......
codesg ends

end start

2.2 原来的解决方案

按照我们原来的方法,用[bx]的方式定位字符串中的字符。代码段中的程序如下:

assembly 复制代码
	   mov ax,datasg
       mov ds,ax	
       mov bx,0	
       
       mov cx,5			
    s: mov al,[bx]		
       and al,11011111b		
       mov [bx],al	
       inc bx			
       loop s
       
       mov bx,5
       mov cx,5		
   s0: mov al,[bx]
       or al,00100000b		
       mov [bx],al
       inc bx
       loop s0

2.3 新的解决方案

现在,我们有了 [bx+idata]的方式,就可以用更简化的方法来完成上面的程序。

观察datasg段中的两个字符串,一个的起始地址为0,另一个的起始地址为5。我们可以将这两个字符串看作两个数组,一个从0地址开始存放,另一个从5开始存放。

那么我们可以用[0+bx]和[5+bx]的方式在同一个循环中定位这两个字符串中的字符。在这里,0和5给定了两个字符串的起始偏移地址,bx中给出了从起始偏移地址开始的相对地址。

这两个字符串在内存中的起始地址是不一样的,但是,它们中的每一个字符,从起始地址开始的相对地址的变化是相同的。

2.3.1 改进后的程序

改进后的程序如下:

assembly 复制代码
	mov ax,datasg
	mov ds,ax
	mov bx,0

	mov cx,5
s:	mov al,[bx]		;定位第一个字符串的字符
	and al,11011111b
	mov [bx],al
	mov al,[5+bx]	;定位第二个字符串的字符
	or al,00100000b
	mov [5+bx],al
	inc bx
	loop s

2.3.2 还可以写成这样

程序也可以写成下面的样子:

assembly 复制代码
 	mov ax,datasg
	mov ds,ax
	mov bx,0

	mov cx,5
s:	mov al,0[bx]		;这里换了一种表达方式,下面也是。
	and al,11011111b
	mov 0[bx],al
	mov al,5[bx]		
	or al,00100000b
	mov 5[bx],al
	inc bx
	loop s

2.3.3 用C语言来描述看看

如果我们用高级语言,比如C语言来描述上面的程序,大致是这样的:

c 复制代码
char a[5]="BaSiC";
char b[5]="MinIX";
int main()
{
    int i;
    i=0;
    do
    {
        a[i]=a[i]&0xDF;
        b[i]=b[i]&0x20;
        i++;
    }while(i<5);
}

2.4 比较与总结

如果你熟悉C语言的话,可以比较一下这个C程序和上面的汇编程序的相似之处。尤其注意它们定位字符串中字符的方式:

  • C语言定位方式:a[i],b[i]

  • 汇编语言定位方式:0[bx],5[bx]

✍通过比较,我们可以发现:[bx+idata]的方式为高级语言实现数组提供了便利机制。

3. SI和DI

3.1 介绍两种寄存器

si和di是8086CPU中和bx功能相近的寄存器,但是si和di不能够分成两个8 位寄存器来使用。

下面的三组指令实现了相同的功能:

(1) mov bx,0

​ mov ax,[bx]

(2) mov si,0

​ mov ax,[si]

(3) mov di,0

​ mov ax,[di]

下面的三组指令也实现了相同的功能:

(1) mov bx,0

​ mov ax,[bx+123]

(2) mov si,0

​ mov ax,[si+123]

(3) mov di,0

​ mov ax,[di+123]

3.2 问题二

用寄存器si和di实现将字符串'welcome to masm!'复制到它后面的数据区中。

assembly 复制代码
 assume cs:codesg,ds:datasg
    datasg segment 
      db 'welcome to masm!'
      db '................'
    datasg ends

思考后看分析。

3.3 问题二的分析与求解

我们编写的程序大都是进行数据的处理,而数据在内存中存放,所以我们在处理数据之前首先要搞清楚数据存储在什么地方,也就是说数据的内存地址。现在我们要对datasg 段中的数据进行复制,我们先来看一下要复制的数据在什么地方,datasg:0,这是要进行复制的数据的地址。

那么复制到哪里去呢?

应该是复制到它后面的数据区。因为 "welcome to masm!"从偏移地址0开始存放,长度为 16 个字节,所以,它后面的数据区的偏移地址为 16 ,就是字符串所要存放的空间。

清楚了地址之后,我们就可以进行处理了。我们用ds:si指向要复制的源始字符串,用ds:di 指向复制的目的空间,然后用一个循环来完成复制。

代码段如下:

assembly 复制代码
codesg segment
start:   mov ax,datasg
         mov ds,ax
         mov si,0
         mov di,16
         
         mov cx,8
    s:   mov ax,[si]
         mov [di],ax
         add si,2
         add di,2
         loop s

         mov ax,4c00h
         int 21h
codesg ends

end start

❗注意,在程序中,我们用16位寄存器进行内存单元之间的数据传送,一次复制 2 个字节,一共循环8次。

3.4 问题三

用更少的代码,实现问题二中的程序。

思考后看分析。

3.5 问题三的分析与求解

我们可以利用[bx(si或di)+idata]的方式,来使程序变得简洁。

程序如下:

assembly 复制代码
codesg segment
start:   mov ax,datasg
         mov ds,ax
         mov si,0
         mov cx,8
    s:   mov ax,0[si]
         mov 16[si],ax
         add si,2
         loop s
         
         mov ax,4c00h
         int 21h
codesg ends

end start

4. [bx+si]和[bx+di]

4.1 更加更加灵活的访问内存

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

  • bx+si

  • \[bx+di

(1)

bx+si\]和\[bx+di\]的含义相似,我们以\[bx+si\]为例进行讲解。 \[bx+si\]表示一个内存单元,它的偏移地址为(bx)+(si)(即bx中的数值加上si中的数值)。 (2) 我们看下指令`mov ax,[bx+si]`的含义: * 将一个内存单元的内容送入ax,这个内存单元的长度为2字节(字单元),存放一个字,偏移地址为bx中的数值加上si中的数值,段地址在ds中。 * 数学化的描述为:(ax)=( (ds)\*16+(bx)+(si) ) * 该指令也可以写成如下格式(常用):`mov ax,[bx][si] ` ### 4.2 问题四 用Debug查看内存,结果如下: 2000:1000 BE 00 06 00 00 00 ...... 写出下面的程序执行后,ax、bx、cx中的内容是什么: ```assembly mov ax,2000H mov ds,ax mov bx,1000H mov si,0 mov ax,[bx+si] inc si mov cx,[bx+si] inc si mov di,si mov ax,[bx+di] ``` 思考后看分析。 ### 4.3 问题四的分析与求解 ```assembly mov ax,[bx+si] ``` 访问的字单元的段地址在ds中,(ds)=2000H;偏移地址=(bx)+(si)=1000H; 指令执行后(ax)=00BEH。 ```assembly mov cx,[bx+si] ``` 访问的字单元的段地址在ds中,(ds)=2000H;偏移地址=(bx)+(si)=1001H; 指令执行后(cx)=0600H。 ```assembly add cx,[bx+di] ``` 访问的字单元的段地址在ds中,(ds)=2000H;偏移地址=(bx)+(di)=1002H; 指令执行后(cx)=0606H。 ## 5. \[bx+si+idata\]和\[bx+di+idata

5.1 更加更加更加灵活的访问内存

(1)

bx+si+idata\]和\[bx+di+idata\]的含义相似,我们以\[bx+si+idata\]为例进行讲解。 \[bx+si+idata\]表示一个内存单元,它的偏移地址为(bx)+(si)+idata。(即bx中的数值加上si中的数值再加上idata) (2) 指令`mov ax,[bx+si+idata]`的含义: * 将一个内存单元的内容送入ax,这个内存单元的长度为2字节(字单元),存放一个字,偏移地址为bx中的数值加上si中的数值再加上idata,段地址在ds中。 * 数学化的描述为:(ax)=( (ds)\*16+(bx)+(si)+idata ) * 该指令也可以写成如下格式(常用): * `mov ax,[bx+200+si]` * `mov ax,[200+bx+si]` * `mov ax,200[bx][si]` * `mov ax,[bx].200[si]` * `mov ax,[bx][si].200` ### 5.2 问题五 用Debug查看内存,结果如下: 2000:1000 BE 00 06 00 6A 22 ...... 写出下面的程序执行后,ax、bx、cx中的内容是什么。 ```assembly mov ax,2000H mov ds,ax mov bx,1000H mov si,0 mov ax,[bx+2+si] inc si mov cx,[bx+2+si] inc si mov di,si mov ax,[bx+2+di] ``` 思考后看分析。 ### 5.3 问题五的分析与求解 ```assembly mov ax,[bx+2+si] ``` 访问的字单元的段地址在ds中,(ds)=2000H;偏移地址=(bx)+(si)+2=1002H; 指令执行后(ax)=0006H。 ```assembly mov ax,[bx+2+si] ``` 访问的字单元的段地址在ds中,(ds)=2000H;偏移地址=(bx)+(si)+2=1003H; 指令执行后(cx)=006AH。 ```assembly mov ax,[bx+2+si] ``` 访问的字单元的段地址在ds中,(ds)=2000H;偏移地址=(bx)+(si)+2=1004H; 指令执行后(cx)=226AH。 ## 结语 今天的分享到这里就结束啦!如果觉得文章还不错的话,可以三连支持一下。 也可以点点关注,避免以后找不到我哦! [Crossoads主页](https://blog.csdn.net/2301_80191662?type=lately)还有很多有趣的文章,欢迎小伙伴们前去点评,您的支持就是作者前进的动力! ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/09ab1c8e54e841e6bc0127ea68d49004.gif)

相关推荐
林九生3 分钟前
【Docker】Docker环境下快速部署Ollama与Open-WebUI:详细指南
java·docker·eureka
Aric_Jones1 小时前
lua入门语法,包含安装,注释,变量,循环等
java·开发语言·git·elasticsearch·junit·lua
Akiiiira1 小时前
【日撸 Java 三百行】Day 12(顺序表(二))
java·开发语言
Hello.Reader1 小时前
ngx_http_limit_conn_module精准连接控制
网络·网络协议·http
鸿蒙布道师2 小时前
鸿蒙NEXT开发动画案例5
android·ios·华为·harmonyos·鸿蒙系统·arkui·huawei
π大星星️2 小时前
基于LNMP架构的个人博客系统部署
服务器·架构
巴巴_羊5 小时前
前端面经 计网 http和https区别
网络协议·http·https
Chase_Mos5 小时前
Spring 必会之微服务篇(1)
java·spring·微服务
小林学习编程7 小时前
SpringBoot校园失物招领信息平台
java·spring boot·后端
撸码到无法自拔7 小时前
docker常见命令
java·spring cloud·docker·容器·eureka