Lab_1:练习2——使用qemu执行并调试lab1中的软件

 

一、实验内容

为了熟悉使用qemu和gdb进行的调试工作,我们进行如下的小练习:

(一)从CPU加电后执行的第一条指令开始,单步跟踪BIOS的执行。

(二)在初始化位置0x7c00设置实地址断点,测试断点正常。

(三)从0x7c00开始跟踪代码运行,将单步跟踪反汇编得到的代码与bootasm.S和 bootblock.asm进行比较。

(四)自己找一个bootloader或内核中的代码位置,设置断点并进行测试。

二、实验步骤 

补充材料:

我们主要通过硬件模拟器qemu来进行各种实验。在实验的过程中我们可能会遇上各种各样的问题,调试是必要的。qemu支持使用gdb进行的强大而方便的调试。所以用好qemu和gdb是完成各种实验的基本要素

默认的gdb需要进行一些额外的配置才进行qemu的调试任务。qemu和gdb之间使用网络端口1234进行通讯。在打开qemu进行模拟之后,执行gdb并输

target remote :1234

即可连接qemu,此时qemu会进入停止状态,听从gdb的命令

另外,我们可能需要qemu在一开始便进入等待模式,则我们不再使用make qemu开始系统的运行,而使用make debug来完成这项工作。这样qemu便不会在gdb尚未连接的时候擅自运行了。

gdb的地址断点

在gdb命令行中,使用b *[地址]便可以在指定内存地址设置断点,当qemu中的cpu执行到指定地址时,便会将控制权交给gdb。

 

(一)从CPU加电后执行的第一条指令开始,单步跟踪BIOS的执行

1.修改gdbinit文件

首先,在 /moocos/ucore_lab/labcodes_answer/lab1_result/tools  目录下,修改gdbinit文件

进入目录:

cd ./moocos/ucore_lab/labcodes_answer/lab1_result/tools

修改方法为:

输入vim gdbinit

用D删除gdbinit中原有的内容(D为删除整行,x或X为删除单个字符)

将以下内容粘贴入gdbinit中

set architecture i8086
target remote :1234 

 

2.make debug

输入cd ..,退回到./moocos/ucore_lab/labcodes_answer/lab1_result

输入make debug

随后执行make debug,将弹出gdb窗口,如图所示:

在gdb窗口中使用si命令即可单步追踪

(注意:你不必每次输入si,输入一次si后,只要按回车即可执行上次的指令)

在gdb界面下,可通过如下命令来看BIOS的代码

x /2i $pc(显示当前eip处的汇编指令)

 (二)在初始化位置0x7c00设置实地址断点,测试断点正常。

1.修改gdbinit文件

进入目录:

cd ./moocos/ucore_lab/labcodes_answer/lab1_result/tools

修改方法与(一)相同,

修改的内容如下:

target remote :1234     //连接qemu,此时qemu会进入停止状态,听从gdb的命令
set architecture i8086  //设置当前调试的CPU是8086
b *0x7c00   //在0x7c00处设置断点。此地址是bootloader入口点地址,可看boot/bootasm.S的start地址处
c     //continue简称,表示继续执行
x/10i $pc    //显示当前eip处的汇编指令

2.make debug 

输入cd ..,退回到./moocos/ucore_lab/labcodes_answer/lab1_result

输入make debug

(三)从0x7c00开始跟踪代码运行,将单步跟踪反汇编得到的代码与bootasm.S和 bootblock.asm进行比较

 bootasm.S的完整代码为:

 1 #include <asm.h>
 2 
 3 # Start the CPU: switch to 32-bit protected mode, jump into C.
 4 # The BIOS loads this code from the first sector of the hard disk into
 5 # memory at physical address 0x7c00 and starts executing in real mode
 6 # with %cs=0 %ip=7c00.
 7 
 8 .set PROT_MODE_CSEG,        0x8                     # kernel code segment selector
 9 .set PROT_MODE_DSEG,        0x10                    # kernel data segment selector
10 .set CR0_PE_ON,             0x1                     # protected mode enable flag
11 
12 # start address should be 0:7c00, in real mode, the beginning address of the running bootloader
13 .globl start
14 start:
15 .code16                                             # Assemble for 16-bit mode
16     cli                                             # Disable interrupts
17     cld                                             # String operations increment
18 
19     # Set up the important data segment registers (DS, ES, SS).
20     xorw %ax, %ax                                   # Segment number zero
21     movw %ax, %ds                                   # -> Data Segment
22     movw %ax, %es                                   # -> Extra Segment
23     movw %ax, %ss                                   # -> Stack Segment
24 
25     # Enable A20:
26     #  For backwards compatibility with the earliest PCs, physical
27     #  address line 20 is tied low, so that addresses higher than
28     #  1MB wrap around to zero by default. This code undoes this.
29 seta20.1:
30     inb $0x64, %al                                  # Wait for not busy(8042 input buffer empty).
31     testb $0x2, %al
32     jnz seta20.1
33 
34     movb $0xd1, %al                                 # 0xd1 -> port 0x64
35     outb %al, $0x64                                 # 0xd1 means: write data to 8042's P2 port
36 
37 seta20.2:
38     inb $0x64, %al                                  # Wait for not busy(8042 input buffer empty).
39     testb $0x2, %al
40     jnz seta20.2
41 
42     movb $0xdf, %al                                 # 0xdf -> port 0x60
43     outb %al, $0x60                                 # 0xdf = 11011111, means set P2's A20 bit(the 1 bit) to 1
44 
45     # Switch from real to protected mode, using a bootstrap GDT
46     # and segment translation that makes virtual addresses
47     # identical to physical addresses, so that the
48     # effective memory map does not change during the switch.
49     lgdt gdtdesc
50     movl %cr0, %eax
51     orl $CR0_PE_ON, %eax
52     movl %eax, %cr0
53 
54     # Jump to next instruction, but in 32-bit code segment.
55     # Switches processor into 32-bit mode.
56     ljmp $PROT_MODE_CSEG, $protcseg
57 
58 .code32                                             # Assemble for 32-bit mode
59 protcseg:
60     # Set up the protected-mode data segment registers
61     movw $PROT_MODE_DSEG, %ax                       # Our data segment selector
62     movw %ax, %ds                                   # -> DS: Data Segment
63     movw %ax, %es                                   # -> ES: Extra Segment
64     movw %ax, %fs                                   # -> FS
65     movw %ax, %gs                                   # -> GS
66     movw %ax, %ss                                   # -> SS: Stack Segment
67 
68     # Set up the stack pointer and call into C. The stack region is from 0--start(0x7c00)
69     movl $0x0, %ebp
70     movl $start, %esp
71     call bootmain
72 
73     # If bootmain returns (it shouldn't), loop.
74 spin:
75     jmp spin
76 
77 # Bootstrap GDT
78 .p2align 2                                          # force 4 byte alignment
79 gdt:
80     SEG_NULLASM                                     # null seg
81     SEG_ASM(STA_X|STA_R, 0x0, 0xffffffff)           # code seg for bootloader and kernel
82     SEG_ASM(STA_W, 0x0, 0xffffffff)                 # data seg for bootloader and kernel
83 
84 gdtdesc:
85     .word 0x17                                      # sizeof(gdt) - 1
86     .long gdt                                       # address gdt
bootasm.S

 bootblock.asm的完整代码为:

  1 obj/bootblock.o:     file format elf32-i386
  2 
  3 
  4 Disassembly of section .text:
  5 
  6 00007c00 <start>:
  7 
  8 # start address should be 0:7c00, in real mode, the beginning address of the running bootloader
  9 .globl start
 10 start:
 11 .code16                                             # Assemble for 16-bit mode
 12     cli                                             # Disable interrupts
 13     7c00:    fa                       cli    
 14     cld                                             # String operations increment
 15     7c01:    fc                       cld    
 16 
 17     # Set up the important data segment registers (DS, ES, SS).
 18     xorw %ax, %ax                                   # Segment number zero
 19     7c02:    31 c0                    xor    %eax,%eax
 20     movw %ax, %ds                                   # -> Data Segment
 21     7c04:    8e d8                    mov    %eax,%ds
 22     movw %ax, %es                                   # -> Extra Segment
 23     7c06:    8e c0                    mov    %eax,%es
 24     movw %ax, %ss                                   # -> Stack Segment
 25     7c08:    8e d0                    mov    %eax,%ss
 26 
 27 00007c0a <seta20.1>:
 28     # Enable A20:
 29     #  For backwards compatibility with the earliest PCs, physical
 30     #  address line 20 is tied low, so that addresses higher than
 31     #  1MB wrap around to zero by default. This code undoes this.
 32 seta20.1:
 33     inb $0x64, %al                                  # Wait for not busy(8042 input buffer empty).
 34     7c0a:    e4 64                    in     $0x64,%al
 35     testb $0x2, %al
 36     7c0c:    a8 02                    test   $0x2,%al
 37     jnz seta20.1
 38     7c0e:    75 fa                    jne    7c0a <seta20.1>
 39 
 40     movb $0xd1, %al                                 # 0xd1 -> port 0x64
 41     7c10:    b0 d1                    mov    $0xd1,%al
 42     outb %al, $0x64                                 # 0xd1 means: write data to 8042's P2 port
 43     7c12:    e6 64                    out    %al,$0x64
 44 
 45 00007c14 <seta20.2>:
 46 
 47 seta20.2:
 48     inb $0x64, %al                                  # Wait for not busy(8042 input buffer empty).
 49     7c14:    e4 64                    in     $0x64,%al
 50     testb $0x2, %al
 51     7c16:    a8 02                    test   $0x2,%al
 52     jnz seta20.2
 53     7c18:    75 fa                    jne    7c14 <seta20.2>
 54 
 55     movb $0xdf, %al                                 # 0xdf -> port 0x60
 56     7c1a:    b0 df                    mov    $0xdf,%al
 57     outb %al, $0x60                                 # 0xdf = 11011111, means set P2's A20 bit(the 1 bit) to 1
 58     7c1c:    e6 60                    out    %al,$0x60
 59 
 60     # Switch from real to protected mode, using a bootstrap GDT
 61     # and segment translation that makes virtual addresses
 62     # identical to physical addresses, so that the
 63     # effective memory map does not change during the switch.
 64     lgdt gdtdesc
 65     7c1e:    0f 01 16                 lgdtl  (%esi)
 66     7c21:    6c                       insb   (%dx),%es:(%edi)
 67     7c22:    7c 0f                    jl     7c33 <protcseg+0x1>
 68     movl %cr0, %eax
 69     7c24:    20 c0                    and    %al,%al
 70     orl $CR0_PE_ON, %eax
 71     7c26:    66 83 c8 01              or     $0x1,%ax
 72     movl %eax, %cr0
 73     7c2a:    0f 22 c0                 mov    %eax,%cr0
 74 
 75     # Jump to next instruction, but in 32-bit code segment.
 76     # Switches processor into 32-bit mode.
 77     ljmp $PROT_MODE_CSEG, $protcseg
 78     7c2d:    ea 32 7c 08 00 66 b8     ljmp   $0xb866,$0x87c32
 79 
 80 00007c32 <protcseg>:
 81 
 82 .code32                                             # Assemble for 32-bit mode
 83 protcseg:
 84     # Set up the protected-mode data segment registers
 85     movw $PROT_MODE_DSEG, %ax                       # Our data segment selector
 86     7c32:    66 b8 10 00              mov    $0x10,%ax
 87     movw %ax, %ds                                   # -> DS: Data Segment
 88     7c36:    8e d8                    mov    %eax,%ds
 89     movw %ax, %es                                   # -> ES: Extra Segment
 90     7c38:    8e c0                    mov    %eax,%es
 91     movw %ax, %fs                                   # -> FS
 92     7c3a:    8e e0                    mov    %eax,%fs
 93     movw %ax, %gs                                   # -> GS
 94     7c3c:    8e e8                    mov    %eax,%gs
 95     movw %ax, %ss                                   # -> SS: Stack Segment
 96     7c3e:    8e d0                    mov    %eax,%ss
 97 
 98     # Set up the stack pointer and call into C. The stack region is from 0--start(0x7c00)
 99     movl $0x0, %ebp
100     7c40:    bd 00 00 00 00           mov    $0x0,%ebp
101     movl $start, %esp
102     7c45:    bc 00 7c 00 00           mov    $0x7c00,%esp
103     call bootmain
104     7c4a:    e8 b1 00 00 00           call   7d00 <bootmain>
105 
106 00007c4f <spin>:
107 
108     # If bootmain returns (it shouldn't), loop.
109 spin:
110     jmp spin
111     7c4f:    eb fe                    jmp    7c4f <spin>
112     7c51:    8d 76 00                 lea    0x0(%esi),%esi
113 
114 00007c54 <gdt>:
115     ...
116     7c5c:    ff                       (bad)  
117     7c5d:    ff 00                    incl   (%eax)
118     7c5f:    00 00                    add    %al,(%eax)
119     7c61:    9a cf 00 ff ff 00 00     lcall  $0x0,$0xffff00cf
120     7c68:    00 92 cf 00 17 00        add    %dl,0x1700cf(%edx)
121 
122 00007c6c <gdtdesc>:
123     7c6c:    17                       pop    %ss
124     7c6d:    00 54 7c 00              add    %dl,0x0(%esp,%edi,2)
125     ...
126 
127 00007c72 <readseg>:
128 /* *
129  * readseg - read @count bytes at @offset from kernel into virtual address @va,
130  * might copy more than asked.
131  * */
132 static void
133 readseg(uintptr_t va, uint32_t count, uint32_t offset) {
134     7c72:    55                       push   %ebp
135     7c73:    89 e5                    mov    %esp,%ebp
136     7c75:    57                       push   %edi
137     7c76:    56                       push   %esi
138     7c77:    89 c6                    mov    %eax,%esi
139     7c79:    53                       push   %ebx
140     uintptr_t end_va = va + count;
141     7c7a:    8d 04 10                 lea    (%eax,%edx,1),%eax
142 
143     // round down to sector boundary
144     va -= offset % SECTSIZE;
145     7c7d:    31 d2                    xor    %edx,%edx
146 /* *
147  * readseg - read @count bytes at @offset from kernel into virtual address @va,
148  * might copy more than asked.
149  * */
150 static void
151 readseg(uintptr_t va, uint32_t count, uint32_t offset) {
152     7c7f:    53                       push   %ebx
153     uintptr_t end_va = va + count;
154     7c80:    89 45 f0                 mov    %eax,-0x10(%ebp)
155 
156     // round down to sector boundary
157     va -= offset % SECTSIZE;
158     7c83:    89 c8                    mov    %ecx,%eax
159     7c85:    f7 35 e4 7d 00 00        divl   0x7de4
160     7c8b:    29 d6                    sub    %edx,%esi
161 
162     // translate from bytes to sectors; kernel starts at sector 1
163     uint32_t secno = (offset / SECTSIZE) + 1;
164     7c8d:    8d 58 01                 lea    0x1(%eax),%ebx
165 
166     // If this is too slow, we could read lots of sectors at a time.
167     // We'd write more to memory than asked, but it doesn't matter --
168     // we load in increasing order.
169     for (; va < end_va; va += SECTSIZE, secno ++) {
170     7c90:    3b 75 f0                 cmp    -0x10(%ebp),%esi
171     7c93:    73 65                    jae    7cfa <readseg+0x88>
172 static inline void ltr(uint16_t sel) __attribute__((always_inline));
173 
174 static inline uint8_t
175 inb(uint16_t port) {
176     uint8_t data;
177     asm volatile ("inb %1, %0" : "=a" (data) : "d" (port));
178     7c95:    ba f7 01 00 00           mov    $0x1f7,%edx
179     7c9a:    ec                       in     (%dx),%al
180 struct elfhdr * ELFHDR    =      ((struct elfhdr *)0x10000) ;     // scratch space
181 
182 /* waitdisk - wait for disk ready */
183 static void
184 waitdisk(void) {
185     while ((inb(0x1F7) & 0xC0) != 0x40)
186     7c9b:    83 e0 c0                 and    $0xffffffc0,%eax
187     7c9e:    3c 40                    cmp    $0x40,%al
188     7ca0:    75 f3                    jne    7c95 <readseg+0x23>
189             : "memory", "cc");
190 }
191 
192 static inline void
193 outb(uint16_t port, uint8_t data) {
194     asm volatile ("outb %0, %1" :: "a" (data), "d" (port));
195     7ca2:    b2 f2                    mov    $0xf2,%dl
196     7ca4:    b0 01                    mov    $0x1,%al
197     7ca6:    ee                       out    %al,(%dx)
198     7ca7:    0f b6 c3                 movzbl %bl,%eax
199     7caa:    b2 f3                    mov    $0xf3,%dl
200     7cac:    ee                       out    %al,(%dx)
201     7cad:    0f b6 c7                 movzbl %bh,%eax
202     7cb0:    b2 f4                    mov    $0xf4,%dl
203     7cb2:    ee                       out    %al,(%dx)
204     waitdisk();
205 
206     outb(0x1F2, 1);                         // count = 1
207     outb(0x1F3, secno & 0xFF);
208     outb(0x1F4, (secno >> 8) & 0xFF);
209     outb(0x1F5, (secno >> 16) & 0xFF);
210     7cb3:    89 d8                    mov    %ebx,%eax
211     7cb5:    b2 f5                    mov    $0xf5,%dl
212     7cb7:    c1 e8 10                 shr    $0x10,%eax
213     7cba:    0f b6 c0                 movzbl %al,%eax
214     7cbd:    ee                       out    %al,(%dx)
215     outb(0x1F6, ((secno >> 24) & 0xF) | 0xE0);
216     7cbe:    89 d8                    mov    %ebx,%eax
217     7cc0:    b2 f6                    mov    $0xf6,%dl
218     7cc2:    c1 e8 18                 shr    $0x18,%eax
219     7cc5:    83 e0 0f                 and    $0xf,%eax
220     7cc8:    83 c8 e0                 or     $0xffffffe0,%eax
221     7ccb:    ee                       out    %al,(%dx)
222     7ccc:    b0 20                    mov    $0x20,%al
223     7cce:    b2 f7                    mov    $0xf7,%dl
224     7cd0:    ee                       out    %al,(%dx)
225 static inline void ltr(uint16_t sel) __attribute__((always_inline));
226 
227 static inline uint8_t
228 inb(uint16_t port) {
229     uint8_t data;
230     asm volatile ("inb %1, %0" : "=a" (data) : "d" (port));
231     7cd1:    ba f7 01 00 00           mov    $0x1f7,%edx
232     7cd6:    ec                       in     (%dx),%al
233 struct elfhdr * ELFHDR    =      ((struct elfhdr *)0x10000) ;     // scratch space
234 
235 /* waitdisk - wait for disk ready */
236 static void
237 waitdisk(void) {
238     while ((inb(0x1F7) & 0xC0) != 0x40)
239     7cd7:    83 e0 c0                 and    $0xffffffc0,%eax
240     7cda:    3c 40                    cmp    $0x40,%al
241     7cdc:    75 f3                    jne    7cd1 <readseg+0x5f>
242 
243     // wait for disk to be ready
244     waitdisk();
245 
246     // read a sector
247     insl(0x1F0, dst, SECTSIZE / 4);
248     7cde:    8b 0d e4 7d 00 00        mov    0x7de4,%ecx
249     return data;
250 }
251 
252 static inline void
253 insl(uint32_t port, void *addr, int cnt) {
254     asm volatile (
255     7ce4:    89 f7                    mov    %esi,%edi
256     7ce6:    ba f0 01 00 00           mov    $0x1f0,%edx
257     7ceb:    c1 e9 02                 shr    $0x2,%ecx
258     7cee:    fc                       cld    
259     7cef:    f2 6d                    repnz insl (%dx),%es:(%edi)
260     uint32_t secno = (offset / SECTSIZE) + 1;
261 
262     // If this is too slow, we could read lots of sectors at a time.
263     // We'd write more to memory than asked, but it doesn't matter --
264     // we load in increasing order.
265     for (; va < end_va; va += SECTSIZE, secno ++) {
266     7cf1:    03 35 e4 7d 00 00        add    0x7de4,%esi
267     7cf7:    43                       inc    %ebx
268     7cf8:    eb 96                    jmp    7c90 <readseg+0x1e>
269         readsect((void *)va, secno);
270     }
271 }
272     7cfa:    58                       pop    %eax
273     7cfb:    5b                       pop    %ebx
274     7cfc:    5e                       pop    %esi
275     7cfd:    5f                       pop    %edi
276     7cfe:    5d                       pop    %ebp
277     7cff:    c3                       ret    
278 
279 00007d00 <bootmain>:
280 
281 /* bootmain - the entry of bootloader */
282 void
283 bootmain(void) {
284     // read the 1st page off disk
285     readseg((uintptr_t)ELFHDR, SECTSIZE * 8, 0);
286     7d00:    a1 e4 7d 00 00           mov    0x7de4,%eax
287     7d05:    31 c9                    xor    %ecx,%ecx
288     }
289 }
290 
291 /* bootmain - the entry of bootloader */
292 void
293 bootmain(void) {
294     7d07:    55                       push   %ebp
295     7d08:    89 e5                    mov    %esp,%ebp
296     7d0a:    56                       push   %esi
297     // read the 1st page off disk
298     readseg((uintptr_t)ELFHDR, SECTSIZE * 8, 0);
299     7d0b:    8d 14 c5 00 00 00 00     lea    0x0(,%eax,8),%edx
300     7d12:    a1 e0 7d 00 00           mov    0x7de0,%eax
301     }
302 }
303 
304 /* bootmain - the entry of bootloader */
305 void
306 bootmain(void) {
307     7d17:    53                       push   %ebx
308     // read the 1st page off disk
309     readseg((uintptr_t)ELFHDR, SECTSIZE * 8, 0);
310     7d18:    e8 55 ff ff ff           call   7c72 <readseg>
311 
312     // is this a valid ELF?
313     if (ELFHDR->e_magic != ELF_MAGIC) {
314     7d1d:    a1 e0 7d 00 00           mov    0x7de0,%eax
315     7d22:    81 38 7f 45 4c 46        cmpl   $0x464c457f,(%eax)
316     7d28:    75 3a                    jne    7d64 <bootmain+0x64>
317     }
318 
319     struct proghdr *ph, *eph;
320 
321     // load each program segment (ignores ph flags)
322     ph = (struct proghdr *)((uintptr_t)ELFHDR + ELFHDR->e_phoff);
323     7d2a:    8b 58 1c                 mov    0x1c(%eax),%ebx
324     7d2d:    01 c3                    add    %eax,%ebx
325     eph = ph + ELFHDR->e_phnum;
326     7d2f:    0f b7 40 2c              movzwl 0x2c(%eax),%eax
327     7d33:    c1 e0 05                 shl    $0x5,%eax
328     7d36:    8d 34 03                 lea    (%ebx,%eax,1),%esi
329     for (; ph < eph; ph ++) {
330     7d39:    39 f3                    cmp    %esi,%ebx
331     7d3b:    73 18                    jae    7d55 <bootmain+0x55>
332         readseg(ph->p_va & 0xFFFFFF, ph->p_memsz, ph->p_offset);
333     7d3d:    8b 43 08                 mov    0x8(%ebx),%eax
334     struct proghdr *ph, *eph;
335 
336     // load each program segment (ignores ph flags)
337     ph = (struct proghdr *)((uintptr_t)ELFHDR + ELFHDR->e_phoff);
338     eph = ph + ELFHDR->e_phnum;
339     for (; ph < eph; ph ++) {
340     7d40:    83 c3 20                 add    $0x20,%ebx
341         readseg(ph->p_va & 0xFFFFFF, ph->p_memsz, ph->p_offset);
342     7d43:    8b 4b e4                 mov    -0x1c(%ebx),%ecx
343     7d46:    8b 53 f4                 mov    -0xc(%ebx),%edx
344     7d49:    25 ff ff ff 00           and    $0xffffff,%eax
345     7d4e:    e8 1f ff ff ff           call   7c72 <readseg>
346     7d53:    eb e4                    jmp    7d39 <bootmain+0x39>
347     }
348 
349     // call the entry point from the ELF header
350     // note: does not return
351     ((void (*)(void))(ELFHDR->e_entry & 0xFFFFFF))();
352     7d55:    a1 e0 7d 00 00           mov    0x7de0,%eax
353     7d5a:    8b 40 18                 mov    0x18(%eax),%eax
354     7d5d:    25 ff ff ff 00           and    $0xffffff,%eax
355     7d62:    ff d0                    call   *%eax
356     asm volatile ("outb %0, %1" :: "a" (data), "d" (port));
357 }
358 
359 static inline void
360 outw(uint16_t port, uint16_t data) {
361     asm volatile ("outw %0, %1" :: "a" (data), "d" (port));
362     7d64:    b8 00 8a ff ff           mov    $0xffff8a00,%eax
363     7d69:    89 c2                    mov    %eax,%edx
364     7d6b:    66 ef                    out    %ax,(%dx)
365     7d6d:    b8 00 8e ff ff           mov    $0xffff8e00,%eax
366     7d72:    66 ef                    out    %ax,(%dx)
367     7d74:    eb fe                    jmp    7d74 <bootmain+0x74>
bootblock.asm

 反汇编得到的代码是:

下图是bootasm.S中14到28行的代码:

下面是bootblock.asm中10到25行的代码

比较可知,三者基本一致。

(四)自己找一个bootloader或内核中的代码位置,设置断点并进行测试

 

  

原文地址:https://www.cnblogs.com/cyx-b/p/11762551.html