80x86汇编—汇编程序基本框架

文章目录

  • First Program
  • 指令系统
  • 伪指令
    • 数值表达式
  • 程序框架解释
  • int 21 中断

通过一个基本框架解释各个指令和用处,方便复习。所以我认为最好的学习顺序就是先看一段完整的汇编代码程序,然后给你逐个逐个的解释每一个代码是干嘛用的。然后剩下的还有很多指令或者伪指令会在以后用到的时候再根据具体上下文使用,我认为汇编就是实战出来的,很多指令根本不用记忆,需求出来了,你用了后就知道是怎个事了。

First Program

经典Hello Word!
代码如下:

stack segment
	db 10 dup(00)
	topSP equ this word ;栈顶指针地址标号
stack ends
datas segment
	string db 'Hello Word!', 0Dh, 0AH, '$'
	db 10 dup (?)
datas ends
code segment
assume cs:code,ss:stack,ds:datas  
start:
	mov ax, datas
	mov ds, ax
	mov dx, offset string
	mov ah, 09h
	int 21h	
	mov ax, 4c00h
	int 21h
code ends
end start


编译->链接->运行,经过三个步骤就能够使用debug对生成的exe文件调试了
编译命令:masm 名.asm;
链接命令:link 名.obj; (obj文件是在masm后自动生成的)
运行命令:名.exe(exe文件是在link后自动生成的)
debug调试exe命令:debug 名.exe

在这里插入图片描述

指令系统

点击复习指令系统

伪指令

伪指令都不占程序空间,因为在编译过程中,你的伪指令全部帮你翻译好了,然后变成机器指令后就只能按照机器指令, 机器指令没有伪指令,伪指令是方便人类阅读代码的,可以通过汇编编译器翻译对应的计算机能够执行的机器指令,比如:fun我把他作为一个函数入口地址,我们编译器翻译的时候不会再fun这一处存fun的地址空间,而是假设你有用到fun这个函数入口地址的话,在你使用该标号的位置处将该标号翻译成fun的入口地址就是fun的下一条指令。

  • 标号(他不是伪指令,是一个不占空间但又不是伪指令的东西)
    可以理解为变量名,变量的名字可以随便起,这个和下面介绍的名字指令差不多。
    标号后一定要接了一个冒号:,表示这个标号可以作为一个地址,地址和下一个指令地址一样。(虽然不是伪指令,但是他也不占程序空间,用来标记程序中某些位置的)

    随便名标号:
    mov ax ,bx
    loop 随便名标号
    ...
    
  • 名字(就是程序中Stack 或者 datas这些,可以随便命名)
    可以理解为变量名,用来记录当前位置的下一条指令或者数据的地址,所以利用这个特点我们就可以用它来定位是一件十分轻松的事情,因为他不占空间地址,写一条指令上去后就可以直接用这个指令的名字来表示地址了,很方便。(这里我程序里面也用到了我给栈顶指针起了个名字topSP ,最显著的特点就是用来当栈顶指针,妈妈再也不用担心我计算指针位置错误了!又因为他不占空间,有了这个标志就直接用就可以找到栈顶指针,不会影响后面的代码位置关系)

    随便名字段 segment 
    随便名字段 ends
    随便名字段 db 'hello'
    ...
    
  • ASSUME
    翻译就是:假设、设想
    在汇编中是指明段寄存器的段名,格式为:assume 段寄存器:随便名字段
    随便名字段是段地址,是段地址,是段地址!!
    assume可以放在开头也行,不一样放在数据段定义的后面,因为assume是伪指令,汇编编译过程中会帮你翻译好。
    很明显这个是给自己编写的段一个归属,比如我datas段就是专门给ds段的,所以在assume中就是ds:datas,这就将我们的datas段数据连接到了数据段了,说到连接,那其实assume的本质就是为了汇编在link的时候将自己写的段设置到正确的段位置。
    注意事项:assume是 给自己定义的数据块指明回家的路,回到自己的段内,意思是DS冒号后面你的数据段属于DS段,那你要是用你他的时候就需要在DS里面访问(这里是一个坑,下面我接着说很重要的一点)
    还有一点很重要:我们assume定义完成后希望在code代码里面使用这段数据的话,其实代码里面还需要自己将DS段设置为随便名字段对应的段地址,我们的随便名字段就是段地址。
    因此正确使用我们定义的数据段因该是:

    assume cs:随便名字段,ds:datas, ss:随便名字段3
    mov ax, datas
    mov ds, ax 
    

    将datas段地址给到我们的ds段,由于前面设置了ds:datas,所以编译器看得懂你这段datas数据,否则定义在其他段了你又在ds使用的话就会出问题。datas可以随便起名字

  • OFFSET 标号或者名字 / SEG 标号或者名字
    offset是返回标号在他自己的段的偏移地址
    seg是返回标号所在的段地址
    一般用法:

    mov ax, offset string 
    mov ax, seg string;这里返回的是string所在的段地址
    

    通过验证也可以知道seg是真的返回了string的段地址,所以有时候不知道string的段地址的名字叫啥比如忘记了datas的话,我们就可以通过这种方式获取段地址,如下图所示
    在这里插入图片描述

  • DUP
    格式:重复次数 DUP (要重复的东西)
    DUP一般是用来赋初值的
    要重复的东西:这里可以是问号,可以是数值,也可以是字符串等等,字符串也给你重复好多次。
    ?问号表示不确定是什么,如下图,通过验证后,8086debug中显示是0的状态。
    在这里插入图片描述

    db 10 dup(00)
    db 10 dup (?)
    
  • DB/DD/DW
    DB字节 8字节
    DD单字 16字节
    DW双字 32字节
    用处就是当你定义一个数据段的时候可以指明一个元素占多少字节
    好比上一个DUP中用到的就是DB,表示他每一个重复的元素都是占8个字节大小

    db 10 dup(00)
    
  • $
    有时候表示当前地址
    比如:使用 $ 和相对偏移计算mov bx, $ - 标号
    有时候表示字符串结束符,当我们int 21中 09h的功能就是当遇到$字符的时候停止输出字符。
    比如:

    前面我们定义了string db 'Hello Word!', 0Dh, 0AH, '$'
    所以int 2109号中断程序会在打印字符中遇到$的时候停止
    mov ah, 09h
    nt 21h	
    
  • EQU / =
    equal相等,=也是相等
    格式:

    随便 equ 12
    随便2 = 13
    

    那以后代码中出现 了随便,就会在汇编编译过程汇总将随便这个名字换成12同理随便2换成13

  • PTR
    在指令系统讲过了,就是指明类型的意思
    下面介绍几个用法即可
    在这里插入图片描述

  • THIS
    用法:THIS 类型名
    这种用法搭配equ和等号简直无敌,因为是伪指令所有使用他的时候不占程序空间内存,单单用作给编译器翻译,让编译器去做而已,翻译机器码后是没有这个语句的
    让我感到优雅的一个语句就是:topSP equ this word ;栈顶指针地址标号
    基本一看就懂了,最牛逼的是opSP equ this word伪指令他不占内存。翻译的时候他名字对应的地址是等于下一个指令的地址,并且不会影响你该语句后面的数据段或者代码段位置。我们以后想用栈的时候直接使用topSP这个名字就行,真的是一箭双雕,太优雅了!

    stack segment
    	db 10 dup(00)
    	topSP equ this word ;栈顶指针地址标号
    stack ends
    

    下图也可以看出确实topSP没有他的内存空间
    在这里插入图片描述
    还有一种老师的用法,就是通过地址相同,因为不占空间,但是地址是下一条指令地址,我们直接将f_jump 相等equ与far,因为不指明跳转范围的标号都是段内转移,但是由于f_jump等于下一个指令的地址,但是他的属性类型是far,所以只要用他的名字就可以实现段间转移(确实有点反人类指令)
    在这里插入图片描述

  • TYPE
    这个就是typeofC语言中的函数一样,
    type 标号或者名字,能够返回该标号或者名字的类型大小,以字节作为单位,
    比如一个标号s是段内转移,那他就是一个byte,返回的就是1,假设像我们f_jump的话,我们type一下他就返回2,因为far是段间

mov ax, type f_jump ;这里等于 mov ax, 2
mov ax, type n_jump ;这里等于 mov ax, 1
  • SIZEOF
    这个指令就是量整个变量所占的空间,可以理解为量我们的数据段首地址,然后就会返回你这个数据段的占的字节大小。

  • LENGTHOF
    这个就是量你元素个数,数据段中我们可能有多个相同大小的多个元素,那么这个指令就是用来量长度的,量个数的。

  • SIZEOF = TYPE × LENGTHOF

数值表达式

这个就有点推翻以前说的格式了,我们以前的指令格式都是:
操作指令 目的操作数,源操作数
但当你使用数值表达式的话就不一样了,就跟我们平常的写式子的顺序是一样的。

mov ax,3*4+5 ;等价于 mov ax,17

目前看起来很正常,因为我们的乘除法这样使用的在高级语言中也是可以。

or al,03h AND 45h ;等价于 or al,01h

这种就有点迷惑了,首先我们学的and指令都是:and 操作数1,操作数2
但是这种就是跟你写数学式子一样
也是数值表达式的一种特色吧,直接用and没给你改成其他的指令,直接拿硬指令,所以通过这个式子例子就可以猜到后面的用法了,
也就是说当我们需要一种计算的式子的话,可以放到源操作数中进行,不用手动计算,工作交给编译器,编译完成后会直接形成结果,所以不会影响执行速度。

mov al,0101b SHL (2*2);等价于 mov al,01010000b

这个指令就真的是推翻了我在指令系统里面的解释,指令系统中提到过shl如果要移位超过1位的话就要将移位个数存进cl中,然后shl ax, cl才可以多次移位,但是在数值表达式中就直接推翻了,但是 前提是你需要按照数值表达式的格式来写才可以,所以我们可以0101b SHL (2*2),但是这种形式是一个结果,所以我们一般都是需要放在源操作数,然然后送进目的操作数中。

程序框架解释

最后会在int中断号给出相关示例代码,这里只给出模版。

  • assume设置自己定义的数据段时属于哪一个段寄存器的,一般都会有assume,因为我们一般情况下是会定义一个代码段,assume一般是放在开头第一段或者code segment下一行。

  • codes segment …
    codes ends

    代码段,段都是用segment,
    开头段都需要 [段名 segment]
    结束段都需要 [段名 ends]

  • start:…
    end start

    start是程序入口,需要在程序最后结尾添上end start
    start是可以随便起名字

  • 代码段和入口程序标号通常是交织在一起的,我们就按照正常的格式写。如下:

codes segment
       start:
       ......
       ......
       ......
codes ends
end start

整合一下整个框架就是:
(记住,要用数据段的时候千万不要漏掉将ds或者其他段用对应的标号修改,比如:mov ax, datas mov ds, ax,修改ds段地址)

assume cs:codes, ss:stacks, ds:datas
stacks segment
... ... ...
stacks ends
datas segment
... ... ...
datas ends
codes segment
	start:
	... ...
	... ...
	... ...
	... ...
codes ends
end start 

int 21 中断

这里是最后一个知识点,因为想要入门一个简单的程序需要用到,但是不会讲的很详细,int中断本来就是一个很大的章节需要慢慢学习,很多功能都能解决很多问题。这里就简单介绍几个常用的功能号

我们在程序中经常会看到这么一段

mov ah, 09h
int 21h	
mov ax, 4c00h
int 21h

int 21h是一个DOS系统中断,21h里面包含很多功能,但是需要用寄存器来空间。
怎么控制?
最简单的一个控制,就是当ax等于09h的时候就是打印一个ds段里面的dx偏移地址的字符串,遇到$符号就停止,所以这里终于解释明白了我们First程序的字符串是怎么打印出来的了。
因此可以想象一下,我们int 21h中断有很多功能,那我们不仅仅是一个打印功能,还有很多,有可能是al来控制,也有可能是ah来控制,也有可能是其他寄存器,当然我不知有没有其他寄存器i,只是告诉使用int 21h功能的时候,记得设置功能调用号和参数。
09功能号,参数是ds:dx作为字符串入口
所以就是打印出来一个Hello Word!
4c00h就是意味着代码段程序正常退出
但是不是整个程序结束,整个程序结束时end start,当然 start是随便名,在你代码段开始的start:自己定义名字的。

下面介绍的比如09h数字是ax或者al/ah对应的数字所对应21h中断的功能程序是什么。当然09h上面说过了是打印ds:dx首地址的字符串,遇到$停止
注意:下面需要将中断号传到ah而不是ax,除了4c00需要传到ax,因为他是16位。

  • 09h
    功能:在显示器输出指定的字符串
    DS:DX=欲显示字符串在主存中的首地址
    字符串应以$(24H)结束
    可以输出回车(0DH)和换行(0AH)字符产生回车和换行的作用
    在这里插入图片描述
    在这里插入图片描述
    示例代码如下:

    ;使用09中断号打印出来Hello Word!
    assume cs:code, ds:datas
    
    datas segment 
    	string db 'Hello Word!', 0dh, 0ah, '$'
    datas ends
    
    code segment
    	start:
    		mov ax, datas 
    		mov ds, ax ;设置datas对应的数据段
    		mov dx, offset string ;这里一定要用offset,
    		mov ah, 09h ;打印ds:dx字符串,遇到$停止
    		int 21h
    		mov ax, 4c00h ;代码段结束
    		int 21h
    code ends
    end start 
    
  • 01h
    功能:获得按键的ASCII代码值
    功能号:AH=01H
    出口参数:AL=字符的ASCII码
    调用此功能时,若无键按下,则会一直等待,直到按键后才读取该键值
    在这里插入图片描述
    示例代码如下:

    ;使用01h中断号,循环录入Hello Word!  也就是说重复录入11个字
    assume cs:codes, ds:datas
    
    datas segment
    	string db 11 dup (0), 0dh, 0ah, '$'
    	endString equ this byte
    datas ends
    
    codes segment
    	start:
    	mov ax, datas
    	mov ds, ax
    	mov cx, 11
    	mov al, 0
    	mov ah, 01h
    	mov si, 0
    	mov bx, offset string 
    	
    	s:
    	int 21h
    	mov [bx][si], al 
    	inc si
    	loop s
    	
    	mov dx, offset string 
    	mov ah, 09h
    	int 21h
    	
    	mov ax, 4c00h
    	int 21h
    	
    codes ends
    end start 
    
    
  • 0ah
    功能:执行该功能调用时,用户按键,最后用回车确认
    功能号:AH=0AH
    入口参数:DS:DX=缓冲区首地址
    本调用可执行全部标准键盘编辑命令;用户按回车键结束输入,如按Ctrl+Break或Ctrl+C则中止

    细节:首先这个其实是有三个参数,
    就拿datas段来举例子

    datas segment
    string  db 12 ;这个是用来表示你最大可以输
    			  ;入多少个字符,这里是包含回车的,不要忘记
    			  
    		db 0 
    		;这里是表示你的输入字符个数,
    		;会在你输入的时候自动计算,然后一般是0
    		
    		db 12 dup(0) 
    		;这里是存你输入的字符串,
    		;所以你要输出的话就要记得将string 地址偏移地址
    		;偏移到该为止,这里由于是db大小所以偏移两个byte。
    

    下图证明了无论你第二个参数设置什么,都是默认帮你计算好最终你输入多少个字符的,我这里是输入了10个字符,但是我设置的是11,最后结果是a=10那就代表是强制性计数器。
    在这里插入图片描述
    下面是执行结果,输入字符串直到回车结束,但是我们这里设置了12个加上回车符号那就是只能够输入11个字符,所以刚好输入Hello Word!,然后再利用09h中断号再次找到字符串入口输出。
    在这里插入图片描述
    下面是示例代码:

    
    ;使用01h中断号,循环录入Hello Word!  也就是说重复录入11个字
    assume cs:codes, ds:datas
    
    datas segment
    	string  db 12
    			db 11
    			beginString equ this byte
    			db 12 dup (0)
    			db 0dh, 0ah, '$'
    datas ends
    
    codes segment
    	start:
    	mov dx, seg string
    	mov ds, dx
    	mov dx, offset string 
    	mov ah, 0ah
    	int 21h
    	
    	mov ah, 09h
    	mov dx, offset beginString
    	int 21h
    	
    	
    	mov ax, 4c00h
    	int 21h
    	
    codes ends
    end start 
    
    
  • 0bh
    功能:仅判断当前是否有按下的键,设置AL后退出
    功能号:AH=0BH
    出口参数:AL=0,当前没有按键;
    AL=FFH,当前已经按键。
    注意的是这里讲的是出口参数,是用来判断你该是否按下按键了

    这个就不打算写示例了,因为就是用来测试有没有按键事件发生的一个中断号,可能在写游戏程序用到很多。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/265898.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

前端三剑客实验5-6-复盘

实验 5 - JavaScript对象 若需要源代码,文章末尾自提 1、实现如下编程内容: 1. 分别使用工厂模式、构造函数和class模式来构建移动硬盘对象 2. 彩票号码生成器 随机生成7个1-36之间的随机数,要求数字不重复,并按从小到大的顺序…

合并排序可视化

合并排序可视化 结果 按照位置分色 按照数组值大小分色 可视化代码 参照 冒泡排序可视化 合并排序 public void mergeSort(List<Integer> list, int[] help, int l, int r) {if (l > r) {return;}int mid l (r - l) / 2;mergeSort(list, help, l, mid);mergeSor…

WPF中使用ListView封装组合控件TreeView+DataGrid

&#xff08;关注博主后&#xff0c;在“粉丝专栏”&#xff0c;可免费阅读此文&#xff09; wpf的功能非常强大&#xff0c;很多控件都是原生的&#xff0c;但是要使用TreeViewDataGrid的组合&#xff0c;就需要我们自己去封装实现。 我们需要的效果如图所示&#x…

Nsum问题

题目 题解 暴力法 class Solution:def fourSum(self, nums: List[int], target: int) -> List[List[int]]:if len(nums) < 4:return []nums.sort()N len(nums)res []for i in range(N-3):for j in range(i1, N-2):for k in range(j1, N-1):for m in range(k1, N):tmp…

灰盒测试简要指南!

在本文中&#xff0c;我们将了解什么是灰盒测试、以及为什么要使用它&#xff0c;以及它的优缺点。 在软件测试中&#xff0c;灰盒测试是一种有用的技术&#xff0c;可以确保发布的软件是高性能的、安全的并满足预期用户的需求。这是一种从外部测试应用程序同时跟踪其内部操作…

ffmpeg使用入门

1. ffmpeg是什么&#xff1a; FFmpeg是一款音视频编解码工具&#xff0c;也是一组音视频编解码开发套件&#xff0c;为开发者提供了丰富的音视频处理调用接口。 FFmpeg源代码编译后会生成三个可执行程序&#xff0c;分别是&#xff1a;ffmpeg、ffplay、ffprobe&#xff0c; 这…

行为型设计模式(四):中介模式 命令模式

中介模式 Mediator 1、什么是中介模式 中介模式用于减少对象之间的直接通信&#xff0c;让系统可以更加松耦合。定义了一个中介者对象&#xff0c;该对象封装了一系列对象的交互&#xff0c;使得对象之间不再直接相互引用&#xff0c;而是通用这个中介者对象进行通信。 2、为…

【开源工程及源码】超级经典开源项目实景三维数字孪生智慧港口

智慧港口可视化平台&#xff0c;旨在实现对港口运营的全面监测、智能管理和优化决策。飞渡科技利用数字化、模拟和仿真的技术&#xff0c;通过互联的传感器和设备&#xff0c;实现实时数据的采集、传输和分析&#xff0c;将港口内外的复杂数据以直观、易懂的方式呈现&#xff0…

搜索二叉树(超详解)

文章目录 前言查找搜索二叉树的结构insertfinderase递归版本Findinserterase 二叉树的拷贝问题搜索二叉树的应用Key模型Key/Value的模型 前言 普通二叉树其实意义不大&#xff0c; 如果用二叉树存储数据的话&#xff0c;还不如顺序表&#xff0c;链表这些。 搜索二叉树它的意义…

核货宝订单管理系统提高企业效率

核货宝订单管理系统可以帮助企业提高效率&#xff0c;具体体现在以下几个方面&#xff1a; 一、订单自动化处理&#xff1a;核货宝订单管理系统支持订单批发和多渠道订单导入&#xff0c;它可以从订单的接收、处理、跟进、发货、到售后服务等环节都可以通过系统自动完成&#x…

DBA-MySql面试问题及答案-上

文章目录 1.什么是数据库?2.如何查看某个操作的语法?3.MySql的存储引擎有哪些?4.常用的2种存储引擎&#xff1f;6.可以针对表设置引擎吗&#xff1f;如何设置&#xff1f;6.选择合适的存储引擎&#xff1f;7.选择合适的数据类型8.char & varchar9.Mysql字符集10.如何选择…

python脚本 链接到ssh服务器 快速登录ssh服务器 ssh登录

此文分享一个python脚本,用于管理和快速链接到ssh服务器。 效果演示 🔥完整演示效果 👇第一步,显然,我们需要选择功能 👇第二步,确认 or 选择ssh服务器,根据配置文件中提供的ssh信息,有以下情况 👇场景一,只有一个候选ssh服务器,则脚本会提示用户是否确认链…

吴恩达RLHF课程笔记

1.创建偏好数据集 一个prompt输入到LLM后可以有多个回答&#xff0c;对每个回答选择偏好 比如{prompt,answer1,answer2,prefer1} 2.根据这个数据集&#xff08;偏好数据集&#xff09;&#xff0c;创建reward model&#xff0c;这个model也是一个LLM,并且它是回归模型&#…

C语言之指针

目录 函数的参数 对象和地址 取地址运算符 注意 指针 注意 指针运算符 注意 在C语言中&#xff0c;指针是一个十分重要的概念&#xff0c;它的作用是“指示对象”。 例如&#xff1a;你要去一座公寓楼找一位朋友&#xff0c;公寓楼由很多楼层组成&#xff0c;每个楼层…

解决 MATLAB 遗传算法中 exitflg=4 的问题

一、优化问题简介 以求解下述优化问题为例&#xff1a; P 1 : min ⁡ p ∑ k 1 K p k s . t . { ∑ k 1 K R k r e q l o g ( 1 α k ∗ p k ) ≤ B b s , ∀ k ∈ K p k ≥ 0 , ∀ k ∈ K \begin{align} {P_1:}&\mathop{\min}_{\bm{p}}{ \sum\limits_{k1}^K p_k } \no…

【Linux笔记】文件查看和编辑

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a;Linux学习 ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言 命令 cat (Concatenate and Display): more 和 less: nano 和 vim (文本编辑器): 结语 我的其他博客 前言 学习Linux命令行和文件…

1854_bash中利用管道进行批量参数传递以及由此实现简单的代码行数统计

Grey 全部学习内容汇总&#xff1a; GreyZhang/bash_basic: my learning note about bash shell. (github.com) 1854_bash中的参数传递以及利用bash进行简单的代码行数统计 有时候需要处理多个文件&#xff0c;把每一个文件作为参数传递给某一个程序。这时候可以用到 xargs&…

高频知识汇总 | 【操作系统】面试题汇总(万字长博通俗易懂)

前言 这篇我亲手整理的【操作系统】资料&#xff0c;融入了我个人的理解。当初我在研习八股文时&#xff0c;深感复习时的困扰&#xff0c;网上资料虽多&#xff0c;却过于繁杂&#xff0c;有的甚至冗余。例如&#xff0c;文件管理这部分&#xff0c;在实际面试中很少涉及&…

Ai图片处理

Ai也可以直接导入PS文件&#xff0c;只不过需要进行一个相关的选择&#xff0c;一般来说是将图层转化为对象 第二个为图层拼合为单个图像&#xff08;不常用&#xff09; 第三个则是将隐藏的图片也进行显示 如果你觉得图片的信息的过少好想插入其他的图片&#xff0c;可以选择…

认识Linux背景

1.发展史 Linux从哪里来&#xff1f;它是怎么发展的&#xff1f;在这里简要介绍Linux的发展史 要说Linux&#xff0c;还得从UNIX说起 UNIX发展的历史 1968年&#xff0c;一些来自通用电器公司、贝尔实验室和麻省理工学院的研究人员开发了一个名叫Multics的特殊操作系统。Mu…