1-4、调试汇编程序

news2024/11/15 12:29:25

语雀原文链接

文章目录

    • 1、执行过程
      • 第一步:源程序
      • 第二步:编译连接
      • 第三步:执行
    • 2、DOSBox运行程序
      • 第1步 进入EDIT.EXE
      • 第2步 编写源程序
      • 第3步 编译
      • 第4步 连接
      • 第5步 执行
      • 完整过程
    • 3、DEBUG跟踪执行过程
      • 加载程序到内存
      • 执行程序
      • debug和源程序数字的默认进制
    • 4、DOS系统的shell

1、执行过程

  • 第一步:编写汇编源程序
  • 第二步:对源程序进行编译连接。使用汇编语言编译程序对源程序文件中的源程序进行编译,产生目标文件;再用连接程序对目标文件进行连接,生成可在操作系统中直接运行的可执行文件。可执行文件包含两部分内容。
    • 程序(从源程序中的汇编指令翻译过来的机器码)和数据(源程序中定义的数据)
    • 相关的描述信息(比如,程序有多大、要占用多少内存空间等)
  • 第三步:执行可执行文件中的程序。
    • 操作系统依照可执行文件中的描述信息,将可执行文件中的机器码和数据加载入内存,并进行相关的初始化(比如设置CS:IP指向第一条要执行的指令),然后由CPU执行程序。

image.png

第一步:源程序

  • 在汇编语言源程序中,包含两种指令,一种是汇编指令,一种是伪指令
  • 汇编指令是有对应的机器码的指令,可以被编译为机器指令,最终为CPU所执行
  • 伪指令没有对应的机器指令,最终不被CPU所执行。伪指令是由编译器来执行的指令,编译器根据伪指令来进行相关的编译工作。
  • 新建一个first.asm文件,内容如下
assume cs:codemsg
codemsg segment
    mov ax,0123H
    mov bx,0456H
    add ax,bx
    add ax,ax

    mov ax,4c00H
    int 21H

codemsg ends
end
  • 上述代码有3中伪指令

  • 第一条伪指令:assume这个伪指令的含义为"假设"。假设某一段寄存器和程序中的某一个用segment…ends定义的段相关联。上述代码中,用assume cs:codesg将把代码段的codesg和CPU中的段寄存器cs联系起来

  • 第二条伪指令:segment和ends是一对成对使用的伪指令,这是在写可被编记择器编译的汇编程序时,必须要用到的一对伪指令。segment和ends的功能是定义一个段,segment说明一个段开始,ends说明一个段结束。

  • 第三条伪指令:end是一个汇编程序的结束标记,编译器在编译汇编程序的过程中,如果碰到了伪指令end,就结束对源程序的编译。所以,在我们写程序的时候,如果程序写完了,要在结尾处加上伪指令end。否则,编译器在编译程序时,无法去知道程序在何处结束。注意,不要搞混了end和ends,ends是和segment成对使用的,标记一个段的结束,ends的含义可理解为"end segment"。我们这里讲的end的作用是标记整个程序的结束。

  • 基本格式如下

assume 段寄存器:xxx
xxx segment
	汇编指令
	...
	...
xxx ends
end

第二步:编译连接

  • 编译连接

image.png

第三步:执行

  • 可执行文件怎么才能运行?
  • 我们在DOS(一个单任务操作系统)的基础上,一个程序P2在可执行文件中,则必须有一个正在运行的程序P1,将P2从可执行文件中加载入内存后,将CPU的控制权交给P2,P2才能得以运行。P2开始运行后,P1暂停运行。而当P2运行完毕后,应该将CPU的控制权交还给使它得以运行的程序P1,此后,P1继续运行。
  • 一个程序结束后,将CPU的控制权交还给使它得以运行的程序,我们称这个过程为:程序返回。在程序的末尾添加返回的程序段就可以实现程序返回
    mov ax,4c00H
    int 21H

2、DOSBox运行程序

第1步 进入EDIT.EXE

  • 运行edit,IT/MASM文件中有几个EXE
    • DEBUG.EXE:debug执行程序
    • EDIT.EXE:编辑执行程序
    • LINK.EXE:连接执行程序
    • MASM.EXE:编译执行程序

image.png

Z:\>mount c d:\IT\MASM
Z:\>c:
Z:\>edit

第2步 编写源程序

  • 编写保存源程序

image.png

  • 保存到c:\first.asm

image.png

第3步 编译

  • 在编译一个源程序之前首先要找到一个相应的编译器。这里采用微软的masm5.0汇编编译器,文件名为MASM.EXE。这里我们把它放在c:\MASM.EXE
C:\>masm
Microsoft (R) Macro Assembler Version 5.00
Copyright (C) Microsoft Corp 1981-1985, 1987. All rights reserved.

Source filename [.ASM]: 
  • 运行masm后,首先显示出一些版本信息,然后提示输入将要被编译的源程序文件的名称。
  • [.ASM]提示我们,默认的文件扩展名是asm,如果要编译的源程序文件名是"pl.asm",只要在这里输入"pl"即可。可如果源程序文件不是以asm为扩展名的话,就要输入它的全名。比如源程序文件名为"pl.txt",就要输入全名。在输入源程序文件名的时候一定要指明它所在的路径。如果文件就在当前路径下,只输入文件名就可以,可如果文件在其他的目录中,则要输入路径。比如,要编译的文件pl.txt在"c:\windows/desktop"下,则要输入"c:/windows/desktop\pbl.txt"
  • 输入first,Enter回车3次即可
    • Object filename:编译出的目标文件名称,默认和源程序同名,直接回车即可;如果想自定义目标文件路径和名称,例如输入“c:\xx\out”
    • Source listing:编译程序提示输入列表文件的名称,这个文件是编译器将源程序编译为目标文件的过程中产生的中间结果。可以让编译器不生成这个文件,直接按Enter键即可。
    • Cross-reference:编译程序提示输入交叉引用文件的名称,这个文件同列表文件一样是编译器将源程序编译为目标文件过程中产生的中间结果。可以让编译器不生成这个文件,直接按Enter键即可。
  • 在编译的过程中,我们提供了一个输入,即源程序文件。最多可以得到3个输出:列表文件(.lst)、交叉引用文件(.crf)、目标文件(.obj)。这3个输出文件中,目标文件是我们最终要得到的结果,而另外两个只是中间结果,可以让编译器忽略对它们的生成。在汇编课程中,我们不讨论这两类文件。
C:\>masm
Microsoft (R) Macro Assembler Version 5.00
Copyright (C) Microsoft Corp 1981-1985, 1987. All rights reserved.

Source filename [.ASM]: first
Object filename [first.OBJ]:
Source listing  [NUL.LST]:
Cross-reference [NUL.CRF]:

	51798 + 464746 Bytes symbol space free

    	0 Warning Errors
    	0 Server  Errors
C:\>masm

第4步 连接

  • [.OBJ]:输入要连接的文件,此处输入first(无须后缀.OBJ)
  • Run File:输入要生成的可执行文件的名称,默认同名.EXE,直接Enter使用默认值
  • List File:连接程序提示输入映像文件的名称,这个文件是连接程序将目标文件连接为可执行文件过程中产生的中间结果,可以让连接程序不生成这个文件,直接按Enter键即可。
  • Libraries:如果程序中调用了某一个库文件中的子程序,就需要在连接的时候,将这个库文件和目标文件连接到一起,生成可执行文件。如果这个程序没有调用任何子程序,这里忽略库文件名的输入,直接按Enter键即可。
  • 最后输出一行警告:no stack segment,这里无需理会
C:\>link
Microsoft (R) Overly Linker Version 3.60
Copyright (C) Microsoft Corp 1981-1985, 1987. All rights reserved.

Object Module [.OBJ]: first
Run File [FIRST.EXE]:
List File [NUL.MAP]:
Libraries [.LIB]:
LINK : warning L4021: no stack segment
  • 连接有什么作用
      1. 当源程序很大时,可以将它分为多个源程序文件来编译,每个源程序编译成为目标文件后,再用连接程序将它们连接到一起,生成一个可执行文件;
      1. 程序中调用了某个库文件中的子程序,需要将这个库文件利该程序生成的目标文件连接到一起,生成一个可执行文件;
    • 3.一个源程序编译后,得到了存有机器码的目标文件,目标文件中的有些内容还不能直接用来生成可执行文件,连接程序将这些内容处理为最终的可执行信息。所以,在只有一个源程序文件,而又不需要调用某个库中的子程序的情况下,也必须用连接程序对目标文件进行处理,生成可执行文件。
  • 上述的编译和连接写法步骤比较多,可以简化以下,忽略一些过程
    • masm c:\first;
    • link first;
C:\>masm c:\first;
Microsoft (R) Macro Assembler Version 5.00
Copyright (C) Microsoft Corp 1981-1985, 1987. All rights reserved.

	51798 + 464746 Bytes symbol space free

    	0 Warning Errors
    	0 Server  Errors

C:\>link first;
Microsoft (R) Overly Linker Version 3.60
Copyright (C) Microsoft Corp 1981-1985, 1987. All rights reserved.

LINK : warning L4021: no stack segment

第5步 执行

  • 直接运行FIRST.EXE,输入first即可,这里也看不到任何结果
C:\>first

c:\>

完整过程

image.png

3、DEBUG跟踪执行过程

加载程序到内存

  • 在DOS中运行一个程序的时候,是由command将程序从可执行文件中加载入内存并使其得以执行。但是,这样我们不能逐条扣指令地看到程序的执行过程,因为command的程序加载,设置CS:IP指向程序的入口的操作是连续完成的,而当CS:IP一指向程序的入口,command就放弃了CPU的控制权,CPU了立即开始运行程序,直至程序结束。
  • DEBUG将程序FIRST.EXE加载入内存,进行相关的初始化后设置CS:IP指向程序的入口
c:\>debug first.exe
-r
AX=FFFF BX=0000 CX=000F DX=0000 SP=00FD BP=0000 SI=0000 DI=0000
DS=075A ES=075A SS=0769 CS=076A IP=0000 NV UP EI PL NZ NA PO NC
076A:0000 B82301		MOV		AX,0123
-u
076A:0000 B82301		MOV		AX,0123
076A:0003 BB5604		MOV		BX,0456
076A:0006 03C3			ADD		AX,BX
076A:0008 03C0			ADD		AX,AX
076A:000A B8004C		MOV		AX,4C00
076A:000D CD21			INT		21
076A:000F 0000		  ADD		[BX+SI],AL
076A:0011 0000		  ADD		[BX+SI],AL
076A:0013 0000		  ADD		[BX+SI],AL
076A:0015 0000		  ADD		[BX+SI],AL
076A:0017 0000		  ADD		[BX+SI],AL
076A:0019 0000		  ADD		[BX+SI],AL
076A:001B 0000		  ADD		[BX+SI],AL
076A:001D 0000		  ADD		[BX+SI],AL
076A:001F 0000		  ADD		[BX+SI],AL
  • 可以看到程序加载到内存从076A:0000~076A:000E,占据15个字节。CX=000F存储的就是程序的长度
  • 程序为何存储在076A:0000开始,可以看下图(图中有一步重定位没有写,这里不做介绍)

image.png

  • 程序加载后,DS=075A存放着程序所在内存区的段地址,这个内存区的偏移地址为0,所以这个内存区的地址为DS:0,也就是075A:0000
  • 这个内存区的前256个字节存放的是PSP(DOS用来和程序进行通信),从256个字节向后的空间放的是程序,所以程序真真是从075A+10H = 076A:0000开始的,所以CS=076A IP=0000,指向程序的第一条指令

执行程序

c:\>debug first.exe
-r
AX=FFFF BX=0000 CX=000F DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=075A ES=075A SS=0769 CS=076A IP=0000 NV UP EI PL NZ NA PO NC
076A:0000 B82301		MOV		AX,0123
-u
076A:0000 B82301		MOV		AX,0123
076A:0003 BB5604		MOV		BX,0456
076A:0006 03C3			ADD		AX,BX
076A:0008 03C0			ADD		AX,AX
076A:000A B8004C		MOV		AX,4C00
076A:000D CD21			INT		21
076A:000F 0000		  ADD		[BX+SI],AL
076A:0011 0000		  ADD		[BX+SI],AL
076A:0013 0000		  ADD		[BX+SI],AL
076A:0015 0000		  ADD		[BX+SI],AL
076A:0017 0000		  ADD		[BX+SI],AL
076A:0019 0000		  ADD		[BX+SI],AL
076A:001B 0000		  ADD		[BX+SI],AL
076A:001D 0000		  ADD		[BX+SI],AL
076A:001F 0000		  ADD		[BX+SI],AL

// 执行MOV AX,0123,结果AX=0123 IP=0003指向下一条指令
-t
AX=0123 BX=0000 CX=000F DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=075A ES=075A SS=0769 CS=076A IP=0003 NV UP EI PL NZ NA PO NC
076A:0003 BB5604		MOV		BX,0456

// 执行MOV BX,0456,结果BX=0456 IP=0006指向下一条指令
-t
AX=0123 BX=0456 CX=000F DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=075A ES=075A SS=0769 CS=076A IP=0006 NV UP EI PL NZ NA PO NC
076A:0006 03C3			ADD		AX,BX

// 执行ADD AX,BX,结果AX=0579 IP=0008指向下一条指令
-t
AX=0579 BX=0456 CX=000F DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=075A ES=075A SS=0769 CS=076A IP=0008 NV UP EI PL NZ NA PO NC
076A:0008 03C0			ADD		AX,AX

// 执行ADD AX,AX,结果AX=0AF2 IP=0006指向下一条指令
-t
AX=0579 BX=0456 CX=000F DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=075A ES=075A SS=0769 CS=076A IP=000A NV UP EI PL NZ NA PO NC
076A:000A B8004C		MOV		AX,4C00

// 执行MOV AX,4C00,结果AX=4C00 IP=0006指向下一条指令
-t
AX=4C00 BX=0456 CX=000F DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=075A ES=075A SS=0769 CS=076A IP=000D NV UP EI PL NZ NA PO NC
076A:000D CD21		INT		21

// 最后执行int 21,这里需要输入p
-p
Program terminated normally

debug和源程序数字的默认进制

  • 在debug中,默认所有数字都是 16 进制,加了 h 反而会报错;
  • 在汇编源程序 .asm 中,不加 h 则默认为 10 进制,加 h 才表示 16 进制,加 b 为后缀为二进制;
  • 使用 debug 跟踪可执行程序 .exe 的时候,debug会将不加 h 的 10 进制(或者加了b为后缀的二进制)变为对应的 16 进制。

4、DOS系统的shell

  • 操作系统是由多个功能模块组成的庞大、复杂的软件系统。任何通用的操作系统,都要提供一个称为shell(外壳)的程序,用户(操作人员)使用这个程序来操作计算机系统进行工作。
  • DOS中有一个程序command.com,这个程序在DOS中称为命令解释器,也就是DOS系统的shell。
  • DOS启动时,先完成其他重要的初始化工作,然后运行command.com,运行后执行完其他的相关任务后,在屏幕上显示出由当前盘符和当前路径组成的提示符,比如:"c:"或"c:\windows"等,然后等待用户的输入。
  • 用户可以输入所要执行的命令,比如,cd、dir、type等,这些些命令由command执行,command执行完这些命令后,再次显示由当前盘符和当前路径组成的提示符,等持用户的输入。
  • 如果用户要执行一个程序,则输入该程序的可执行文件的名称,command首先根据文件名找到可执行文件,然后将这个可执行文件中的程序加载入内存,设置CS:IP指向程序的入口。此后,command暂停运行,CPU运行程序。程序运行结束后,返回到command中,command再次显示由当前盘符和当前路径组成的提示符,等待用户的输入。
  • 在DOS中,command处理各种输入:命令或要执行的程序的文件名。我们就是通过command来进行工作的。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【导航控制器总结-导航控制器栈 Objective-C语言】

一、导航控制器总结 1.我们接着上一堂课的内容继续 我们上节课说到哪里了,是不是就是对这个导航控制器的一个总结啊 然后,使用的注意事项 2.导航控制器使用注意事项: 1)第一点,使用导航控制器,你在创建的时候,需要给它指定一个根控制器 创建导航控制器的同时,指定…

【译】如何在调试时分析CPU和内存(Analyze CPU and Memory while Debugging)

您想了解如何使您的代码运行得更快,使用更少的内存,或者只是找出您的代码是否有CPU或内存问题?你当然会——你是一名开发人员!但是,内存和性能调优经常会遇到“重要但不紧急”的任务,因为真正紧急的事情,您似乎根本无…

优化 SQL 日志记录的方法

为什么 SQL 日志记录是必不可少的 SQL 日志记录在数据库安全和审计中起着至关重要的作用,它涉及跟踪在数据库上执行的所有 SQL 语句,从而实现审计、故障排除和取证分析。SQL 日志记录可以提供有关数据库如何访问和使用的宝贵见解,使其成为确…

Dockerfile脚本编写流程及示例

学习dockerfile指令 Dockerfile 指令 说明 FROM 指定基础镜像 MAINTAINER 声明镜像的维护者 LABEL 添加元数据标签 RUN 在容器中执行命令 CMD 容器启动后默认执行的命令 EXPOSE 暴露容器的端口 ENV 设置环境变量 ADD 将文件、目录或远程文件添加到容器中 COP…

[ 蓝桥杯Web真题 ]-外卖给好评

目录 介绍 准备 目标 效果 规定 思路 解答参考 介绍 外卖是现代生活中必备的一环。收到外卖后,各大平台软件常常会邀请用户在口味,配送速度等多个方面给与评分。在 element-ui 组件中,已经有相应的 Rate 组件,但是已有组件…

论文解读--PointPillars- Fast Encoders for Object Detection from Point Clouds

PointPillars--点云目标检测的快速编码器 摘要 点云中的物体检测是许多机器人应用(如自动驾驶)的重要方面。在本文中,我们考虑将点云编码为适合下游检测流程的格式的问题。最近的文献提出了两种编码器;固定编码器往往很快,但牺牲了准确性,而…

【latex笔记】双栏格式下插入单栏、双栏格式图片

双栏格式下插入单栏、双栏格式图片 1.缘起multicols2.双栏格式 插入单栏图片3.双栏格式 插入双栏图片 1.缘起multicols 插入双栏格式图片问题被困扰了有很长一段时间,查看网络资源也一直没找到解决方法,今天查看Latex官方文档,才发现因为mul…

spring cloud 整合Feign经行远程调用

文章目录 Feign远程调用Feign替代RestTemplate1)引入依赖2)添加注解3)编写Feign的客户端4)测试5)总结 自定义配置配置文件方式Java代码方式 Feign使用优化 Feign远程调用 先来看我们以前利用RestTemplate发起远程调用…

将rtsp视频流发送到AWS Kinesis Video Streams的方案——使用Gstreamer(C++) Command Line

大纲 1 创建Kinesis Video Streams1.1 创建视频流1.2 记录Creation Time 2 创建策略2.1 赋予权限2.2 限制资源2.3 Json格式描述(或上面手工设置)2.4 注意事项 3 创建IAM用户3.1 生成密钥对3.2 附加策略3.3 记录访问密钥对 4 编译C 创建者库5 发送6 检查参…

聊聊 Jetpack Compose 的 “状态订阅自动刷新” -- mutableStateListOf

Jekpack Compose “状态订阅&自动刷新” 系列: 【 聊聊 Jetpack Compose 的 “状态订阅&自动刷新” - - MutableState/mutableStateOf 】 【 聊聊 Jetpack Compose 的 “状态订阅&自动刷新” - - remember 和重组作用域 】 【 聊聊 Jetpack Compose 的 …

非标设计之气缸类型

空压机: 空压机又称空气压缩机,简单来说就是将机械能转化为压力能来进行工作的,空压机在电力行业应用比较多,除了在电力行业应用较多外,其实空压机还有一个比较常见的用途就是用来制冷和分离气体,输送气体…

java SSM毕业生信息管理myeclipse开发mysql数据库springMVC模式java编程计算机网页设计

前言 学校的规模不断扩大,学生数量急剧增加,有关学生的各种信息量也成倍增长。面对庞大的信息量需要有学生信息管理系统来提高学生管理工作的效率。通过这样的系统可以做到信息的规范管理、科学统计和快速查询、修改、增加、删除等,从而减少管…

【力扣热题100】207. 课程表 python 拓扑排序

【力扣热题100】207. 课程表 python 拓扑排序 写在最前面207. 课程表解决方案:判断是否可以完成所有课程的学习方法:拓扑排序实现步骤Python 实现性能分析结论 写在最前面 刷一道力扣热题100吧 难度中等 https://leetcode.cn/problems/course-schedule…

[leetcode ~二叉树] 模版

文章目录 1. 左叶子之和2. 翻转二叉树 E 1. 左叶子之和 :::details 给定二叉树的根节点 root ,返回所有左叶子之和。 示例 1: 输入: root [3,9,20,null,null,15,7] 输出: 24 解释: 在这个二叉树中,有两个左叶子,分别是 9 和 15&…

Proteus仿真--基于1602LCD与DS18B20设计的温度报警器

本文介绍基于1602LCD与DS18B20设计的温度报警器设计(完整仿真源文件及代码见文末链接) 仿真图如下 其中温度传感器选用DS18B20器件,主要用于获取温度数据并上传,温度显示1602LCD液晶显示器,报警模块选用蜂鸣器&#…

隐写术和人工智能

在一项新的研究中,人工智能对齐研究实验室 Redwood Research 揭示了大型语言模型 (LLM) 可以掌握“编码推理”,这是一种隐写术形式。 这种有趣的现象使得大型语言模型能够以人类读者无法理解的方式巧妙地将中间推理步骤嵌入到生成的文本中。 大型语言…

从零开始学习 JS APL(五):完整指南和实例解析

目录 学习目标: 学习内容: 学习时间: 学习内容: Window对象: 定时器-延时函数: JS 执行机制: location对象: 本地存储: 本地存储分类- localStorage&#xff1a…

Fiddler移动端抓包

本篇文章,博主想使用通俗易懂的话语,让大家明白以下内容: 什么是抓包哪些场景需要用到抓包Fiddler抓包的原理怎样使用Fiddler进行移动端抓包 抓包 包 (Packet) 是TCP/IP协议通信传输中的数据单位,一般也称“数据包”。 我们平常…

uniapp 云打包 生成安卓证书文件

现在使用uniapp来开发小程序,H5,APP越来越多了,目前开发了一款APP,使用的也是uniapp。在此记录下用uniapp开发app云打包时约到的一些问题吧。 前因是我司安卓同学休产假,像云打包时需要的证书文件只能自己动手来搞。看…

ai绘画Midjourney绘画提示词Prompt教程

一、Midjourney绘画工具 SparkAi【无需魔法使用】: SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如何搭建部署AI创作ChatGPT?小编这里写一个详细图文教程吧!本系统使用NestjsVueTypescript框架技术,持续集成AI能力到…