BUAA OS LAB1 实验报告

Thinking

Thinking 1.1

Q:

在阅读附录中的编译链接详解以及本章内容后,尝试分别使用实验环境中 的原生 x86 工具链(gcc、ld、readelf、objdump 等)和 MIPS 交叉编译工具链(带有 mips-linux-gnu- 前缀,如 mips-linux-gnu-gcc、mips-linux-gnu-ld),重复其中的编 译和解析过程,观察相应的结果,并解释其中向objdump传入的参数的含义。

A:

编写程序hello.c

1
2
3
4
5
6
#include <stdio.h>
int main()
{
printf("Hello World!\n");
return 0;
}

这里只截取.text部分

x86 .o

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
am.o:     文件格式 elf64-x86-64
Disassembly of section .text:
0000000000000000 <main>:
0: f3 0f 1e fa endbr64
4: 55 push %rbp
5: 48 89 e5 mov %rsp,%rbp
8: 48 8d 05 00 00 00 00 lea 0x0(%rip),%rax # f <main+0xf>
f: 48 89 c7 mov %rax,%rdi
12: b8 00 00 00 00 mov $0x0,%eax
17: e8 00 00 00 00 call 1c <main+0x1c>
1c: b8 00 00 00 00 mov $0x0,%eax
21: 5d pop %rbp
22: c3 ret

...

x86

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
a:     文件格式 elf64-x86-64

Disassembly of section .text:

0000000000001060 <_start>:
1060: f3 0f 1e fa endbr64
1064: 31 ed xor %ebp,%ebp
1066: 49 89 d1 mov %rdx,%r9
1069: 5e pop %rsi
106a: 48 89 e2 mov %rsp,%rdx
106d: 48 83 e4 f0 and $0xfffffffffffffff0,%rsp
1071: 50 push %rax
1072: 54 push %rsp
1073: 45 31 c0 xor %r8d,%r8d
1076: 31 c9 xor %ecx,%ecx
1078: 48 8d 3d ca 00 00 00 lea 0xca(%rip),%rdi # 1149 <main>
107f: ff 15 53 2f 00 00 call *0x2f53(%rip) # 3fd8 <__libc_start_main@GLIBC_2.34>
1085: f4 hlt
1086: 66 2e 0f 1f 84 00 00 cs nopw 0x0(%rax,%rax,1)
108d: 00 00 00

0000000000001090 <deregister_tm_clones>:
1090: 48 8d 3d 79 2f 00 00 lea 0x2f79(%rip),%rdi # 4010 <__TMC_END__>
1097: 48 8d 05 72 2f 00 00 lea 0x2f72(%rip),%rax # 4010 <__TMC_END__>
109e: 48 39 f8 cmp %rdi,%rax
10a1: 74 15 je 10b8 <deregister_tm_clones+0x28>
10a3: 48 8b 05 36 2f 00 00 mov 0x2f36(%rip),%rax # 3fe0 <_ITM_deregisterTMCloneTable@Base>
10aa: 48 85 c0 test %rax,%rax
10ad: 74 09 je 10b8 <deregister_tm_clones+0x28>
10af: ff e0 jmp *%rax
10b1: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
10b8: c3 ret
10b9: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)

00000000000010c0 <register_tm_clones>:
10c0: 48 8d 3d 49 2f 00 00 lea 0x2f49(%rip),%rdi # 4010 <__TMC_END__>
10c7: 48 8d 35 42 2f 00 00 lea 0x2f42(%rip),%rsi # 4010 <__TMC_END__>
10ce: 48 29 fe sub %rdi,%rsi
10d1: 48 89 f0 mov %rsi,%rax
10d4: 48 c1 ee 3f shr $0x3f,%rsi
10d8: 48 c1 f8 03 sar $0x3,%rax
10dc: 48 01 c6 add %rax,%rsi
10df: 48 d1 fe sar $1,%rsi
10e2: 74 14 je 10f8 <register_tm_clones+0x38>
10e4: 48 8b 05 05 2f 00 00 mov 0x2f05(%rip),%rax # 3ff0 <_ITM_registerTMCloneTable@Base>
10eb: 48 85 c0 test %rax,%rax
10ee: 74 08 je 10f8 <register_tm_clones+0x38>
10f0: ff e0 jmp *%rax
10f2: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
10f8: c3 ret
10f9: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)

0000000000001100 <__do_global_dtors_aux>:
1100: f3 0f 1e fa endbr64
1104: 80 3d 05 2f 00 00 00 cmpb $0x0,0x2f05(%rip) # 4010 <__TMC_END__>
110b: 75 2b jne 1138 <__do_global_dtors_aux+0x38>
110d: 55 push %rbp
110e: 48 83 3d e2 2e 00 00 cmpq $0x0,0x2ee2(%rip) # 3ff8 <__cxa_finalize@GLIBC_2.2.5>
1115: 00
1116: 48 89 e5 mov %rsp,%rbp
1119: 74 0c je 1127 <__do_global_dtors_aux+0x27>
111b: 48 8b 3d e6 2e 00 00 mov 0x2ee6(%rip),%rdi # 4008 <__dso_handle>
1122: e8 19 ff ff ff call 1040 <__cxa_finalize@plt>
1127: e8 64 ff ff ff call 1090 <deregister_tm_clones>
112c: c6 05 dd 2e 00 00 01 movb $0x1,0x2edd(%rip) # 4010 <__TMC_END__>
1133: 5d pop %rbp
1134: c3 ret
1135: 0f 1f 00 nopl (%rax)
1138: c3 ret
1139: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)

0000000000001140 <frame_dummy>:
1140: f3 0f 1e fa endbr64
1144: e9 77 ff ff ff jmp 10c0 <register_tm_clones>

0000000000001149 <main>:
1149: f3 0f 1e fa endbr64
114d: 55 push %rbp
114e: 48 89 e5 mov %rsp,%rbp
1151: 48 8d 05 ac 0e 00 00 lea 0xeac(%rip),%rax # 2004 <_IO_stdin_used+0x4>
1158: 48 89 c7 mov %rax,%rdi
115b: b8 00 00 00 00 mov $0x0,%eax
1160: e8 eb fe ff ff call 1050 <printf@plt>
1165: b8 00 00 00 00 mov $0x0,%eax
116a: 5d pop %rbp
116b: c3 ret
...

mips .o

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
a.o:     文件格式 elf32-tradbigmips

Disassembly of section .text:

00000000 <main>:
0: 27bdffe0 addiu sp,sp,-32
4: afbf001c sw ra,28(sp)
8: afbe0018 sw s8,24(sp)
c: 03a0f025 move s8,sp
10: 3c1c0000 lui gp,0x0
14: 279c0000 addiu gp,gp,0
18: afbc0010 sw gp,16(sp)
1c: 3c020000 lui v0,0x0
20: 24440000 addiu a0,v0,0
24: 8f820000 lw v0,0(gp)
28: 0040c825 move t9,v0
2c: 0320f809 jalr t9
30: 00000000 nop
34: 8fdc0010 lw gp,16(s8)
38: 00001025 move v0,zero
3c: 03c0e825 move sp,s8
40: 8fbf001c lw ra,28(sp)
44: 8fbe0018 lw s8,24(sp)
48: 27bd0020 addiu sp,sp,32
4c: 03e00008 jr ra
50: 00000000 nop
...

mips

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
a:     文件格式 elf32-tradbigmips

Disassembly of section .text:

00400520 <__start>:
400520: 03e00025 move zero,ra
400524: 04110001 bal 40052c <__start+0xc>
400528: 00000000 nop
40052c: 3c1c0002 lui gp,0x2
400530: 279c7ae4 addiu gp,gp,31460
400534: 039fe021 addu gp,gp,ra
400538: 0000f825 move ra,zero
40053c: 8f848018 lw a0,-32744(gp)
400540: 8fa50000 lw a1,0(sp)
400544: 27a60004 addiu a2,sp,4
400548: 2401fff8 li at,-8
40054c: 03a1e824 and sp,sp,at
400550: 27bdffe0 addiu sp,sp,-32
400554: 00003825 move a3,zero
400558: afa00010 sw zero,16(sp)
40055c: afa20014 sw v0,20(sp)
400560: afbd0018 sw sp,24(sp)
400564: 8f99802c lw t9,-32724(gp)
400568: 0320f809 jalr t9
40056c: 00000000 nop

00400570 <hlt>:
400570: 1000ffff b 400570 <hlt>
400574: 00000000 nop
...

00400580 <deregister_tm_clones>:
400580: 3c040042 lui a0,0x42
400584: 3c020042 lui v0,0x42
400588: 24840014 addiu a0,a0,20
40058c: 24420014 addiu v0,v0,20
400590: 10440007 beq v0,a0,4005b0 <deregister_tm_clones+0x30>
400594: 3c1c0043 lui gp,0x43
400598: 279c8010 addiu gp,gp,-32752
40059c: 8f998028 lw t9,-32728(gp)
4005a0: 13200003 beqz t9,4005b0 <deregister_tm_clones+0x30>
4005a4: 00000000 nop
4005a8: 03200008 jr t9
4005ac: 00000000 nop
4005b0: 03e00008 jr ra
4005b4: 00000000 nop

004005b8 <register_tm_clones>:
4005b8: 3c040042 lui a0,0x42
4005bc: 3c020042 lui v0,0x42
4005c0: 24840014 addiu a0,a0,20
4005c4: 24450014 addiu a1,v0,20
4005c8: 00a42823 subu a1,a1,a0
4005cc: 00051083 sra v0,a1,0x2
4005d0: 00052fc2 srl a1,a1,0x1f
4005d4: 00a22821 addu a1,a1,v0
4005d8: 00052843 sra a1,a1,0x1
4005dc: 10a00007 beqz a1,4005fc <register_tm_clones+0x44>
4005e0: 3c1c0043 lui gp,0x43
4005e4: 279c8010 addiu gp,gp,-32752
4005e8: 8f99801c lw t9,-32740(gp)
4005ec: 13200003 beqz t9,4005fc <register_tm_clones+0x44>
4005f0: 00000000 nop
4005f4: 03200008 jr t9
4005f8: 00000000 nop
4005fc: 03e00008 jr ra
400600: 00000000 nop

00400604 <__do_global_dtors_aux>:
400604: 27bdffe0 addiu sp,sp,-32
400608: afb00018 sw s0,24(sp)
40060c: 3c100042 lui s0,0x42
400610: afbf001c sw ra,28(sp)
400614: 92020050 lbu v0,80(s0)
400618: 14400006 bnez v0,400634 <__do_global_dtors_aux+0x30>
40061c: 8fbf001c lw ra,28(sp)
400620: 0c100160 jal 400580 <deregister_tm_clones>
400624: 00000000 nop
400628: 24020001 li v0,1
40062c: a2020050 sb v0,80(s0)
400630: 8fbf001c lw ra,28(sp)
400634: 8fb00018 lw s0,24(sp)
400638: 03e00008 jr ra
40063c: 27bd0020 addiu sp,sp,32

00400640 <frame_dummy>:
400640: 0810016e j 4005b8 <register_tm_clones>
400644: 00000000 nop
...

00400650 <main>:
400650: 27bdffe0 addiu sp,sp,-32
400654: afbf001c sw ra,28(sp)
400658: afbe0018 sw s8,24(sp)
40065c: 03a0f025 move s8,sp
400660: 3c1c0043 lui gp,0x43
400664: 279c8010 addiu gp,gp,-32752
400668: afbc0010 sw gp,16(sp)
40066c: 3c020040 lui v0,0x40
400670: 24440720 addiu a0,v0,1824
400674: 8f828024 lw v0,-32732(gp)
400678: 0040c825 move t9,v0
40067c: 0320f809 jalr t9
400680: 00000000 nop
400684: 8fdc0010 lw gp,16(s8)
400688: 00001025 move v0,zero
40068c: 03c0e825 move sp,s8
400690: 8fbf001c lw ra,28(sp)
400694: 8fbe0018 lw s8,24(sp)
400698: 27bd0020 addiu sp,sp,32
40069c: 03e00008 jr ra
4006a0: 00000000 nop
...

objdump 格式:
objdump -DS 要反汇编的目标文件名 > 导出文本文件名
-D:反汇编所有的section;
-d:反汇编那些特定指令机器码的section;
-S :尽可能反汇编出源代码,尤其当编译的时候指定了-g 这种调试参数时,效果比较明显,隐含了-d参数;
-s:显示指定section的完整内容。默认所有的非空section都会被显示。

Thinking 1.2

Q:

• 尝试使用我们编写的readelf程序,解析之前在target目录下生成的内核ELF文 件。
• 也许你会发现我们编写的readelf程序是不能解析readelf 文件本身的,而我们刚 才介绍的系统工具readelf 则可以解析,这是为什么呢?(提示:尝试使用readelf-h,并阅读tools/readelf 目录下的 Makefile,观察 readelf 与 hello 的不同)

A:

运行 ./tools/readelf/readelf ./target/mos 指令得:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
0:0x0
1:0x80400000
2:0x804016f0
3:0x80401708
4:0x80401720
5:0x0
6:0x0
7:0x0
8:0x0
9:0x0
10:0x0
11:0x0
12:0x0
13:0x0
14:0x0
15:0x0
16:0x0
17:0x0

hello:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
git@23371468:~/23371468/tools/readelf (lab1)$ readelf -h hello
ELF 头:
Magic: 7f 45 4c 46 01 01 01 03 00 00 00 00 00 00 00 00
类别: ELF32
数据: 2 补码,小端序 (little endian)
Version: 1 (current)
OS/ABI: UNIX - GNU
ABI 版本: 0
类型: EXEC (可执行文件)
系统架构: Intel 80386
版本: 0x1
入口点地址: 0x8049750
程序头起点: 52 (bytes into file)
Start of section headers: 707128 (bytes into file)
标志: 0x0
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 8
Size of section headers: 40 (bytes)
Number of section headers: 30
Section header string table index: 29

readelf:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
git@23371468:~/23371468/tools/readelf (lab1)$ readelf -h readelf
ELF 头:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
类别: ELF64
数据: 2 补码,小端序 (little endian)
Version: 1 (current)
OS/ABI: UNIX - System V
ABI 版本: 0
类型: DYN (Position-Independent Executable file)
系统架构: Advanced Micro Devices X86-64
版本: 0x1
入口点地址: 0x1180
程序头起点: 64 (bytes into file)
Start of section headers: 14488 (bytes into file)
标志: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 13
Size of section headers: 64 (bytes)
Number of section headers: 31
Section header string table index: 30

Makefile 中对于 hello readelf 的生成分别是:

1
2
3
4
readelf: main.o readelf.o
$(CC) $^ -o $@
hello: hello.c
$(CC) $^ -o $@ -m32 -static -g

hello 是静态的 -static,将生成的可执行程序识别为 “executable” + “statically linked”,

而gcc 默认情况下生成 PIE,会将生成的可执行程序直接识别为 “shared object” + “dynamically linked”,PIE 文件设计为支持 地址空间布局随机化

因此与hello不同,他不能解析自己。

Thinking 1.3

Q:

在理论课上我们了解到,MIPS体系结构上电时,启动入口地址为0xBFC00000 (其实启动入口地址是根据具体型号而定的,由硬件逻辑确定,也有可能不是这个地址,但 一定是一个确定的地址),但实验操作系统的内核入口并没有放在上电启动地址,而是按照 内存布局图放置。思考为什么这样放置内核还能保证内核入口被正确跳转到? (提示:思考实验中启动过程的两阶段分别由谁执行。)

A:

在MIPS体系结构中,虽然硬件上电后的启动入口地址固定为0xBFC00000(或其他硬件指定地址),但操作系统内核仍能正确跳转到其实际入口地址的原因在于启动过程分为两个阶段:

  1. 第一阶段:Bootloader执行
    硬件启动后,首先执行位于0xBFC00000地址的代码(通常为Bootloader或固件)。这段代码负责:
    • 初始化硬件(如CPU、内存控制器等)。
    • 将操作系统内核从存储设备(如ROM)加载到内存中预定义的位置(由内存布局图决定)。
    • 通过跳转指令(如jrjal)将控制权移交到内核的实际入口地址。
  2. 第二阶段:内核执行
    内核的入口地址由链接脚本kernel.lds定义,通常位于内存布局图中。Bootloader通过硬编码或动态加载的方式跳转到该地址,从而启动内核。

lab0难点

T1

Elf32_Ehdr是ELF文件头;Elf32_Shdr是section节头表表项
一个节头表由多个节头表表项组成;
文件头的e_shoff是节头表所在处与文件头的偏移;
节头表表项的sh_offset是节的文件内偏移;
文件头的e_shentsize是节头表表项的大小;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//......
int readelf(const void *binary, size_t size) {
Elf32_Ehdr *ehdr = (Elf32_Ehdr *)binary;//ehdr是ELF程序头地址
//...
const void *sh_table;
Elf32_Half sh_entry_count;
Elf32_Half sh_entry_size;

/* Exercise 1.1: Your code here. (1/2) */

sh_table = binary + ehdr->e_shoff; //节头表第一项的地址
//!!!注意此处不能是 ehdr,否则会偏移e_shoff*sizeof(ehdr)的大小
sh_entry_count = ehdr->e_shnum; //节头表一共有多少项
sh_entry_size = ehdr->e_shentsize; //节头表每一项是多大

for (int i = 0; i < sh_entry_count; i++) {
const Elf32_Shdr *shdr;
unsigned int addr;

/* Exercise 1.1: Your code here. (2/2) */

shdr = (Elf32_Shdr*)(sh_table + i*sh_entry_size); //当前要输出的节头项
addr = shdr->sh_addr; //待输出的节头项地址
printf("%d:0x%x\n", i, addr);
}
return 0;
}

T2

通过查看内存布局图,能找到.text节的加载地址,.data和 .bss只需要紧随其后即可。

注意 LinkerScript文件编辑时“=”两边的空格

1
2
3
4
5
6
7
8
9
10
SECTIONS {
. = 0x80020000;
.text : { *(.text) }
.data : { *(.data) }
bss_start = .;
.bss : { *(.bss) }
bss_end = .;
. = 0x80400000;
end = . ;
}

T3

从内存示意图可见栈起始为0x80400000

这里做一个提醒,请注意栈的增长方向

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <asm/asm.h>
#include <mmu.h>
.text
EXPORT(_start)
.set at
.set reorder
la v0, bss_start
la v1, bss_end
clear_bss_loop:
beq v0, v1, clear_bss_done
sb zero, 0(v0)
addiu v0, v0, 1
j clear_bss_loop
clear_bss_done:
mtc0 zero, CP0_STATUS
/* Exercise 1.3: Your code here. (1/2) */
li sp, 0x80400000
/* jump to mips_init */
/* Exercise 1.3: Your code here. (2/2) */
jal mips_init

T4

注意负数的取值,和各个判断变量的初始化,这里考虑0-和-0的情况。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
for (;;) {
char *old=fmt;
while(*fmt!='\0'&&*fmt!='%') {
fmt++;
}
for(char *i=old;i<fmt;i++){
print_char(out,data,*i,1,0);
}
if(*fmt=='\0'){
break;
}
fmt++;
padc=' ';
ladjust=0;
long_flag=0;
if(*fmt=='0'){
padc='0';
fmt++;
if(*fmt=='-'){
ladjust=1;
fmt++;
}
}
else if(*fmt=='-'){
ladjust=1;
fmt++;
if(*fmt=='0'){
padc='0';
fmt++;
}
}
else{
;
}
int m=0;
while(*fmt>='0'&&*fmt<='9') {
m = ( m * 10) + ( *fmt - '0' );
fmt++;
}
width=m;
if(*fmt=='l'){
long_flag=1;
fmt++;
}
if(num<0) {
neg_flag=1;
num = -num;
}
print_num(out,data,num,10,neg_flag,width,ladjust,padc,0);
break;
}

实验体会总结

Lab1主要学习

操作系统启动的基本流程
ELF文件的结构和功能
完成一个printf函数的书写

在完成第一部分时,主要的时间花费在了理解定义的结构体的各个属性,以及指针的使用上,而地址的分配和start.S的书写则十分简单。

第二部分的printk书写的时候需要先理清解析函数的执行顺序,对前置函数的参数需要足够熟悉。

这次实验学习了多种文件的操作包括lds,c,makefile,shell,需要多种文件之间的相互配合,这锻炼了我们的系统能力和综合能力,为之后的实验奠定了良好的基础。

附录

OS内存地址图示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/*
o 4G -----------> +----------------------------+------------0x100000000
o | ... | kseg2
o KSEG2 -----> +----------------------------+------------0xc000 0000
o | Devices | kseg1
o KSEG1 -----> +----------------------------+------------0xa000 0000
o | Invalid Memory | /|\
o +----------------------------+----|-------Physical Memory Max
o | ... | kseg0
o KSTACKTOP-----> +----------------------------+----|-------0x8040 0000-------end
o | Kernel Stack | | KSTKSIZE /|\
o +----------------------------+----|------ |
o | Kernel Text | | PDMAP
o KERNBASE -----> +----------------------------+----|-------0x8002 0000 |
o | Exception Entry | \|/ \|/
o ULIM -----> +----------------------------+------------0x8000 0000-------
o | User VPT | PDMAP /|\
o UVPT -----> +----------------------------+------------0x7fc0 0000 |
o | pages | PDMAP |
o UPAGES -----> +----------------------------+------------0x7f80 0000 |
o | envs | PDMAP |
o UTOP,UENVS -----> +----------------------------+------------0x7f40 0000 |
o UXSTACKTOP -/ | user exception stack | PTMAP |
o +----------------------------+------------0x7f3f f000 |
o | | PTMAP |
o USTACKTOP ----> +----------------------------+------------0x7f3f e000 |
o | normal user stack | PTMAP |
o +----------------------------+------------0x7f3f d000 |
a | | |
a ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
a . . |
a . . kuseg
a . . |
a |~~~~~~~~~~~~~~~~~~~~~~~~~~~~| |
a | | |
o UTEXT -----> +----------------------------+------------0x0040 0000 |
o | reserved for COW | PTMAP |
o UCOW -----> +----------------------------+------------0x003f f000 |
o | reversed for temporary | PTMAP |
o UTEMP -----> +----------------------------+------------0x003f e000 |
o | invalid memory | \|/
a 0 ------------> +----------------------------+ ----------------------------
o
*/
/* End of Key Code "load-kernel" */