自己手动写操作系统

org 是Origin的缩写:起始地址汇编语言源程序中若没有ORG伪指令,则程序执行时,指令代码被放到自由内存空间的CS:0处;若有ORG伪指令,编译器则把其后的指令代码放到ORG伪指令指定的偏移地址
在nasm中任何不被[]括起来的标签或变量名都被认为是地址,如果想访问标签中的内容必须使用[]。
foo dw 1 === foo: dw 1 第一个foo是变量,第二个foo是标签, 在nasm中变量和标签是一样的。
mov ax foo //是将foo的地址给ax
mov ax [foo] //是将foo的值给ax

$表示当前位置在编译后的地址
$$表示当前节(section)在编译后的地址

汇编指令是与cpu相关的,请搜索x86汇编指令大全。但书写形式因汇编器的不同而不同,如masm,nasm, gas
伪指令是与汇编器有关的,它的目的是辅助编译器编译代码,编译后的代码里没有伪指令。

//bochs的编译:
. /configure -- enable-debugger -- enable-disasm -- enable-readline LIBS= '-lX11'

制作启动盘:
dd if=/dev/zero of=d.img bs=10485760 count=1 //制作10M的镜像 10485760=1024*1024*10
使用nasm写512字节的以0x55aa结束的MBR程序boot.bin
dd if=boot.bin of=d.img bs=512 count=1 conv=notrunc //用boot.bin覆盖d.img的前512字节
nasm boot.asm -o boot.bin
boot.asm:
org 0x7c00; mov ax,cs; mov ds,ax; mov es,ax;
call ShowMessage;
jmp $;
ShowMessage:
mov ax, BootMessage; mov bp, ax; mov cx, 16;
mov ax, 01301h; mov bx, 000ch; mov dl, 0;
int 10h;
ret

BootMessage: db 'Hello, OS Wo111'
times 510-($-$$) db 0;
dw 0xaa55;
nasm支持预编译宏:%include, % define

xor异或:和加法的运算法则相同,只是不带进位,0 0=0,0 1=1,1 1=0
xor ax,ax;清零
SP:堆栈寄存器SP(stack pointer)
BP: 基数指针寄存器BP(base pointer)
shl和shr是逻辑移位指令。
==================================================================================================================================================
SECTION 是一种组织代码和存储的方式. [SECTION .data] [SECTION .mysection]
1. NASM 支持标准的 .data, .text .bss
2.NASM 支持用户自定义 section
3. 同名的 section ,编译后会放在同一块连续的内存上
4. 每个 SECTION 默认都是按 4 字节对齐的,SECTION的对齐方式可以用ALIGN来调整:ALIGN 32
===================================================================================================================================================
[BITS 32]与[BITS 16]
'BITS'指令指定NASM产生的代码是被设计运行在16位模式的处理器上还是运行在32位模式的处理器上
'aout','coff','elf'和'win32'目标文件格式都是被设计用在32位操作系统上的,它们会让NASM缺省选择32位模式
而'obj'目标文件格式(即纯粹的二进制可执行文件,不带任何头文件)允许你为 每一个段 指定'USE16'或'USE32',然后NASM就会按你的指定设定操作模式
比如:push 0 ;既可以是push 0000 也可以是 push 00000000,编译器需要知道 当前段 是16位模式或32位模式,来push后面几个字节入栈。
===================================================================================================================================================
CLI 全称 Clear Interupt 屏蔽中断
STI 全称 Set Interupt 恢复中断
设置栈基址SS和偏移地址SP时,需要CLI,因为设置SS与SP必须是原子操作
CLD和STD 把标志(flags)寄存器的DF=0, 地址指针si、di增加 ;如是std则把DF=1,地址指针减小也, 是在字行块传送时使用的.
CLD 全称 Clear Director
STD 全称 Set Director
===================================================================================================================================================
字符串处理指令
(1) lodsb、lodsw:把DS:SI指向的存储单元中的数据装入AL或AX,然后根据DF标志增减SI
(2) stosb、stosw:把AL或AX中的数据装入ES:DI指向的存储单元,然后根据DF标志增减DI
(3) movsb、movsw:把DS:SI指向的存储单元中的数据装入ES:DI指向的存储单元中,然后根据DF标志分别增减SI和DI
(4) scasb、scasw:把AL或AX中的数据与ES:DI指向的存储单元中的数据相减,影响标志位,然后根据DF标志分别增减SI和DI
(5) cmpsb、cmpsw:把DS:SI指向的存储单元中的数据与ES:DI指向的存储单元中的数据相减,影响标志位,然后根据DF标志分别增减SI和DI
(6) rep:重复其后的串操作指令。重复前先判断CX是否为0,为0就结束重复,否则CX减1,重复其后的串操作指令。主要用在MOVS和STOS前。一般不用在LODS前。
上述指令涉及的寄存器:段寄存器DS和ES、变址寄存器SI和DI、累加器AX、计数器CX
           涉及的标志位:DF、AF、CF、OF、PF、SF、ZF
=====================================================================================================================================================
DPL(Descriptor Privilege Level),
CPL(Current Privilege Level),
RPL(Required Privilege Level)
数据段的访问时特权级检查,只要CPL和RPL都小于DPL就可以访问此数据段。

======================================================================================================================================================
Linux对于TSS的使用(违背了Intel的初衷):
所有的进程共享一个TSS和TR,每次从ring3->ring0切换时,内核程序只更新TSS中的SS0与ESP0为最新值即可。
每个进程的寄存器组信息由task_struct来维护,从ring0->ring3时由自身进程缓存的寄存器组来设置所有寄存器。
TR寄存器里放的是tss的选择子,接下来在特权级转换时,不同特权级的堆栈的切换都是由CPU完成:
call:

ret:
========================================================================================================================================================
HLT指令:
使程序停止运行,处理器进入暂停状态,不执行任何操作,不影响标志。当复位(外语:RESET)线上有复位信号、CPU响应非屏蔽中断、CPU响应可屏蔽中断3种情况之一时,CPU脱离暂停状态,执行HLT的下一条指令
========================================================================================================================================================
MBR=446字节的引导程序+16*4=64字节的4个主分区+55aa结束标志。
一条分区记录:
80 01 01 00 0B FE BF FC 3F 00 00 00 7E 86 BB 00  在这里我们可以看到,最前面的“80”是一个分区的激活标志,表示系统可引导;“01 01 00”表示分区开始的磁头号为01,开始的扇区号为01,开始的柱面号为00;“0B”表示分区的系统类型是FAT32,其他比较常用的有 04(FAT16)、07(NTFS);“FE BF FC”表示分区结束的磁头号为254,分区结束的扇区号为63、分区结束的柱面号为764;“3F 00 00 00”表示首扇区的相对扇区号为63;“7E 86 BB 00”表示总扇区数为12289622。
==============================================================================================================================================================
中断门和陷阱门是特殊的调用门
分页机制开关cr0的PG位置1
保护模式开关cr0的最低位置1
Nasm的equ是宏,不会占用二进制文件的数据空间,StrLen equ $-$$;
cr3又叫PDBR(Page-Directory Base Register)共32位,前20位是页目录基址,因为页是4K大小对齐的,所以页目录基址为前20位+12位的0,后12位为控制属性。
段描述符:段基址,段界限和段属性三部分组成
段选择子(cs,ds,es,ss):13位做索引,后三位控制属性RPL2位和TI(0 GDT,1 LDT)1位
gdtr:gdt基址寄存器
ldtr:ldt基址寄存器
tr: tss基址寄存器
idtr:idt基址寄存器

IDT是描述符表,里面有中断门,陷阱门和任务门(任务门在linux中根本没有用到),linux里的系统调用使用的是中断门int,没有使用调用门call。
global _start链接器用于global指向的_start标签作为程序的入口地址。
=================================================================================================================================================================
实模式下段值还被看做是地址的一部分XXXX0,但在保护模式下段值只是做为索引来取段描述符。
===============================================================================================================================================================
bochs调试命令: bochs调试方法与指令详解 https://blog.csdn.net/liu0808/article/details/53099099
b 物理地址:设置断点
info break:查询目前已经设置过的断点
c:执行程序,直到遇到断点
s:单步执行
step N:执行N条指令
info r :查询基本的寄存器的值
dump_cpu:比info r的更全面,而且连影子寄存器的值都打印出来了
xp /Nbx 物理地址: 查询从某个地址开始的N个字节的内存
print-stack:打印当前栈里的内容
disassemble 起始地址 终止地址:反汇编一段内存

==========================================================================================================================================================
GDT:包括数据段,代码段,系统段和门
系统段包括TSS和LDT
门包括调用门,中断门和陷阱门

==================================================================================================
一致性代码中的“一致”的意思是:当转移的目标是一个特权级更高的一致代码段,当前的特权级会被延续下去,而向特权级更高的非一致代码段的转移会引起常规保护错误,除非使用调用门或任务门。
应用:如果系统代码不访问受保护的资源时,它可以放在一致代码段中;
为避免低特权级程序访问被保护起来的系统代码则应放到非一致代码段中。
目标是非一致代码段,要求CPL必须等于目标段的DPL,并且要求RPL小于等于DPL。对于目标是一致代码段,RPL不参与检查。
如果目标代码的特权级低,无论它是不是一致代码段,都不能通过call或jmp转移进去,即高特权代码段不能调用低特权代码段。
所有的数据段都是非一致的,即不可能被低特权级的代码访问到。而与代码段不同的是,数据段可以被高特权级的代码访问到。

jmp selector:offset解释
selector为GDTR或LDTR基址的offset,一般selector的值为0,0x8,0x10,0x18,0x20
也可将selector放入段寄存器cs,es,ds,gs中。

selector的TI位标识是GDT还是LDT选择子,如果是GDT选择子,则从GDTR为基址,offset的值为selector,取出段描述符,再从描述符中取中段基址,再用段基址加上selector:offset中offset得到线性地址。
如果是LDT选择子,先拿索引GDT中的LDT的选择子来加载LDTR, 再以LDTR的值为索引,取出GDT中LDT的描述符中的段基址作为LDT的基址,再以selector为索引取出LDT中对应的描述符的段基址再加上selector:offset中offset得到线性地址。

调用门的描述符里的没有段基址,它是引用另一个特权级更高的选择子,而它本身的特权级是低的,这样低特权级代码可以通过调用门来调用特权级高的代码。

===================================================================================================================================================
ret 用栈中数据改IP内容,近转移.
ret   ->  pop ip
retf用栈中数据同时改CS,IP,远转移
retf  ->  pop ip
             pop cs
=====================================================================================================================================

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值