OS专题-了解内存组成规则

OS专题-了解内存组成规则

前面我们其实已经接触到了CPU如何从内存中获取或执行指令,以及如何加载MBR扇区到内存中并按照顺序一步一步执行。但是我们的引导扇区的代码存放在了内存的哪个位置呢?

我们可以通过推到得知它的存放位置肯定不在0x0。因为在此之前BIOS已经将ISR写入到内存中了。并且这些ISR在计算机运行期间仍然存在(因为我们仍要用到它,所以它不会被覆盖),而且之前我们已经讲到,中断向量位于内存的起始处,如果BIOS真的将我们的代码加载到那里,就会覆盖中断向量,这样的话,当下一次触发中断时计算机就会崩溃。

通过一些资料了解到,BIOS总是将MBR扇区加载到地址0x7c00,在那里它肯定不会被中断向量占用。上述图中是刚刚加载引导扇区时计算机的典型低内存布局的示例。可以看得出,有一部分内存已经被其他程序(例如:ISR、计时器中断和磁盘设备)占用了,为了不发生内存污染,导致计算机崩溃,我们必须控制对内存的写入位置。

利用标记探究内存的可控范围

为了探究内存,我们编写一个汇编程序,为一个字符保留一个字节的数据,然后我们将尝试在屏幕上打印出该字符。要做到这一点,我们需要确定它的绝对内存地址,这样我们就可以将它加载到AL中并让BIOS打印它。以下是程序样例:

mov ah, 0x0e ; TTY模式

; 第一次尝试 打印数字1 打印标签
mov al, "1"
int 0x10
mov al, the_secret
int 0x10

; 第二次尝试 打印数字2 打印标签指向的字符
mov al, "2"
int 0x10
mov al, [the_secret]
int 0x10

; 第三次尝试 打印数字3 对标签地址进行运算,打印运算后地址指向的字符
mov al, "3"
int 0x10
mov bx, the_secret
add bx, 0x7c00
mov al, [bx]
int 0x10

; 第四次尝试 打印数字4 打印地址0x7c2d指向的字符
mov al, "4"
int 0x10
mov al, [0x7c2d]
int 0x10

jmp $ ; 无线循环

the_secret:
    ; ASCII 的字符
    db "X"

; 填充其他位的值为00
times 510-($-$$) db 0
; 魔数
dw 0xaa55

通过运行上述例子,可以看得出,前两次的尝试都无法得到正确的标记X。只有第三次和第四次是成功的。这说明我们在获取数据时可以直接用内存地址来获取,也可以用标签来进行一些运算得到地址来获取。

当然直接使用标签是不准确的,一旦修改了代码,偏移量就要重新计算,所以一般我们都在代码顶部使用[org 0x7c00]来纠正标签引用。

[org 0x7c00] ; 纠正加载位置
mov ah, 0x0e ; TTY模式

; 第一次尝试 打印数字1 打印标签
mov al, "1"
int 0x10
mov al, the_secret
int 0x10

; 第二次尝试 打印数字2 打印标签指向的字符
mov al, "2"
int 0x10
mov al, [the_secret]
int 0x10

; 第三次尝试 打印数字3 对标签地址进行运算,打印运算后地址指向的字符
mov al, "3"
int 0x10
mov bx, the_secret
add bx, 0x7c00
mov al, [bx]
int 0x10

; 第四次尝试 打印数字4 打印地址0x7c2d指向的字符
mov al, "4"
int 0x10
mov al, [0x7c2d]
int 0x10


jmp $ ; 无线循环

the_secret:
    ; ASCII 的字符
    db "X"

; 填充其他位的值为00
times 510-($-$$) db 0
; 魔数
dw 0xaa55

这样修改后,第二个打印就成功了,标签代表的就是内存地址,而不是偏移地址了。


OS专题-了解内存组成规则
https://blog.cikaros.top/doc/47db40c6.html
作者
Cikaros
发布于
2022年9月22日
许可协议