源程序

  伪指令

    segment和ends

    end

    assume

  标号

  程序的结构

  程序返回

  语法错误和逻辑错误

  编译

  连接

  执行

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

    问题1

    问题2

操作系统的外壳

程序执行过程的跟踪

 

 

源程序

第一步:编写汇编源程序

使用文本编辑器(记事本等),用汇编语言来编写汇编语言

 

第二步:编译源程序

使用汇编语言的编译程序对源程序进行编译,产生目标文件

再用连接程序对目标程序进行连接,生成可执行文件

 

可执行分界线包含两部分内容:

程序和数据

相关的描述信息

 

第三步:执行可执行文件中的程序

1 assume cs:codesg
 2 codesg segment
 3     mov ax,0123H
 4     mov bx,0456H
 5     add ax,bx
 6     add ax, ax
 7     mov ax,4c0OH
 8     int 21H
 9 codesg ends
10 end

在汇编源程序中包含两种指令,一种是汇编指令,一种是伪指令

汇编指令有对应的机器码,可以被编译为机器指令被cpu执行

 

伪指令没有对应的机器指令,不能被cpu执行

伪指令由编辑器执行

 

 

伪指令

 

segment和ends

 

segment和ends是一对 成对使用的伪指令,这是在写可被编译器编译的汇编程序时,必须要用到的一对伪指令。

 

segment和ends的功能是定义一个段

segment说明一个段开始

ends说明一个段结束

一个段必须有一个名称来标识,使用格式为:

1 段名 segment
2  :
3 段名 ends

 

 

一个汇编程序是由多个段组成的,一个有意义的汇编程序至少有一个存放代码的段

 

 

end

end是一个汇编程序的结束标记,编译器遇到end就会结束对源程序的编译

注意end后面没有s,ends是段结束

 

 

assume

含义为"假设"

它假设某一段寄存器 和 程序中的某一个用segment...ends定义的段相关联。

通过assume 说明这种关联,在需要的情况下,编译程序可以将段寄存器和某一个具体的段相联系。

不需要深入理解,只要记着用assume将有特定用途的段和相关的段寄存器关联起来就行

 

 

源程序由计算机编译成程序

程序以汇编指令的形式粗在于源程序中

编译连接后变成机器码,存储在可执行文件里

iOS 编写汇编 怎么写汇编代码_bc

 

 

 

 

 

标号

一个标号代表了一个地址

比如

codesg:放在segment前面

作为一个段的名称

这个段的名称最终将被编译、连接程序处理为一个段地址

程序的结构

 

例题:运算2^3

先定义一个段,名为abc

1 abc segment
2   :
3 abc ends

之后在段中写入汇编指令

1 abc segment
2  
3   mov ax,2
4   add ax,ax
5   add ax,ax
6  
7 abc ends

段写完后要指出程序在何时结束

1 abc segment
2  
3   mov ax,2
4   add ax,ax
5   add ax,ax
6  
7 abc ends
8 end
9

abc作为代码段所以要让cs指向abc

1 abc segment
2   mov ax,2
3   add ax,ax
4   add ax,ax
5   abc ends
6  
7 end

程序返回

 

DOS是一个单任务操作系统

一个程序P2在可执行文件中则必须有一个正在运行的程序P1

将P2从可执行文件中加载入内存后

将CPU控制权交结P2,P2才能得运行·P2开始运行后,P1暂停运行

 

而当P2运行完毕后,应该将CPU的控制权交还给使它得以运行的程序Pl

此后P1继续运行

 

程序返回 就是将CPU的控制权交还给使它得以运行的程序,

程序的末尾添加返回的程序段

mov ax, 4c00H int 21H

这两条指令所实现的功能就是程序返回

暂时不需要理解原因,只需要知道这两条指令可以实现程序返回

iOS 编写汇编 怎么写汇编代码_汇编_02

 

 

语法错误和逻辑错误

语法错误:

编译时被编译器发现的错误

 

逻辑错误:

编译后,运行时发生的错误是逻辑错误

 

 

 

 

编译

使用dosbox编译

在编辑器里写号源代码,后缀名是asm

存放在c:/code(dosbox默认目录)

 

打开dosbox,输入dir,就能显示出文件(文件夹变动,dosbox必须重启才能在里面看到)

 

开始编译

输入masm + 名字.asm

iOS 编写汇编 怎么写汇编代码_可执行文件_03

 

或者这样,输入masm,在第一行后面写文件名(如果文件后缀是asm,则可省略不写)

后面都可按enter跳过,或者输入路径,指定生成位置

iOS 编写汇编 怎么写汇编代码_加载_04

最终生成目标文件.obj 其中.list(列表文件) .crf(交叉引用文件)是中间结果,可忽略

 

 

连接

使用dosbox

输入link

 

iOS 编写汇编 怎么写汇编代码_可执行文件_05

类似编译

只要在第一行输入文件名即可,后面可跳过

 

最后一行报错是 没有栈段,可忽略

 

最后生成 .EXE文件

 

 

还有种简洁的方法

masm 1;

link 1;

自动跳过中间文件

直接生成目标文件

iOS 编写汇编 怎么写汇编代码_bc_06

 

 

 

 

 

执行

在dosbox里执行文件,win10里不支持这种格式了

iOS 编写汇编 怎么写汇编代码_bc_07

执行没结果,很正常,因为没有写向显示器输出信息的命令

后面再说

 

如果在想用debug跟踪执行

只要 debug xxx.exe 即可

然后输入t,输入一次执行一行

 

 

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

前文提过

在DOS中,可执行文件中的程序 a 若要运行

必须有一个正在运行的程序 b,

将 a 从可执行文件中加载入内存,将CPU的控制权交给它,a 才能得以运行;

当 a 运行完毕后,应该将CPU的控制权交还给使它得以运行的程序 b。

 

 

按照上面的原理,再来看一下 上面的 执行 中的 1.exe的执行过程

(1)在提示符 “c:\>” 后面输入可执行文件的名字“1”,按Enter键。

这时,请思考问题1。

 

(2)1.exe中的程序运行

 

(3)运行结束,返回,再次显示提示符 “c:\>” 。请思考问题2。.

 

问题1

此时,有一个正在运行的程序将1.exe中的程序加载入内存,这个正在运行的程序是

什么?它将程序加载入内存后,如何使程序得以运行?

 

问题2

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

 

如果你对DOS有比较深入的了解,那么,很容易回答问题4.1、问题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来进行工作的

 

 

 

现在我们可以回答 问题1和2

问题1:

是正在运行的command,将1.exe中的程序加载入内存;

command 设置CPU的 CS:IP指向程序的第一条指令(即程序的入口),从而使程序得以运行;

问题2

程序运行结束后,返回到command 中,CPU继续运行command。

 

iOS 编写汇编 怎么写汇编代码_加载_08

 

 

 

 

 

程序执行过程的跟踪

可以用Debug来跟踪一个程序的运行过程

对于隐藏较深的错误,就必须对程序的执行过程进行跟踪分析才容易发现。

 

以1.exe为例,讲解如何用Debug 对程序的执行过程进行跟踪。

 

现在我们知道,在DOS中运行一个程序的时候,是由command 将程序从可执行文件中加载入内存,并使其得以执行。

而Debug可以将程序加载入内存,设置CS:IP指向程序的入口

但Debug 并不放弃对CPU的控制

这样,我们就可以使用Debug的相关命令来单步执行程序,查看每一条指令的执行结果。

输入


 

iOS 编写汇编 怎么写汇编代码_汇编_09

 

DOS中.exe文件中的程序的加载过程


 

iOS 编写汇编 怎么写汇编代码_加载_10

注意,有一步称为重定位的工作没有讲解,因为这个问题和操作系统的关系较大,不作讨论

 

 

从上图中我们知道以下的信息。

(1)程序加载后,ds 中存放着程序所在内存区的段地址,这个内存区的偏移地址为0,则程序所在的内存区的地址为ds:0;

(2)这个内存区的前256个字节中存放的是PSP,DOS用来和程序进行通信。

从256字节处向后的空间存放的是程序。

所以,从ds中可以得到PSP的段地址SA,PSP的偏移地址为0,则物理地址为SA×16+0。

因为PSP占256(100H)字节,所以程序的物理地址是:

SA×16+0+256 = SA×16+16×16+0= (SA+16) × 16 + 0

可用段地址和偏移地址表示为:SA+10H:0。

 

 

iOS 编写汇编 怎么写汇编代码_汇编_11


上图中,DS = 075C,IP = 0,CS:IP 指向程序的第一条指令

所以程序的地址为075C + 10 :0 即 076C : 0

cs里就是076C

注意,debug里默认数据用16进制表示

 

使用u查看指令


 

iOS 编写汇编 怎么写汇编代码_可执行文件_12

输入t开始单步执行,观察每一步指令的执行结果,直到int 21

用p命令执行int 21


iOS 编写汇编 怎么写汇编代码_汇编_13

 

 

上图中 int 21 执行后,显示出“Program terminated normally” 返回到 Debug中。

表示程序正常结束。

注意,要使用Р命令执行int 21。

这里不必考虑是为什么,只要记住这一点就可以了。

 

需要注意的是,在这里是Debug 将程序加载入内存

所以程序运行结束后要返回到Debug 中

 

使用 q 命令退出 Debug,将返回到command 中

因为Debug 是由command加载运行的。

 

在DOS中用“debug 1.exe”运行Debug对1.exe进行跟踪时

程序加载的顺序是:

command加载Debug

Debug加载1.exe

 

返回的顺序是:

从 1.exe中的程序返回到Debug

从Debug 返回到command

 

 

参考: 王爽 - 汇编语言 和 小甲鱼零基础汇编

 

源程序

  伪指令

    segment和ends

    end

    assume

  标号

  程序的结构

  程序返回

  语法错误和逻辑错误

  编译

  连接

  执行

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

    问题1

    问题2

     操作系统的外壳

程序执行过程的跟踪