当裸机之下没有org 0x7c00之后

来源:互联网 发布:蚁族的奋斗 知乎 编辑:程序博客网 时间:2024/06/05 23:40

this is my first blog !!!


测试系统:Ubuntu

汇编器:Nasm

虚拟机:virtualbox


当没有使用保护模式下实现打印‘AB’这两个字符在屏幕的代码如下,这很简单

代码在执行的时候,CS=0,IP=0X7C00,标号的偏移量从0X7C00计起

org 0x7c00
start:
    mov ax,cs
    mov ds,ax
    mov es,ax
    
    mov ax,0xb800
    mov gs,ax
    mov word [gs:0],0x0741   ; 打印‘A’
    
    mov word [gs:2],0x0c42   ; 打印‘B’
    
    jmp $
    
times 510-($-$$) db 0
dw 0xaa55


接着,我们时入保护模式:在实模式下只打印‘A’,然后到保护模式下打印‘B’


org 0x7c00
[BITS 16]
start:
    mov ax,cs
    mov ds,ax
    mov es,ax
    
    mov ax,0xb800
    mov gs,ax
    mov word [gs:0],0x0741
    
    cli
    lgdt [ gdtr ]
    mov eax,cr0
    or al,1
    mov cr0,eax
    jmp codesel:protectedmode
    
[BITS 32]
protectedmode:

    mov ax,videosel
    mov gs,ax
    mov word [gs:2],0x0c42
    
    jmp $
    
[BITS 16]
gdtr:
    dw gdt_end - gdt - 1
    dd gdt
    
gdt:
    nullsel    equ $-gdt
    dd 0,0
    
    codesel    equ $-gdt
    dw 0xffff
    dw 0
    db 0
    dw 0xcf9a
    db 0
    
    datasel    equ $-gdt
    dw 0xffff
    dw 0
    db 0
    dw 0xcf92
    db 0
    
    videosel    equ $-gdt
    dw 3999
    dw 0x8000
    db 0xb
    dw 0x0092
    db 0
    
gdt_end:
times 510-($-$$) db 0
dw 0xaa55


好了,最后的一个版本里头,我把org 0x7c00这条指令干掉,因为有某个特殊情况下,我们不能使用它

然后麻烦的问题就来了,所有的标号偏移量从0计起,解决的方法大致就是把“一部分”的加上0X7C00,

但有“小部分”的标号不能加0X7C00!为了防止太多的标号引起BUG,我把很多标号干掉了,用$来代替。。。


OFFSET equ 0x7c00

[BITS 16]
real_mode:
 
     ; 把CS和IP的值交换过来
     ; 并把IP的值指定第4行"mov ax,cs"这条指令的起始位置
     db 0xea
     dw $+4
     dw 0x7c0
 
    ; OK,此时CS的值改变了,所以设置其他段寄存器
     mov ax,cs
     mov ds,ax
     mov es,ax
     
     ; 在屏幕上打印一个灰色的字符‘A’
     mov ax,0xb800
     mov gs,ax
     mov word [gs:0],0x0741

    ; 加载gdtr这个寄存器的值,并启动保护模式
    cli
    lgdt [ gdtr ] ;为什么这里没有加上OFFSET? 因为此时DS=0x7c0
    mov eax,cr0
    or al,0x01
    mov cr0,eax
 
     ; 好了,现在跳转到protected_mode
    jmp 8 : $+5+OFFSET
 
[BITS 32]
;protected_mode:
    ; 在屏幕上打印一个绿色的字符‘B’,位于之前打印的字符‘A’之后
    mov ax,24
    mov gs,ax
    mov word [gs:2],0x0c42
    
    dw 0xfeeb
    
[BITS 16]
gdtr:
    dw 31    ; 总共有4个描述符,32=4*8-1=32-1
    dd $+4+OFFSET

    ; 空的描述符,虽然没用,但不能没有
    dd 0,0
 
     ; 代码段描述符
    dw 0x0ffff ; 4G
    dw 0x0
    db 0x00
    dw 0xcf9a
    db 0x00
 
     ; 数据段描述符
    dw 0x0ffff ; 4G
    dw 0x0
    db 0x00
    dw 0xcf92
    db 0x00

    ; 显示屏的描述符
    dw 3999 ; 80 cols * 25 * rows * 2bytes - 1
    dw 0x8000
    db 0x0b
    dw 0x0092
    db 0x00
 
times 510-($-$$) db 0
dw 0xAA55


以上的三个版本的代码都可以正常地运行 ,我已经测试过了.....

原创粉丝点击