![]() |
#2
zklhp2012-04-11 08:42
|

;一个非常简单的启动程序,在屏幕中央打印一行代码
[BITS 16] ;告诉编译器是在16下编译
org 07c00h ;org,明确告诉编译器程序的开始段地址是7c00h
;而不是原来的0000
;int汇编指令 后面跟上你要呼叫的中断号 eg:int 10h
jmp main
gdt_table_start:
gdt_null:
dd 0h
dd 0h ;inter规定段描述表的第一个表项必须为零
gdt_data_addr equ $-gdt_table_start ;数据段
gdt_data:
dw 07FFH ;段界限
dw 0h ;段基地址0-18位
db 0h ;段基地址19-23位
db 10010010b ;段描述符的第六个字节属性(数据段)
db 11000000b ;段描述符的第七个字节属性
db 0 ;段描述符的最后一个字节也就是段基地址
gdt_video_addr equ $-gdt_table_start ;描述显存地址空间的段描述符
gdt_video:
dw 0ffh ;显存段界限大小1M
dw 8000h;段基地址0-18
db 0bh;
db 10010010b;
db 11000000b;
db 0;
gdt_code_addr equ $-gdt_table_start ;代码段
gdt_code:
dw 07ffh ;段界限
dw 1h ;段基地址0-18位
db 80h ;段基地址19-23位
db 10011010b ;段描述符的第六个字节属校(代码段)
db 11000000b ;段描述符的第七个字节属性
db 0 ;段基地址的第二部分
gdt_table_end: ;表示段描述符的结束
gdtr_addr:
dw gdt_table_end-gdt_table_start-1 ;段描述表长度
dd gdt_table_start ;段描述符表基地址
lgdt [gdtr_addr] ;让CPU读取gdtr_addr所指向内存的内容保存到GDT寄存器中
;A20地址线问题。必须开启,这是切换到保护模式的必备条件
main:
enable_a20:
in al,92h ;往92号端口写,以开启A20地址线
or al,00000010b ;为了实现,就拿32位来和这个数据进行或
out 92h,al ;从92号端口读
cli ;在转入保护模式之前,要废除中断向量表,进入保护模式后,再有系统创建该表
;怎么进入保护模式呢?怎么设置分页或者分段管理模式呢?仅需设置CR0寄存器
;设置cr0寄存器的第一位为1
mov eax,cr0 ;将cr0的内容拷贝进32位的寄存器
or eax,1 ;
mov cr0,eax ;万事俱备只欠东风,下一步就该跳转到保护模式了
;跳转
jmp gdt_code_addr:0 ;有三种jmp,这里选择了远跳转
;接下来是在保护模式下编程,注意不再是16位,而是32位了
[BITS 32] ; 告诉编译器是在32位下编译
data_32:
db "hello word"
code_32:
mov ax,gdt_data_addr
mov ds,ax
mov ax,gdt_video_addr
mov gs,ax
mov cx,11
mov edi,(80*10+12)*2 ;在平幕中央显示
mov bx,0
mov ah,0ch
s: mov al,[ds:bx]
mov [gs:edi],al
mov [gs:edi+1],ah
inc bx
add edi,2
loop s
jmp $
times 510-($-$$) db 0
dw 0aa55h
mov ax,cs
mov es,ax
mov bp,msgstr ;es:bp 指向的内容就是我们要显示的字符串地址了
mov cx,12 ;字符串长度
mov dh,12 ;行号
mov dl,36 ;列号
mov bh,0 ;页号,页数
mov al,1 ;显示方式 字符串
mov bl,0ch ;字体的属性,颜色背景之类
mov ah,13h ;明确调用13h子程序
msgstr: db "hello my os!"
int 10h ;呼叫BIOS的中断,以实现上面的工能
times 510-($-$$) db 0 ;重复N次,每次填充值为零
dw 55aah ;512K的最后两字
jmp $ ;不让程序结束,不断跳转到当前位置以形成死循环,如果程序一结束,那么就达不到目的了
[BITS 16] ;告诉编译器是在16下编译
org 07c00h ;org,明确告诉编译器程序的开始段地址是7c00h
;而不是原来的0000
;int汇编指令 后面跟上你要呼叫的中断号 eg:int 10h
jmp main
gdt_table_start:
gdt_null:
dd 0h
dd 0h ;inter规定段描述表的第一个表项必须为零
gdt_data_addr equ $-gdt_table_start ;数据段
gdt_data:
dw 07FFH ;段界限
dw 0h ;段基地址0-18位
db 0h ;段基地址19-23位
db 10010010b ;段描述符的第六个字节属性(数据段)
db 11000000b ;段描述符的第七个字节属性
db 0 ;段描述符的最后一个字节也就是段基地址
gdt_video_addr equ $-gdt_table_start ;描述显存地址空间的段描述符
gdt_video:
dw 0ffh ;显存段界限大小1M
dw 8000h;段基地址0-18
db 0bh;
db 10010010b;
db 11000000b;
db 0;
gdt_code_addr equ $-gdt_table_start ;代码段
gdt_code:
dw 07ffh ;段界限
dw 1h ;段基地址0-18位
db 80h ;段基地址19-23位
db 10011010b ;段描述符的第六个字节属校(代码段)
db 11000000b ;段描述符的第七个字节属性
db 0 ;段基地址的第二部分
gdt_table_end: ;表示段描述符的结束
gdtr_addr:
dw gdt_table_end-gdt_table_start-1 ;段描述表长度
dd gdt_table_start ;段描述符表基地址
lgdt [gdtr_addr] ;让CPU读取gdtr_addr所指向内存的内容保存到GDT寄存器中
;A20地址线问题。必须开启,这是切换到保护模式的必备条件
main:
enable_a20:
in al,92h ;往92号端口写,以开启A20地址线
or al,00000010b ;为了实现,就拿32位来和这个数据进行或
out 92h,al ;从92号端口读
cli ;在转入保护模式之前,要废除中断向量表,进入保护模式后,再有系统创建该表
;怎么进入保护模式呢?怎么设置分页或者分段管理模式呢?仅需设置CR0寄存器
;设置cr0寄存器的第一位为1
mov eax,cr0 ;将cr0的内容拷贝进32位的寄存器
or eax,1 ;
mov cr0,eax ;万事俱备只欠东风,下一步就该跳转到保护模式了
;跳转
jmp gdt_code_addr:0 ;有三种jmp,这里选择了远跳转
;接下来是在保护模式下编程,注意不再是16位,而是32位了
[BITS 32] ; 告诉编译器是在32位下编译
data_32:
db "hello word"
code_32:
mov ax,gdt_data_addr
mov ds,ax
mov ax,gdt_video_addr
mov gs,ax
mov cx,11
mov edi,(80*10+12)*2 ;在平幕中央显示
mov bx,0
mov ah,0ch
s: mov al,[ds:bx]
mov [gs:edi],al
mov [gs:edi+1],ah
inc bx
add edi,2
loop s
jmp $
times 510-($-$$) db 0
dw 0aa55h
mov ax,cs
mov es,ax
mov bp,msgstr ;es:bp 指向的内容就是我们要显示的字符串地址了
mov cx,12 ;字符串长度
mov dh,12 ;行号
mov dl,36 ;列号
mov bh,0 ;页号,页数
mov al,1 ;显示方式 字符串
mov bl,0ch ;字体的属性,颜色背景之类
mov ah,13h ;明确调用13h子程序
msgstr: db "hello my os!"
int 10h ;呼叫BIOS的中断,以实现上面的工能
times 510-($-$$) db 0 ;重复N次,每次填充值为零
dw 55aah ;512K的最后两字
jmp $ ;不让程序结束,不断跳转到当前位置以形成死循环,如果程序一结束,那么就达不到目的了
错误是如下提示
[shi@localhost c_programming]$ nasm boot.asm -o boot.bin
boot.asm:32: error: symbol `gdt_table_end' undefined
boot.asm:74: error: symbol `msgstr' undefined
boot.asm:79: error: TIMES value -17 is negative
[shi@localhost c_programming]$
[shi@localhost c_programming]$
[shi@localhost c_programming]$
但是我搞不懂这个怎么会是这样, gdt_table_end 怎么就会没定义呢?求求大神指点一下,万分感谢!