暑假学习小日本的那本书:30天自制操作系统
qq交流群:159336168
A:开发环境:我是完全在ubuntu下面进行的学习,实验。
开源的好处不用多说了。各种软件直接sudo apt-get install就行了,不用到处找。
学习笔记:
org address ; nasm汇编器没有lds文件,所以通过这个方式指定链接地址,
jmp entry
entry;
mov ax,0
mov ds,ax
mov es,ax
mov ss,ax
mov sp,0x7c00 ;这一部分代码只是初始代segment寄存器,没有说不定也可以
mov si,msg ;送的是指针
putcharloop:
mov al,[si]
add si,1
cmp al,0
je finish ;decide when to finish displaying
;this is interrupt to display one character
mov ah,0x0e ;one character
mov bx,15 ;the color of character
int 0x10;
jmp putcharloop
finish:
hlt
jmp finish
msg:
db "\n\nhello,world\n\0"
times 510-($-$$) db 0
dw 0xaa55
这里要学习的重要知识:
bios的0x10中断:
传递的参数al=character ah=function, bx=display color
int 0x10 ; 就这样就可以显示一个字符了,如果要显示多个字符,只要多调用几次 int 0x10
还有if 和loop的实现
cmp al,0
je finish ; 这两条代码实现了c中的 if(al==0) goto finish;
loop 的最简单:
loop:
xxx ;这一部分的指令需要有跳出loop的判断语句
jmp loop
所以这个代码的两个重点:1:int 0x10 2: loop 中if判断的实现
下面是伪c代码:
org 0x7c00
goto entry
entry:
ax=0;
ds=ax;
es=ax;
ss=ax;
sp=0x7c00;
si=msg
putcharloop:
al=*si;
si++;
if(al==0)
goto finish;
ah=0x0e ;
bx=15
interrupt(al,ah,bx);
goto putcharloop;
finish:
while(1);
goto finish;
char *msg="\n\nhello,world\n"
times 510-($-$$) db 0;
short boot_flag=0xaa55;
通过c伪代码 理解整个结构,不要局限于汇编的细节,汇编只有两点新内容
loop:
xxx
cmp al,0
je finish
xxx
jmp loop
还有两条语句拿出来做对比: char *msg="\n\nhello,world\n\0"
mov si,msg ;这个是得到指针,就是地址 si=msg;
mov al,[si] ; 这个是得到指针指向的内容 al=*si;
x86的几个寄存器:
ax:accumulator
bx:base
cx:counter
dx:data
上面几个是通用的,
bp:base pointer 都是指针,所以通常放的是地址
sp:stack pointer
si: source index 数据来源的 地址
di: destination index 数据目的的 地址
全是16位的,上面四个通用的可以折成两个8位,如ax=ah,al 其它三个一样。
16位是说放二进制的数16bits。
读内存mov al,[si]
寄存器之间,mov ds,ax
寄存器只有名字,没有地址,内存有地址。
寄存器的全名是说:通常情况下,这个寄存器是用来干这个活的,盘子是装菜的,但是装其它的东西也行。
add cx,0x1234 ;机器码 4个字节
add ax,0x1234 ;机器码 3个字节
上面的例子说明了一个道理:cpu内部对每个寄存器做了不同的优化,每个寄存器都有自己擅长的操作。ax寄存器就是擅长做add操作,cx这方面就是不好ax
桶就是用来装水的,用桶来装菜,在桌上放着了不方便吃。让每个寄存器发挥自己的优点。从寄存的名字,考虑怎么用这些寄存器。
ax,bx,cx,dx: accumulator,base,counter,data
每个寄存器都有自己的优点:如同金刚葫芦娃一样,每个娃都有自己的牛逼这处。
上面有8个寄存器,每个都是16位的,所以寄存器的存储空间为16个字节。
bp,sp,di,si,这四个寄存器通常都是放的地址,也就是说当指针用,内存的地址通常都是很多位的,8位的内存地址有什么用呢??只有在51单片机中可能有有
如果要用到bp,sp,di,si的高低8位,怎么办,间接的达到目的,曲线救国
mov ax,bp
这时就可以访问al,ah了。
我家的电脑是32位的,这个32位就是通常指的是寄存器的最大位数,
eax,ebx,ecx,edx,esp,ebp,edi,esi
上面是32位的寄存器,低16位与原来的保持兼容,高16位的部分没有名字,所以要访问高16位的数据时,要用移位指令把高16位的数据移到低16位才能使用。
如eax:低16为ax,但是高16位的部分,没有名字,通过移位访问。
几个segment寄存器:
cs,ds,es,ss,fs,gs
code,data,extra,stack,
关于地址的访问:
jmp address ;address为内存的一个地址,pc为指向这个地址
mov si ,msg ; 此时msg 为内存的一个地址
msg,address 都称为标号,英文为label,汇编器负责把这些label翻译成具体的地址。org指令会对编译有label的指令产生影响。因为label地址的产生是以org为基准的,所以
org后面的地址变了,编译器计算出label的地址也会变。
[]方括号,是指针操作,是访问内存中数据的操作
mov al, [si] ; 等效于al =*si;
内存是大规模的放数据的一张表,这个表由表格组成,每个表格都有一个地址。
英文称为memory.
不管是32位的机器,还是16位的机器,寄存器的存储容量都太小了。所以memory用来存放code and data. 32个字节连bootsector的代码都放不了,所以code是必须要放到cpu外部,就是memory中,memory的容量是很大的,所以需要地址方便管理。人少可以叫名字,人多了就只能给学生编上学号,方便管理。
因为内存很大,为了方便管理,每个空间搞个线性的地址。
因为寄存器很少,干脆给每个寄存器起个名字,
cpu与内存进行通信,也就是交换数据,中间还有一个东东,称为memory controller
这个东西用来协调cpu与memory的数据交换过程。
mov al,[si] ;读内存
mov byte [reg] ,123 or reg ;写内存
mov word [reg] ,123 or reg ;写内存
mov dword [reg] ,123 or reg ;写内存
mov byte [address] ,123 or reg ;写内存
mov word [address] ,123 or reg ;写内存
mov dword [address] ,123 or reg ;写内存
有方括号就是与读写内存有关的操作,具体数据的长度看byte word dword
mov bx,dx
mov al,byte[bx] ;读内存
mov al,[bx] ;al 只有8bit 所以读一个字节
add si,1 ; si++;
if a==3
;this is important
cmp al,3
je ;jump if equal
label means address
int 0x10只是一个中断服务程序,bios提供的一个函数,输入参数为al=character you want to display,ah=how many character ,bx=color
int:interrupt
int is provided by bios
hlt:means halt
halt指令只是sleep的状态,一旦有外部中断发生,还是会执行中断
bios会所启动设备的头512字节的代码复制到内存中地址为0x7c00-0x7dff处
bios把代码复制到0x7c00处,可能没有什么特别的原因,只是这样做可以罢了。可能有个时代背景的原因。但这个对现在的人已经不重要,只是一个rule.
ipl:inital program loader
makefile文件的学习比较简单,注意语法,格式就行了,依赖关系搞清楚。
msg:后面的字符串如果当code解释,
0x0a 0x0a,解释成代码是 or cl,[bp+si]
0x68 0x65 0x6c,解释成代码是push 0x6c65
作者,把msg:后面的"\n\nhello,world\n"
本来是显示的信息,如果当代码解释 就是上面的两条代码。
cpu一直是把pc指向的内容当指令。不管他是指令还是信息,都会当指令去执行。
人才是程序的编写着,安排着,要知道什么是code,什么是data.
cpu是不关心这些电信号是干什么的,只有人类正确的安装,上下文件,才会产生伟大的程序。安排好cpu要做的一切,内存中哪部分是code,哪部分是data.
可能性的存在:数码相机拍一个照片,当程序给cpu执行,可能就是一个很好的程序
写一个程序,保存成jpg的格式,可能就是一幅好的 艺术品。
有点问题:hlt指好像没有起作用,不知为什么。
在hello.asm中,用下面的代码测试了hlt指令,但是好像没有用,会一直打印1
finish:
hlt
mov al,0x31 ; ascii for 1
int 0x10
hlt
jmp finish