【汇编】Loop指令、段前缀

简介: 【汇编】Loop指令、段前缀

前言


计算机编程的世界里,了解底层的硬件操作是提升程序员能力的关键一步。汇编语言作为一种底层语言,直接操作计算机的硬件,其中的 LOOP 指令和段前缀是我们探讨的两个重要概念。LOOP 指令为我们提供了一种简洁的方式来实现循环,而段前缀则是用来指定数据存储位置的关键工具。在这篇文章中,我们将深入探讨这两个概念的作用和用法,以便读者更好地理解汇编语言的底层机制。


一、Loop指令


1.1 Loop指令是什么?

汇编语言中,LOOP 指令是一个循环控制指令,用来简化循环结构的编写。这个指令的作用就像你在做同样的事情一遍又一遍,而不必重复写相同的代码。

通俗解释:

假设你在写程序,需要做一件事情多次,比如打印一系列数字。使用 LOOP 就像是告诉计算机:“嘿,这里有一段代码,我要重复执行它多次。” 计算机就会明白,不用你一遍遍写相同的指令。


1.2 他的条件是什么?

在高级语言中,我们知道,一个循环他肯定是需要一个条件的

那么我们的汇编语言也不例外,

他的条件如下:

CPU 执行loop指令时要进行的操作

①(cx)=(cx)-1;

②判断cx中的值

不为零则转至标号处执行程序

如果为零则向下执行。

要求

cx 中要提前存放循环次数,因为(cx)影响着

loop指令的执行结果

要定义一个标号

标号如下:

flag:
  ;you want to do
other


其中flag就是标号,后面加冒号:


1.3 例子

示例1

想象你要打印数字1到10。使用 LOOP 你可以这样写:

MOV CX, 10 ; 将计数器CX设置为10

MY_LOOP:
    ; 这里放你要重复执行的代码,比如打印数字
    LOOP MY_LOOP ; CX减1,如果不为0,跳回MY_LOOP


在这个例子中,LOOP 指令会检查 CX 寄存器的值,如果不为零,就会跳回标记为 MY_LOOP 的地方,重复执行那段代码。这样你就不需要写十次相同的代码,只需要告诉计算机循环的次数,它会帮你搞定。


示例2

本示例为把2加11次,即2^11

assume cs:codesg
codesg segment
  mov cx,11
  mov ax,2
s: add ax,ax
   loop s
  mov ax,4c00h
  int 21h
codesg ends
end


706f00313ff64c0d97ca3956640ebd68.png

我们通过在DOSBox中编译

d2394a291fe14cf184d0ffb05ac41bfa.png

e6d64689db944fe5932306b4be79bb90.png

然后使用debug进行追踪

523271916ec64c6ea8ba38cb78ca0252.png

使用r命令查看寄存器

f1766c9d00cb42ebbdd18918ccdddf1d.png

使用t命令单步走

c8091367bc9945c9b49c9c1de240545f.png

可以观察寄存器的值和后面要执行的命令可以发现,loop指令已经成功执行了。


1.4 要点总结

用cx和loop 指令相配合实现循环功能的三个要点:

(1)在cx中存放循环次数;

(2)用标号指定循环开始的位置;

(3)在标号和loop 指令的中间,写上要循环执行的程序段(循环体)。


二、段前缀


在汇编语言中,段前缀是一种用来指定数据存储位置的方式。在实模式下,x86 架构的计算机使用段寄存器来确定程序的数据在内存中的位置。通俗地说,段前缀就像是你告诉计算机:“我的数据在哪一块内存中”。

举例说明:

假设你有一块内存,存储了一串字符串。如果你想告诉计算机去读取这个字符串,你需要使用段前缀来指定这块内存的位置。

比如,DS(数据段寄存器)是一个常用的段寄存器。使用 DS 作为段前缀,你可以告诉计算机:“嘿,我的数据在 DS 寄存器指示的那一块内存里。”

MOV AX, DS ; 把数据段寄存器的值加载到通用寄存器AX中

MOV DS, AX ; 设置数据段寄存器为AX中的值,即指向你想访问的内存块


; 然后你可以使用寄存器BX来指定内存中的偏移量,访问具体的数据

MOV BX, 0 ; 从内存块的开始位置开始

MOV AL, [BX] ; 读取内存中BX指定位置的数据


这样,通过合理设置段前缀,你可以方便地在汇编语言中定位和访问存储在内存中的数据。


2.1 为什么要引入他

Debug中,mov al, [0]的功能是

——将DS:0存储单元的值传给AL

将下面这个代码编译,链接使用debug打开

assume cs:codesg
codesg segment
  mov ax,2000h
  mov ds,ax
  mov al,[0]
  mov bl,[1]
  mov cl,[2]
  mov ax,4c00h
  int 21h
codesg ends
end


6e12976109fa4da99827999d817a97fa.png

使用u命令查看

a3247823698548a2adf077723107d03d.png

他就变成

mov al,00
mov bl,01
mov cl,02


这属实让人大跌眼镜


2.2 对策

对策:在[idata]前显式地写上段寄存器

mov ax,2000h
mov ds,ax
mov bx,0
mov al,ds:[bx]
mov ax,2000h
mov ds,ax
mov al,ds:[0]


f3fb558136f74e5297d26b03a20c6d31.png

9cc281adfdb545afb5f36dc6e28ced73.png

现在可以看到就是[0001]了


小结(在程序中):

mov al,[0]:(al)=0,同mov al,0

mov al,ds:[0]:(al)=((ds)*16+0)

mov al,[bx]:(al)=((ds)*16+(bx))

mov al,ds:[bx]:与mov al,[bx]相同


这些出现在访问内存单元的指令中,用于显式地指明内存单元的段地址的“ds:”、“cs:”、“ss:”或“es:”,在汇编语言中称为段前缀。


总结


汇编语言的学习不仅仅是为了理解代码的执行流程,更是为了掌握计算机底层的工作原理。本文中,我们深入研究了 LOOP 指令和段前缀的概念。LOOP 让我们能够更轻松地实现循环结构,提高代码的复用性和可读性;而段前缀则是在实模式下指定数据存储位置的关键,为程序员提供了对内存的更精准控制。通过理解和熟练运用这两个概念,我们可以更高效地编写汇编代码,更深入地理解计算机底层运作的原理。希望本文对读者在汇编语言的学习和应用中有所帮助。

相关文章
|
2月前
|
存储 Unix 编译器
汇编语言----X86汇编指令
汇编语言----X86汇编指令
43 1
|
2月前
|
存储 机器学习/深度学习 移动开发
汇编语言指令系列
汇编语言指令系列
128 0
|
13天前
汇编语言(第四版) 实验一 查看CPU和内存,用机器指令和汇编指令编程
汇编语言(第四版) 实验一 查看CPU和内存,用机器指令和汇编指令编程
|
5天前
|
C语言
程序技术好文:部分ARM汇编指令解读
程序技术好文:部分ARM汇编指令解读
|
2月前
|
安全 编译器
8086 汇编笔记(四):[BX] 和 loop 指令
8086 汇编笔记(四):[BX] 和 loop 指令
|
2月前
|
Shell C语言 SoC
计基2—RISCV指令集介绍与汇编
计基2—RISCV指令集介绍与汇编
35 1
|
2月前
|
存储 C++
C/C++中的整数除法运算与汇编指令DIV和IDIV
C/C++中的整数除法运算与汇编指令DIV和IDIV
33 1
|
2月前
|
存储 安全 程序员
C/C++中的整数乘法运算与汇编指令MUL和IMUL
C/C++中的整数乘法运算与汇编指令MUL和IMUL
25 0
|
2月前
|
编译器 C++
C/C++中的逻辑运算与汇编指令的交互
C/C++中的逻辑运算与汇编指令的交互
20 0
|
2月前
|
编译器 程序员 C++
C/C++逻辑与运算与汇编指令的关系
C/C++逻辑与运算与汇编指令的关系
31 0