.text
.code16 #必须有,而且是code16
.global _start
_start:
jmp LABEL_BEGIN #ld -Ttext 0x7c00, 不要jmp $LABEL_BEGIN
#BOOTSEG = 0x07C0
#jmpl $BOOTSEG, $LABEL_BEGIN #ld -Ttext 0x0
LABEL_BEGIN:
movw %cs,%ax
movw %ax,%ds
movw %ax,%es
movw %ax,%ss
#movw $0x100,%sp #有和用意?为了兼容com
# 初始化 32 位代码段描述符
xorl %eax,%eax #code16为何可以操作32为的寄存器? 16位指的是寻址,并不是不能使用32位寄存器. 如果改为.code32,为何编译成xor %ax,%ax了呢?
movw %cs,%ax
shll $4,%eax
addl $LABEL_SEG_CODE32, %eax
movw %ax, LABEL_DESC_CODE32 + 2
shrl $16,%eax
movb %al, LABEL_DESC_CODE32 + 4
movb %ah, LABEL_DESC_CODE32 + 7
xorl %eax,%eax
movw %ds,%ax
shll $4,%eax
addl $LABEL_GDT, %eax
movl %eax, GdtPtr + 2
#; 加载 GDTR
lgdt GdtPtr
cli
# 打开地址线A20
inb $0x92,%al
orb $0b00000010,%al
outb %al, $0x92
# 准备切换到保护模式
#movl $cr0, %eax
#orl $1,%eax
#movl %eax, $cr0
movw $1, %ax # protected mode (PE) bit
lmsw %ax # This is it!
#66ea000000000800 jmp far 0008:00000000
.byte 0x66, 0xea # prefix + jmpi-opcode
.long 0
.word 8 #.word $SelectorCode32,不合法
#ljmp $8, $0x0 #ea00000800, jmp far 0008:0000 #ljmp $SelectorCode32, $0x,不合法
.code32 #必须有,而且是code32
#.text
LABEL_SEG_CODE32:
movw $SelectorVideo, %ax
movw %ax,%gs # 视频段选择子(目的)
movl $((80 * 11 + 79) * 2), %edi # 屏幕第 11 行, 第 79 列。
movb $0xC,%ah # 0000: 黑底 1100: 红字
movb $'P', %al
movw %ax, %gs:(%edi) #括号必须
jmp .
SegCode32Len = . - LABEL_SEG_CODE32
SelectorCode32 = LABEL_DESC_CODE32 - LABEL_GDT
SelectorVideo = LABEL_DESC_VIDEO - LABEL_GDT
#.align 16
LABEL_GDT:
.byte 0
.byte 0
.byte 0
.byte 0
.byte 0
.byte 0
.byte 0
.byte 0
LABEL_DESC_CODE32:
.byte 0x14
.byte 0
.byte 0
.byte 0
.byte 0
.byte 0x98
.byte 0x40
.byte 0
LABEL_DESC_VIDEO:
.byte 0xff
.byte 0xff
.byte 0
.byte 0x80
.byte 0x0b
.byte 0x92
.byte 0
.byte 0
GdtLen = . - LABEL_GDT
GdtPtr:
.word GdtLen - 1
.long 0
#编译
#as -o a.bin attpmTest1.S 或者 gcc -c -o a.bin attpmTest1.S
#ld -Ttext 0x7c00 --oformat binary a.bin -o bootsect //-Ttext 0x7c00加载地址,很关键, 或者 BOOTSEG = 0x07C0 jmpl $BOOTSEG, $LABEL_BEGIN
#dd if=bootsect of=a.img bs=512 count=1 conv=notrunc
#debug nasm版本的,把gdt的值初始化, 不知如何像nasm那样定义宏,宏的使用如下:
/*
.macro Descriptor p1,p2,p3
.word \p2 & 0xFFFF # 段界限1, 前面必须加反斜线,十六进制必须是0x的,不能0FFFFh
.word \p1 & 0xFFFF # 段基址1
.byte (\p1 >> 16) & 0xFF # 段基址2
.word ((\p2 >> 8) & 0xF00) | (\p3 & 0xF0FF) # 属性1 + 段界限2 + 属性2
.byte (\p1 >> 24) & 0xFF # 段基址3
.endm
DA_32 = 0x4000 # 32 位段
DA_DRW = 0x92 # 存在的可读写数据段属性值
DA_C = 0x98 # 存在的只执行代码段属性值
LABEL_GDT: Descriptor 0, 0, 0 # 空描述符,逗号也可用空格,常数前不用加$
LABEL_DESC_CODE32: Descriptor 0, (SegCode32Len - 1), (DA_C + DA_32) # 非一致代码段
LABEL_DESC_VIDEO: Descriptor 0xB8000, 0xffff, DA_DRW # 显存首地址
*/
#取相对地址时要使用$, 常数要使用$, 比如: movw $SelectorVideo, %ax; addl $LABEL_SEG_CODE32, %eax; movl $((80 * 11 + 79) * 2), %edi
#当前相对地址为.,而非$, 比如:GdtLen = . - LABEL_GDT
#jmp dword SelectorCode32:0, 改为写字节码的形式, 为何为8?指向第二个描述符
#LABEL_SEG_CODE32中的.code32不可少。
#nasm注释为;,而att为#
#反汇编:objdump -D -b binary -m i8086 -M att
#objdump -b binary -s ,现实16进制数据,与hexdump 、xxd对比
#file命令