assume cs:codesg codesg segment ; codesg 段开始 start: mov ax , 0123 mov bx , 0456 add ax , bx add ax , ax mov ax , 4c00 int 21h ;后面两条指令实现程序返回,交还控制权 codesg ends ;codesg 段结束 end |
定义了一个 codesg 的段,这个段中存放我们的代码,开头伪指令用 assume 将用做代码段的段 codesg 和 CPU 中的段寄存器 cs 联系起来。 |
1、伪指令:汇编语言中包含两种指令,汇编指令和伪指令;汇编指令是有对应机器码的指令,可以被编译为机器指令,最终为 CPU 所执行。而伪指令没有对应的机器指令,最终不被 CPU 所执行。伪指令是由编译器来执行的指令,编译器根据伪指令来进行相关的编译工作。
XXX segment ;XXX 段开始 : : : XXX ends ;XXX 段结束 |
segment 和 ends 是一对成对使用的伪指令 ,这是写可被编译器编译的汇编文件时,必须要用到的一对伪指令。segment 和 ends 的功能是定义一个段,segment说明一个段的开始,ends说明一个段的结束。 一个汇编程序由多个段组成,这些段被用来存放代码、数据、或当作栈空间来使用。一个源程序中所有将被计算机所处理的信息:指令,数据,栈,被划分到了不同的段中。 |
end | 一个汇编程序的结束标记,编译器在编译汇编程序的过程中,如果碰到伪指令 end ,就结束对源程序的编译。 |
assume | “假设”,它假设某一段寄存器和程序中的某一个用 segment ... ends 定义的段相关联。通过这种关联,需要的情况下编译程序可以将段寄存器和某一个具体的段相联系关联起来。 |
2、源程序中的“程序”
这里的程序只源程序中最终由计算机执行、处理的指令或数据;伪指令由编译器来处理,不算这里的“程序”;
3、标号
eg: “codesg” ;一个标号指代了一个地址。“codesg”做为一个段的名称,这个段的名称最终将被编译、连接程序处理为一个段的段地址。
4、程序的结构
源程序由一些段构成,这些段中存放着代码、数据或将某个段当做栈空空间。
eg: 编程运算 2^3 ①定义一个段叫做“abc”; ②段中写入汇编指令; ③指出程序在哪里结束; ④adc 当作代码段来用;(对于这个例子非必须) 为了程序运行结束能交出cpu控制权,应该在最后加上中断 返回;在同edit编辑代码的时候可以在数后面加上h,不加会出错 |
assume cs:abc abc segment mov ax , 2 mov ax , ax mov ax , ax mov ax , 4c00h int 21 abc ends end |
5、语法错误和逻辑错误
语法错误编译器可以发现,逻辑错误编译器发现不了,等到运行时出bug;
编辑源程序
(需要下载一个edit.com文件,类似debug.exe)
文件写完后可以 File-》Save as 保存到刚才 mount 的文件夹
编译
(需要下载一个 masm 5.0 汇编编译器,文件名为 masm.exe)
// 只输入文件名即可,如果文件不是 .asm 就要输入全名;如果文件不在当前目录就要输入 绝对路径;
//直接按 enter 会生成 1.obj 文件,也可以自己输入自己想要的名字
//生成一个编译器将源程序编译为目标文件的过程中产生的中间结果,直接 enter 就行
//Cross-reference 同上
连接
(需要下载一个LINK.exe文件)
//程序警告没有 "栈段"; 不用理会,我们程序中没用到栈段
//生成可执行文件后直接执行
**操作系统外壳(shell):任何通用的操作系统,都要提供一个称为shell的程序,用户(操作人员)使用这个程序来操作计算机系统进行工作。
调试跟踪汇编程序
// cx=15 表示1.exe程序的机器码只有15个字节
// EXE 程序文件中的加载过程
ds 存放 PSP 的段地址,偏移为 0,所以程序的物理地址就是 SA*16+0+256=SA*16+16*16+0=(SA+16)*16+0;
最终就是:SA+10:0
DS=075A , PSP 的地址就为 075A:0 ; 程序的地址就为 CS:IP = 076A:0
|
//-u查看其它指令(?为什么int 21 变成 15)代码中默认10进制,debug系统一律按16进制,所以代码中要写成 int 21h
//到中断命令要用 p 命令 ,q 命令退出debug