bootsect.S框架基础级分析

    xiaoxiao2021-03-25  39

    本篇内容:

          8086处理器执行指令原理      本程序相关as86汇编基础      bootsect.S分析 =============================================== 1   8086处理器执行指令过程  1.0 相关概念:    >内存单元的物理地址:     所有内存单元构成的存储空间是一个一维的线性空间,每一个单元都有一个唯一的地址即单元的物理地址。    >CPU(8086)内部形成物理地址的方式:      公式:物理地址=段地址 X 16 + 偏移地址      原理: CPU相关部件提供两个16位的地址:段地址和偏移地址,地址加法器将          两个16位地址合成一个20位的物理地址;物理地址将被送上地址总线到达存储器;      地址加法器工作流程如图:          >CS:IP     CS: 代码段寄存器:存放段地址     IP: 指令指针寄存器:存放偏移地址     设任意时刻,CS中的内容为M,IP中的地址为N,8086CPU将从内存M*16+N单元开始,     读取一条指令并执行。  1.1 过程:      <1> CPU从CS:IP指向的内存单元读取指令,读取的指令被送入指令缓冲器;      <2> IP=IP+所读指令的长度,从而指向下一条指令;      <3>执行指令,转到步骤<1>重复这个过程。        2  本程序相关的as86汇编基础   2.0 as86概念     as86是8086..80386处理器下的汇编程序,它所采用的语法与Intel/MS采取的语法类似,而不同于广泛运用于UNIX下的汇编语法(译注,gas中的语法,AT&T汇编)    2.1 本程序部分指令/语法/基础器:        格式 ".xxx" 是伪操作符,具体作用与xxx有关      例如:.txt 指定正文段开始位置         .data 指定数据段开始位置         .bss 指定未初始化数据段开始位置         .org 定义当前汇编的位置,执行结果:将把当前的位置计数器值调为该伪操作符语句上给出的值      格式 "AAA" 标识符,功能之一:可作常量      例如: AAA = 123            格式 "yyy:" 标号, 标号是"标识符+冒号"      例如:.globl 作用为定义随后的标号是外部的或是全局的,并且即使不适用也强制引入(在引入时,标号无需带":")。             .globl yyy begtext zzz            其它时候需要带冒号":"         例如:.txt               begtext:                       数据格式:         .ascii 写到输出的ASCII字符串(Ascii string copied to output.)         .asciz 尾部带有一字节的nul(Ascii string copied to output with trailing nul byte.)         .byte/ FCB/ DATA1/ DB 一字节的对象列表         .word/ FDB/ DATA2/ DW 两字节的对象列表         .LONG/ DATA4/ DD 四字节的对象列表         部分指令:         jmpi 段间跳转         例如 jmpi go, BOOTSEG  !即CS = BOOTSEG, IP = go  (标号go是偏移地址)         int 中断调用         int 0x10  !使用BIOS功能19子功能1,作用显示一字符串到屏幕指定位置         寄存器:         8086寄存器列表如下:                   ax bx cx dx 16位寄存器: 通用寄存器/数据寄存器           ah ax的高8位,al ax的低8位   ah&al = ax         bp (base pointer)基址指针寄存器         sp (stack pointer) 堆栈指针寄存器         cs (Code Segment)段寄存器         ds (Data Segment)数据段寄存器         es (Extra Segment)附加段寄存器         ss (Stack Segment)堆栈段寄存器                 显示一行字符串可能用到的寄存器:          cx,dx,bx,ax :用于指定字符串的字符串长度/显示位置/字符属性/光标位置         bp :指定要显示的字符串                 3 bootsect.S分析   !boot.s/bootsect.s 是磁盘引导程序,驻留在第一个扇区(引导扇区,0磁道 , 0磁头 第一个扇区)。   !在PC机加电ROM BIOS 加电自检后,ROM BIOS 会将boot.s 或者bootsect.s 加载到0x7c00开始处,并且开始运行。 !感叹号用于注释 !此代码段功能:用0x07替换字符串msg的第18个字符,然后在屏幕指定位置显示。 !为什么把操作系统的引导程序加载到0x7c00处: !BIOS就是将MBR读入0x7C00地址,然后进行后续的引导的。 !操作系统或是bootloader开发者必须假设 他们的汇编代码被加载并从0x7C00处开始执行        .globl begtext,begdata,begdata,begbss,endtext,enddata,endbss .text !正文段 begtext: !在正文段定义一个标号begtext .data !数据段 begdata: !在数据段定义一个标号begdata .bss !未初始化数据段 begbss: !在未初始化数据段定义一个标号begbss .text  !正文段 BOOTSEG = 0x7c0 !BIOS加载原始段地址,根据以上公式推算, !要跳到物理地址0x7c00, CS 须是:0x7c0 (理由:0x07c00 + 0x0000 = 0x07c00) entry start    !告知链接程序,程序从start标号处开始执行。 boot/bootsect.S与boot/setup.s可以省略 !因为我们并不希望在生成的纯二进制执行文件包含任何符号信息 start:  jmpi go,BOOTSEG !跳转到CS=BOOTSEG,IP=go处执行,其实就是go处 go: mov ax,cs  !初始化ds,es ,设为cs便于对程序中的数据进行寻址   mov ds,ax   mov es,ax   mov [msg1+17],ah  !替换字符   mov cx, #20 !显示字符总数   mov dx, #0x1004 !显示位置:第17行第5列   mov bx, #0x000c !显示字符属性:红色   mov bp, #msg !指向要显示的字符串(中断调用要求,个人猜测:0x10中断会判断bp是否为空,bp实际就是字符串首地址)   mov ax, #0x1301 !跳转光标到某处   int 0x10 !BIOS调用字符串显示中断 loop0: jmp loop0 !死循环,不退出程序 msg1: .ascii "Loading system ..." !18个字符       .byte 13,10  !再补充两个字符:一个回车一个换行(ASCII)       .ascii "Marry Chritmas"       .byte 13,10 .org 510   !定义当前的位置计数器为510    .word 0xAA55   !再写两个字节,正好512 bytes(一个扇区的大小) .text    !表示代码段的结束位置 endtext: .data   !表示数据段的结束位置 enddata: .bss      !表示未初始化数据段的结束位置 endbss:                  附图:window 10和RedHat Enterprise Linux 5运行bochs成功的图片 windows linux: 我在bochs配置遇到不少问题(Linux下),可能会找时间分享。

    参考与引用:

          《Linux内核完全剖析-基于0.12内核》--- 赵炯

    博客:

    "as86汇编语言" --- AstrayLinux

    "CPU如何执行指令(CS/IP)" --- zhliao

    转载请注明原文地址: https://ju.6miu.com/read-300036.html

    最新回复(0)