⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 新建 文本文档.txt

📁 这个程序主要是实现汇编语言的自动启动电脑的程序
💻 TXT
字号:
 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, 16 ; cx = 串长度

 mov ax, 01301h ; ah = 13, al = 01h

 mov bx, 000ch ; 页号为0(bh = 0) 黑底红字(bl = 0Ch,高亮)

 mov dl, 0

 int 10h ; 10h 号中断

 ret

BootMessage: db "Hello, OS world!"

times 510-($-$$) db 0 ; 填充剩下的空间,使生成的二进制代码恰好为

; 512字节

dw 0xaa55 ; 结束标志




其实程序的主体框架只有5行(从第2行到第6行),其中调用了一个显示字符串的子程序。程序的第2、3、4行是3个mov指令,使ds和es两个段寄存器指向与cs相同的段,以便在以后进行数据操作的时候能定位到正确的位置。第5行调用子程序显示字符串,然后jmp $让程序无限循环下去。

可能大部分人开始学汇编时用的都是MASM,其实NASM的格式跟MASM总体上是差不多的,在这段程序中,值得说明的地方有以下几点:

(1)在NASM中,任何不被方括号[]括起来的标签或变量名都被认为是地址,访问标签中的内容必须使用[]。所以,

mov ax, BootMessage

将会把“Hello, OS world!”这个字符串的首地址传给寄存器ax。又比如,如果有:

foo dw 1

则mov ax, foo将把foo的地址传给ax,而mov bx, [foo]将把bx的值赋为1。

实际上,在NASM中,变量和标签是一样的,也就是说:

foo dw 1 ≡ foo: dw 1

而且你会发现,Offset这个关键字在NASM也是不需要的。因为不加方括号时表示的就是Offset。

笔者认为这是NASM的一大优点,要地址就不加方括号,也不必额外地用什么Offset,想要访问地址中的内容就必须加上方括号。代码规则非常鲜明,一目了然。

(2)关于$和$$。$表示当前行被汇编后的地址。这好像不太好理解,不要紧,我们把刚刚生成的二进制代码文件反汇编来看看:

ndisasmw -o 0x7c00 boot.bin >> disboot.asm

打开disboot.asm,你会发现这样一行:

00007C09  EBFE              jmp short 0x7c09

明白了吧,$在这里的意思原来就是0x7c09。

那么$$表示什么呢?它表示一个节(section)的开始处被汇编后的地址。在这里,我们的程序只有1个节,所以,$$实际上就表示程序被编译后的开始地址,也就是0x7c00。



注意:这里的section属于NASM规范的一部分,表示一段代码,关于它和$$更详细的注解请参考NASM联机技术文档。

 

在写程序的过程中,$-$$可能会被经常用到,它表示本行距离程序开始处的相对距离。现在,你应该明白510-($-$$)表示什么意思了吧?times 510-($-$$) db 0表示将0这个字节重复510-($-$$)遍,也就是在剩下的空间中不停地填充0,直到程序有510B为止。这样,加上结束标志0xAA55占用的2B,恰好是512B。






























org 0x07c00; 起始地址是0000:7c00  
    jmp short begin_boot ; 跳过其它的数据,跳转到引导程序的开始处  
    bootmesg db "Our OS boot sector loading ......"  
    pm_mesg db "tching to protected mode ...."  
    dw 512 ; 每一扇区的字节数  
    db 1 ; 每一簇的扇区数  
    dw 1 ; 保留的扇区号  
    db 2  
    dw 0x00e0  
    dw 0x0b40  
    db 0x0f0  
    dw 9  
 
 
  
 作者: 小毛315   2006-5-18 12:58   回复此发言    
 
--------------------------------------------------------------------------------
 
6 【转】自己动手编写操作系统  
     dw 18  
    dw 2 ; 读写扇区号  
    dw 0 ; 隐藏扇区号  
    print_mesg :  
    mov ah,0x13 ; 使用中断10h的功能13,在屏幕上写一个字符串  
    mov al,0x00 ; 决定调用函数后光标所处的位置  
    mov bx,0x0007 ; 设置显示属性  
    mov cx,0x20 ; 在此字符串长度为32  
    mov dx,0x0000 ; 光标的起始行和列  
    int 0x10 ; 调用BIOS的中断10h  
    ret ; 返回调用程序  
    get_key :  
    mov ah,0x00  
    int 0x16 ; Get_key使用中断16h的功能0,读取下一个字符  
    ret  
    clrscr :  
    mov ax,0x0600 ; 使用中断10h的功能6,实现卷屏,如果al=0则清屏  
    mov cx,0x0000 ; 清屏  
    mov dx,0x174f ; 卷屏至23,79  
    mov bh,0 ; 使用颜色0来填充  
    int 0x10 ; 调用10h中断  
    ret  
    begin_boot :  
    call clrscr ; 先清屏  
    mov bp,bootmesg ; 提供串地址  
    call print_mesg ; 输出信息  
    call get_key ; 等待用户按下任一键  
    bits 16  
    call clrscr ; 清屏  
    mov ax,0xb800 ; 使gs指向显示内存  
    mov gs,ax ; 在实模式下显示一个棕色的A  
    mov word [gs:0],0x641 ; 显示  
    call get_key ; 调用Get_key等待用户按下任一键  
    mov bp,pm_mesg ; 设置串指针  
    call print_mesg ; 调用print_mesg子程序  
    call get_key ; 等待按键  
    call clrscr ; 清屏  
    cli ; 关中断  
    lgdt[gdtr] ; 加载GDT  
    mov eax,cr0  
    or al,0x01 ; 设置保护模式位  
    mov cr0,eax ; 将更改后的字送至控制寄存器中  
    jmp codesel:go_pm  
    bits 32  
    go_pm :  
    mov ax,datasel  
    mov ds,ax ; 初始化ds和es,使其指向数据段  
    mov es,ax  
    mov ax,videosel ; 初始化gs,使其指向显示内存  
    mov gs,ax  
    mov word [gs:0],0x741 ; 在保护模式下显示一个白色的字符A  
    spin : jmp spin ; 循环  
    bits 16  
    gdtr :  
    dw gdt_end-gdt-1 ; gdt的长度  
    dd gdt ; gdt的物理地址  
    gdt  
    nullsel equ $-gdt ; $指向当前位置,所以nullsel = 0h  
    gdt0 ; 空描述符  
    dd 0  
    dd 0 ; 所有的段描述符都是64位的  
    codesel equ $-gdt ; 这是8h也就是gdt的第二个描述符  
    code_gdt  
    dw 0x0ffff ; 段描述符的界限是4Gb  
    dw 0x0000  
    db 0x00  
    db 0x09a  
    db 0x0cf  
    db 0x00  
    datasel equ $-gdt  
    data_gdt  
    dw 0x0ffff  
    dw 0x0000  
    db 0x00  
    db 0x092  
    db 0x0cf  
    db 0x00  
    videosel equ $-gdt  
    dw 3999  
    dw 0x8000 ; 基址是0xb8000  
    db 0x0b  
    db 0x92  
    db 0x00  
    db 0x00  
    gdt_end  
    times 510-($-$$) db 0  
    dw 0x0aa55  
 
 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -