最近在写一个x86下的boot loader,由于是基于legacy bios的,所以要使用real mode编程,编写汇编文件,用as编译生成目标文件,再用ld链接器手动链接,把代码段和数据段指定到合适的位置。
而这个“合适的位置”,引发了我的思考。
代码如下供参考。
.code16
.data
.global _start
BIOS_COPY_ADDR = 0x7c0
_start:
ljmp $BIOS_COPY_ADDR, $next
#jmp next
next:
loop0:
jmp loop0
msg:
.string "In boot-sect.s message"
.byte 0x0d, 0x0a, 0x00
.org 510
.word 0xaa55
这份代码如果编译的时候,把代码段和数据段指定到了0x1234,结果,用objdump来看一下,效果如下。
boot-sect.bin: file format binary
Disassembly of section .data:
0000000000000000 <.data>:
0: ea (bad)
1: 39 12 cmp %edx,(%rdx)
3: c0 07 eb rolb $0xeb,(%rdi)
6: fe 49 6e decb 0x6e(%rcx)
9: 20 62 6f and %ah,0x6f(%rdx)
c: 6f outsl %ds:(%rsi),(%dx)
d: 74 2d je 0x3c
f: 73 65 jae 0x76
11: 63 74 2e 73 movslq 0x73(%rsi,%rbp,1),%esi
15: 20 6d 65 and %ch,0x65(%rbp)
18: 73 73 jae 0x8d
1a: 61 (bad)
1b: 67 65 00 0d 0a 00 00 add %cl,%gs:0xa(%eip) # 0x2d
22: 00
...
1fb: 00 00 add %al,(%rax)
1fd: 00 55 aa add %dl,-0x56(%rbp)
第一行没有显示出来是因为ljmp这个指令在ia32下是不支持的,所以解析错误,我们看下机器码即可,实际上这个指令的机器码是 ea 39 12 c0 07,为什么是39,是因为第一条指令正好占用4个字节,所以next的标号就是1234+5=1239,这就是指定代码段基址的结果。