• 操作系统开发系列—1.HelloWorld ●


    		org 07c00h	    ;伪指令,告诉编译器程序会被加载到7c00处
    
    		mov ax, cs
    		mov ds, ax
    		mov es, ax
    		call DispStr	     ;调用显示字符串例程
    		jmp $			;无限循环
    DispStr:
    		mov ax, BootMessage
    		mov bp, ax		;ES:BP=字符串地址
    		mov cx, 22		;CX=字符串长度
    
    		mov ax, 01301h		;AH=13,AL=01h
    		mov bx, 000ch		;页号为0(BH=0)黑底红字(BL=0Ch,高亮)
    		mov dl, 0
    		int 10h			;10h号中断
    		ret	                ;pop IP
    BootMessage:	db "Hello world! I'm Joey!"
    times 510-($-$$)db 0	         ;填充剩下的空间,使生成的二进制代码恰好为512字节
    dw	0xaa55				;结束标志
            
    

    a.编译

    首先编译源码:

    nasm boot.asm -o boot.bin

    或者

    nasm boot.asm -o boot.com(在DOS中运行)

    然后创建一个软盘映像,进入安装好的Bochs目录下:

    bximage

    Create new floppy or hard disk image | fd | 1.44 | a.img 在Bochs目录下生成了一个空的a.img。

    在linux中执行,如果是windows下的则不需要conv=notrunc:

    dd if=boot.bin of=a.img bs=512 count=1 conv=notrunc

    b.运行

    用VMware虚拟机用软盘的方式加载这个a.img,结果如下:

    源码解析:

    1.org 07c00h和dw 0xaa55和times 510-($-$$) db 0

    当计算机电源打开,会先进行加电自检(POST),然后寻找启动盘,如果是选择从软盘启动,计算机会检查软盘的0面0磁道1扇区,如果发现它以0xaa55结束,则BIOS认为它是一个引导扇区。一个正确的引导扇区除了以0xaa55结束之外,还应该包含一段512字节的执行码。一旦BIOS发现了引导扇区,就会将这512字节的内容装载到内存地址0000:7c00处,然后跳转到0000:7c00处将控制权彻底交给这段引导代码。

    org 07c00h就是告诉编译器,这段代码是要被加载到这个地址的。所以BootMessage的偏移地址是相对于0000:07c00h处开始的。BootMessage实际上也是一个地址,不是相对量

    2.mov ax, cs、mov ds, ax、mov es, ax

    让ds和es指向当前代码段。以便在以后进行数据操作的时候能定位到正确的位置。

    3.call DispStr

    调用显示字符串的函数,在NASM中,任何不被[]括起来的标签或变量名都被认为是地址,如果是访问标签中的内容则必须使用[]。所以mov ax, BootMessage会把"Hello,OS world!"这个字符串的首地址传给寄存器ax。然后mov bp, ax赋给bp,如果没写org指令,则BootMessage编译的时候就是相对于本程序加载到地址0的偏移地址,但是这里是相对于0000:07c00h为基址的偏移地址,所以这里显示了org的作用。

    4.int 10h

    10H中断是由BIOS对显示器和屏幕所提供的服务程序。使用int 10h服务程序时,必须先指定ah寄存器。

    功能13h:

    功能描述:在Teletype模式下显示字符串
    入口参数:AH=13H
    BH=页码
    BL=属性(若AL=00H或 01H)
    CX=显示字符串长度
    (DH、DL)=坐标(行、列)

    ES:BP=显示字符串的地址
    AL=显示输出方式
    0—— 字符串中只含显示字符,其显示属性在BL中。显示后,光标位置不变
    1——字符串中只含显示字符,其显示属性在BL中。显示后,光标位置改变
    2 ——字符串中含显示字符和显示属性。显示后,光标位置不变
    3——字符串中含显示字符和显示属性。显示后,光标位置改变
    出口参数:无

    5.$和$$

    $-$$表示本行距离程序开始处的相对距离。times 510-($-$$) db 0表示将0这个字节重复510-($-$$)遍,也就是在剩下的空间中不停地填充0,直到程序有510字节为止。这样,加上结束标志0xaa55占用的2字节,恰好是512字节。

    c.调试

    对bochsrc.bxrc文件右键Debbuger,然后start。可以先在07c00h处设一个断点,引导扇区就是从这里开始执行的,所以这里就是我们的入口地址,b 0x7c00。然后单步执行。

    b 0x7c00——在0x7c00处设置断点

    info break——显示当前所有断点信息

    c——让代码继续执行,直到遇上断点

    r——查看通用寄存器值

    x /64bx 0x7c00——从0x7c00地址处开始的64字节的内存数据(x是线性地址,xp是物理地址)

    x /nuf addr ——【显示指定内存地址的数据,addr可以是线性的内存地址,也可以是虚址 格式是基址:偏移或者基址寄存器:偏移

    n 显示的数据长度 

    u 数据单元大小 b,h,w,g分别对应1,2,4,8字节

    f 数据显示格式 x,d,u,o,t,c分别对应十六进制、十进制、无符号十进制、八进制、二进制、字符串】

    s——单步执行

    n——单步执行,遇到函数则跳过

    trace-reg on——每走一步都显示主要寄存器的值

    print-stack——查看堆栈

    sreg——段寄存器

    creg——查看控制寄存器(cr0,cr1,cr2,cr3)

    dreg——查看调试寄存器(dr0-dr7)

    info idt——展示中断描述表

    info ivt——展示中断向量表(保护模式下无效)

    info gdt——展示全局描述表

    info tss——展示当前的任务状态段

    info cr——展示CR0-CR4寄存器状态 (无法使用)

    info flags——展示标志寄存器   (无法使用)

    这里再插一句,标志寄存器的查看方法:

    eflags 0x00000002: id vip vif ac vm rf nt IOPL=0 of df if tf sf zf af pf cf    (均为置位)

    eflags 0x00000046: id vip vif ac vm rf nt IOPL=0 of df if tf sf ZF af PF cf (ZF,PF置位)

    0x00000002是标志寄存器的实际数值,后面的zf,sf等为标志位,小写时标志位未置位,大写为已置位。

    d.在DOS中运行

    在以后的代码中会出现程序总字节数超过512字节的情况,那么直接运行就会崩溃,所以得在DOS系统中运行,并代码需改成

    org	0100h
    

    首先安装DOSBOX,可以在64位机器上运行。

    打开dos,输入mount d d:MyDos,执行d:,然后运行程序,输入boot.com,结果如下:

    一个码农的日常 

    源码及软盘映像

  • 相关阅读:
    Nubiers to follow
    pp to write
    Reading source code
    build opencv with python support
    add monitor resolution
    Install cv2.so for Anaconda
    axios 上传下载显示进度
    vant 上传图片 图片回显 是base64
    多个时间段 合并
    热部署
  • 原文地址:https://www.cnblogs.com/joey-hua/p/5336675.html
Copyright © 2020-2023  润新知