第一个程序---汇编学习笔记

第四章 第一个程序


4.1 一个源程序从写出到执行的过程

一个汇编语言程序从写到最终执行的简要过程。

  1. 编写汇编源程序
  2. 对源程序进行编译连接
  3. 执行可执行文件中的程序

如图所示:
这里写图片描述


4.2 源程序

程序代码如下:

;assume是假设
assume cs:codesg

;伪指令
;段名 segment
codesg segment
    mov ax,0123H
    mov bx,0456H
    add ax,bx
    add ax,ax

    ;程序返回,没有下面2句,程序发生逻辑错误
    mov ax,4c00H
    int 21H

codesg ends
;段名 ends

end
;end是汇编程序的结束标记

以上代码相关说明:
这里写图片描述

编译连接后:
这里写图片描述


4.3 编辑源程序

过程:

  1. 打开编辑器
  2. 在编辑器中编辑程序。

这里写图片描述


4.4 编译

**编译**T1.asm文件,如图:
这里写图片描述
一般来说,有两类错误使我们得不到所期望的目标文件:

  1. 程序中有“Severe Errors”。
  2. 找不到所给出的源程序文件。

在编译过程中,我们提供一个输入:T1。最多可以的到三个输出:目标文件(.obj)、目标文件(.lst)、交叉引用文件(.crf)。目标文件使我们最终得到的结果,而另外两个只是中间结果,可以让编译器忽略对它们的生成。


4.5 连接

**连接**T1.obj文件,如图:
这里写图片描述
这个程序中有一个警告错误:“没有栈段”,这里我们不理会这个错误。

第一个是输入:目标文件输出是:可执行文件名、映像文件的生成、库文件的连接

连接的作用:

  1. 当源程序很大时,可以将它分为多个源程序文件来编译,每个源程序编译成为目标文件后,再用连接程序将他们连接到一起,生成一个可执行文件;
  2. 程序中调用了某个库文件中的子程序,需要将这个库文件和该程序生成的目标文件连接到一起,生成一个可执行文件;
  3. 一个源程序编译后,得到了存有机器码的目标文件,目标文件中的有些内容还不能直接用来生成可执行文件,连接程序将这些内容处理为最终的可执行信息。所以,在只有一个源程序文件,而又不需要调用某个库中的子程序的情况下,也必须用连接程序对目标文件进行处理,生成可以执行文件。

4.6 以简化的方式进行编译和连接

如图,在命令行的结尾加上分号
这里写图片描述


4.7 T1.exe的执行

运行后没有任何结果,这很正常!因为我们是对寄存器做操作,并不是显示到屏幕上。
这里写图片描述


4.8 谁将可执行文件中的程序转载进入内存并使它运行?

按照上面原理,我们来看一下4.7节中的T1.exe的执行过程(思考相关的问题)。

  1. 在提示符“c:\”后面输入可执行文件的名字“T1”,按Enter键。这时,请思考问题4.1。
  2. T1.exe中的程序运行。
  3. 运行结束,返回,再次显示提示符“c:\”。

问题 4.1

此时,有一个正在运行的程序将 T1.exe 中的程序加载入内存,这个正在运行的程序是什么?它将程序加载入内存后,如何使程序得以运行?

问题 4.2

程序运行结束后,返回到哪里?

我们来了解一下操作系统的外壳

    操作系统是一个由多个功能模块组成的庞大、复杂的软件系统。任何通用的操作系统,都要提供一个称为
shell(外壳)的程序,用户(操作人员)使用这个程序来操作计算机系统进行工作。

    DOS中有一个程序command.com,在这个程序在DOS中称为命令解释器,也就是DOS系统的shell。

    DOS启动时,先完成其他重要的初始化工作,然后运行 command.com,command.com运行后,执行完
其他的相关任务后,在屏幕上显示出由当前盘符和当前路径组成的提示符,比如:“c:\”或“c:\windows”等,
然后等待用户的输入。

    用户可以输入所要执行的命令,比如,cd、dir、type等,这些命令由command执行,command执行完
这些命令后,再次显示由当前盘符和当前路径组成的提示符,等待用户的输入。

    如果用户要执行一个程序,则输入该程序的可执行文件的名称,command首先根据文件名找到可执行文件,
然后将这个可执行文件中的程序加载入内存,设置CS:IP指向程序的入口。此后,command暂停运行,CPU运行
程序。程序运行结束后,返回到command中,command再次显示当前盘符和当前路径组成的提示符,等待用户的
输入。

    在DOS中,command处理各种输入:命令或要执行的程序的文件名。我们就是通过command来进行工作的。

现在来回答问题4.1和4.2中所提到的问题。
(1) 在DOS中直接执行T1.exe时,是正在运行的command,将T1.exe中的程序加载入内存;
(2) command设置CPU的CS:IP指向程序的第一条指令(即程序的入口)。从而使程序得以运行;
(3) 程序运行结束后,返回command中,CPU继续运行command。

这里写图片描述


4.9 程序执行过程的跟踪

在编写程序的时候,常常会出现我们的语法没有错误,而逻辑出现错误。这个时候我们就需要拿起强有力的工具,就是我们的 Debug

通过command的命令:Debug T1.exe

这里写图片描述

由上图,我们可以知道两个信息。

  1. 程序加载后,ds 中存放着程序所在的内存区的段地址,这个内存区的偏移地址为 0,则程序所在的内存区地址为 ds:0;
  2. 这个内存区的前 256 个字节中存放的是 PSP,DOS 用来和程序进行通信。从 256 字节处向后的空间存放的是程序。

我们可以用Debug T1.exe实验一下,如图。
这里写图片描述
发现DS=075A,CS=076A,但是,发现一个SS和书上的不一样,一个是相差10H,而实际上我们做的实验是相差了09H,我想可能标准不一样吧。我们忽略细节(找不到为什么,不过我们只要知道 PSP 是256个字节就对了)。

当我们执行到 int 21h 的时候,需要使用 p命令,这里不说明原因(因为t命令是单步执行,而p是跳出循环)。

q命令 退出Debug。


实验 3 编程、编译、连接、跟踪

这里先吐槽一下,前面2章教我们使用命令的时候,我做笔记是有点想吐的。因为太冗余了,我们只要记住某些命令就行了。可能是本人认为学习汇编是为了学习汇编语言的思想。也许我们需要使用到比如像“中断”这样模式的编程。

(1)将下面的程序保存为 t1.asm 文件,将其生成可执行文件 t1.exe 。
(2)用 Debug 跟踪 t1.exe 的执行过程,写出每一步执行后,相关寄存器中的内容和栈顶的内容。

assume cs:codesg

codesg segment

    mov ax,2000h    ;ax = 2000h
    mov ss,ax       ;ss = 2000h
    mov sp,0        ;sp = 0h
    add sp,10       ;sp = 10h
    pop ax          ;ax = 0h
    pop bx          ;bx = 0h
    push ax         ;ss:e = 0h
    push bx         ;ss:c = 0h
    pop ax          ;ax = 0h
    pop bx          ;ax = 0h

    mov ax,4c00h
    int 21h

codesg ends

end

编写完代码后,如图。
这里写图片描述
这样生成了t1.exe文件。

(3)PSP的头两个字节是CD 20,用 Debug 加载 t1.exe,查看PSP的内容。
(注意,一定要做完这个实验才能进行下面的课程。)
这里写图片描述


本章完。

猜你喜欢

转载自blog.csdn.net/qq_37340753/article/details/81192796