【汇编】汇编的helloWorld
过程
汇编源代码 -> 编译 -> 链接 -> 执行exe。
编译:将源码翻译成机器代码,生成目标(obj)文件。有 x 个源码文件就会生成 x 个目标文件。
链接:将目标文件进行链接,生成exe文件。
在dos中,shell是一直运行的进程,当执行汇编exe时,shell会将exe加载进内存,shell中断暂停运行,并设置CPU的CS:IP指向入口。exe执行结束后中断返回至shell,shell继续运行。
exe
exe中包含两部分文件,程序(exe)和数据;相关的描述信息(map),比如程序有多大,占用的内存空间等。
在操作系统中,操作系统依照可执行文件中的描述信息,加载机器码和数据,并进行相关初始化(比如设置cs:ip指向第一条要执行的指令),然后CPU执行程序。
dos加载exe的过程
- 找到一段起始地址SA:0,起始地址的偏移地址为0的容量足够的空闲内存区。
- 在这个内存去的前256个字节,创建一个数据区(PSP),DOS利用PSP来和家在程序进行通信。
- 程序被加载在PSP后面,程序地址被设为SA+10H:0。
- 将该内存区(程序起始内存地址,不是程序入口地址,不是CS:IP,这里包含了PSP区域)的段地址存入ds,初始化其他寄存器,设置CS:IP指向程序的入口。
需要特别注意的是:PSP区域是属于程序内存区域的,相当于ds:0这里既是PSP区域也是程序内的内存地址,从ds:100后开始是程序指令的入口地址。
而不是说PSP区域不是程序内存,他们不是分开的。
访问psp区域:ds:0
为什么是 SA+10H:0
程序加载后,ds存放着程序所在内存区的段地址,这个内存区的偏移地址为0,即地址为ds:0。
这个内存区的前256个字节是PSP,256之后是程序。
所以,PSP的段地址是SA,PSP偏移地址是0,所以物理地址是SA*16 + 0。
因为PSP占用256字节,所以程序物理地址是:
SA * 16 + 0 + 256 = SA * 16 + 16 * 16 + 0 = (SA+16)*16 + 0
简化乘法分配律,即得SA + 10H:0。
SA * 16 + 0 是起始地址,加上 PSP 的大小后就是程序的物理地址。
PSP区域相关
PSP是dos和程序通信的模块,比如有一些命令行参数等信息会保存在这里。
头字节是 CD 20,是指令int 20H
码,作用是退出程序,返回DOS。
int 21h 和 int 20h 是 DOS(Disk Operating System)中用于系统调用的软中断指令。
int 21h 用于调用 DOS 提供的各种服务程序,如读写文件、创建进程、获取系统时间等。根据不同的功能需要,在 AH 寄存器中传入对应的功能号,同时还可以传入其他必要的参数和数据。
例如,AH=02h 表示显示一个字符,需要将待显示的字符存放在 DL 寄存器中。通过 int 21h,程序可以利用 DOS 提供的功能实现文件的读写、屏幕输出等操作。
int 20h 用于终止程序的执行,其作用相当于执行 return 语句。当程序执行到 int 20h 指令时,程序将停止执行并返回操作系统,释放占用的内存资源等。
需要注意的是,在现代操作系统中,int 21h 和 int 20h 已经不再是常用的系统调用方式,取而代之的是更为先进、高效的 API 接口。
INT 21H 功能号码表
https://blog.51cto.com/u_15127637/4342756
源码分析
assume cs:code, ds: data, ss: stack
data segment
dw 1, 2, 3, 4
data ends
stack segment stack
dw 0H,0H,0H,0H
stack ends
code segment
start: mov ax, stack
mov ss, ax
mov sp, 16
mov ax, data
mov ds, ax
mov cx, 8
mov ax, 4c00h
int 21h
code ends
end start
伪指令
汇编指令有对应的机器码指令,可以被编译为机器指令,CPU最终执行。
伪指令是编译器来执行的指令,编译器根据伪指令来进行相关的编译工作。
XXX segemnt / XXX ends
这是一对指令伪指令,作用是定义一个段,segment说明一个段开始,ends说明一个段结束。
段名 segment
...
段名 ends
这里的段名可以任意取名。
end
这里的end是end start
中的end,不是段的ends,代表了对源程序的编译,写完程序要加上end,不然编译器不知道在何时结束。
start
start是一个标号,代表程序入口在此。程序加载到内存后,CS:IP会指向这个标号,从start指向的指令开始运行。
start换成main也行,start不一定在程序代码最前面,也有可能在中间,前面是可以有指令或者数据的,但这样很不规范,在代码段里放置变量。
assume
定义标记符,将segement...end的段和某一寄存器相关联。
assume cs:code
定义了一个代码段,使用了assume来关联了cs寄存器。
程序的返回
当程序运行结束之后就要返回,返回程序段如下。
mov ax, 4c00H
int 21H
调用 INT 21H 的 4CH 号中断,安全退出程序。