1. org 0x7c00
ORG: 是伪指令, 而且是给链接器用的, 是在链接的时候, 让 代码里的所有偏移地址, 从 0x7c00开始, 而不是 0x0000
比如 mov ds, ax,默认编译完成后 , 他的地址是 从 0x00开始, 逐渐递增, 而 org ***, 只是让 地址从 0x**开始递增而已.
一些其他的书籍(比如自己动手写操作系统), 很多示例代码, 会在boot.s先加上 org 0x7c00;
原因是, bios会做一些固定的操作, 自检完毕后, 会把 启动扇区的头512个字节加载到 0x0000: 0x7cc 处,
并且设置 cs = 0x0000, ip = 0x7c00. 这里要说明一下, 如果, boot.s里全是 mov ds, ax这种不在乎偏移地址的操作, 其实没啥大关系, 一点儿影响都没有, 因为 不论 boot.s 有没有 org 0x7c00, 反正 可执行代码都被加载到了 0x7c00出, 一样可以执行的.
至于为什么一定要加 org, 是因为, 程序中, 会用某些 label
比如
mov ax, msg
msg:
.ascii "hello system"
如果没有 org , 那么实际上,编译后的 , 是这种的, mov ax 0x12; 0x12 是 msg的地址, 当加了 org 0x7c00的时候, 编译后是 mov ax, 0x7c12, 这才是 msg真正的地址, ORG只是起了这个作用而已.
在 linux 0.00 那个多任务的示例代码中, 没有用这种方式(貌似是 nasm独有的? 不知道), 用了 jmpi go, 0x7c0, 这种方式, 实际上是通过改变段寄存器CS来达到这种效果的
cs= 0x7c0, ip = go, 所以加完了, 也是 0x7c0 左移四位(*16), 再加上go,一样是 0x7c00 + go.
2. 汇编指令IRET
【指令格式】IRET
【指令功能】IRET(interrupt return)中断返回,中断服务程序的最后一条指令。IRET指令将推入堆栈的段地址和偏移地址弹出,使程序返回到原来发生中断的地方。其作用是从中断中恢复中断前的状态,具体作用有如下三点:
1.恢复IP(instruction pointer):(IP)←((SP)+1:(SP)),(SP)←(SP)+2
2.恢复CS(code segment):(CS)←((SP)+1:(SP)),(SP)←(SP)+2
3.恢复中断前的PSW(program status word),即恢复中断前的标志寄存器的状态。
(FR)←((SP)+1:(SP)),(SP)←(SP)+2
4.恢复ESP(返回权限发生变化)
5.恢复SS(返回权限发生变化)
以上操作按顺序进行。
3. CALL和 RET指令
ret指令和retf指令
ret
指令用栈中的数据,修改IP的内容,从而实现近转移retf
指令用栈的数据,修改CS和IP的内容,从而实现远转移
CPU执行ret
指令时,相当于进行:
pop IP
CPU执行retf
指令时,相当于进行:
pop IP
pop CS
call指令
当执行call指令时,进行两步操作:
1)将当前的IP或CS和IP压入栈中
2)转移
call指令不能实现短转移,它的书写格式同jmp指令
依据标号进行转移的call指令
语法格式:call 标号
汇编解释:(1) push IP (2) jmp near ptr 标号
依据目的地址在指令中的call指令
语法格式:call far ptr 标号
汇编解释:(1) push CS (2) push IP (3) jmp far ptr 标号
转移地址在寄存器中的call指令
语法格式:call 16位reg
汇编解释:(1) push IP (2) jmp 16位reg
转移地址在内存中的call指令
语法格式一:call word ptr 内存单元地址
汇编解释一:(1) push IP (2) jmp word ptr 内存单元地址
语法格式二:call dword ptr 内存单元地址
汇编解释二:(1) push CS (2) push IP (3) jmp dword ptr 内存单元地址
也就是说, CALL 会 自动把 IP或者CS / IP压入栈中 ,然后再 JMP,
而JMP,就只是设置了cs:ip(返回后,原函数需要继续执行的地址),方便CPU去执行.