Lab1实验报告

Lab1实验报告

思考题

Q1

实验中采用过的objdumpobjdump -DS 要反汇编的目标文件名 > 导出文本文件名,通过执行man objdump查看参数含义为:

1
2
3
4
-D:
disassemble the contents of all sections, not just those expected to contain instructions.
-S:
Display source code intermixed with disassembly, if possible.

发现-D是反汇编所有的section,-S为尽可能展示出反汇编汇合后的源代码。

执行如下代码,其中.c文件是 $Hello world$ 程序:

1
2
3
4
mips-linux-gnu-gcc -c c_file.c
mips-linux-gnu-gcc -o c_file c_file.c
mips-linux-gnu-objdump -DS c_file.o > a.txt
mips-linux-gnu-objdump -DS c_file > b.txt

得到a.txt

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
c_file.o:     文件格式 elf32-tradbigmips


Disassembly of section .text:

00000000 <main>:
0: 27bdffe0 addiu sp,sp,-32
4: afbe001c sw s8,28(sp)
8: 03a0f025 move s8,sp
c: 24020001 li v0,1
10: afc20000 sw v0,0(s8)
14: 24020002 li v0,2
18: afc20004 sw v0,4(s8)
1c: 8fc30000 lw v1,0(s8)
20: 8fc20004 lw v0,4(s8)
24: 00621021 addu v0,v1,v0
28: afc20008 sw v0,8(s8)
2c: 8fc30000 lw v1,0(s8)
30: 8fc20004 lw v0,4(s8)
34: 00621023 subu v0,v1,v0
38: afc2000c sw v0,12(s8)
3c: 8fc30000 lw v1,0(s8)
40: 8fc20004 lw v0,4(s8)
44: 70621002 mul v0,v1,v0
48: afc20010 sw v0,16(s8)
4c: 8fc30000 lw v1,0(s8)
50: 8fc20004 lw v0,4(s8)
54: 004001f4 teq v0,zero,0x7
58: 0062001a div zero,v1,v0
5c: 00001010 mfhi v0
60: 00001012 mflo v0
64: afc20014 sw v0,20(s8)
68: 00001025 move v0,zero
6c: 03c0e825 move sp,s8
70: 8fbe001c lw s8,28(sp)
74: 27bd0020 addiu sp,sp,32
78: 03e00008 jr ra
7c: 00000000 nop

Disassembly of section .reginfo:

00000000 <.reginfo>:
0: e000000c sc zero,12(zero)
...

Disassembly of section .MIPS.abiflags:

00000000 <.MIPS.abiflags>:
0: 00002002 srl a0,zero,0x0
4: 01010005 lsa zero,t0,at,0x1
...

Disassembly of section .pdr:

00000000 <.pdr>:
0: 00000000 nop
4: 40000000 mfc0 zero,c0_index
8: fffffffc 0xfffffffc
...
14: 00000020 add zero,zero,zero
18: 0000001e 0x1e
1c: 0000001f 0x1f

Disassembly of section .comment:

00000000 <.comment>:
0: 00474343 0x474343
4: 3a202855 xori zero,s1,0x2855
8: 62756e74 0x62756e74
c: 75203130 jalx 480c4c0 <main+0x480c4c0>
10: 2e332e30 sltiu s3,s1,11824
14: 2d317562 sltiu s1,t1,30050
18: 756e7475 jalx 5b9d1d4 <main+0x5b9d1d4>
1c: 31292031 andi t1,t1,0x2031
20: 302e332e andi t6,at,0x332e
24: 地址 0x0000000000000024 越界。


Disassembly of section .gnu.attributes:

00000000 <.gnu.attributes>:
0: 41000000 mftc0 zero,c0_index
4: 0f676e75 jal d9db9d4 <main+0xd9db9d4>
8: 00010000 sll

部分b.txt如下:

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
c_file:     文件格式 elf32-tradbigmips


Disassembly of section .interp:

00400194 <.interp>:
400194: 2f6c6962 sltiu t4,k1,26978
400198: 2f6c642e sltiu t4,k1,25646
40019c: 736f2e31 0x736f2e31
...

Disassembly of section .MIPS.abiflags:

004001a8 <.MIPS.abiflags>:
4001a8: 00002002 srl a0,zero,0x0
4001ac: 01010005 lsa zero,t0,at,0x1
...

Disassembly of section .reginfo:

004001c0 <.reginfo>:
4001c0: b20000f6 0xb20000f6
...
4001d4: 00419010 0x419010

Disassembly of section .note.gnu.build-id:

004001d8 <.note.gnu.build-id>:
4001d8: 00000004 sllv zero,zero,zero
4001dc: 00000014 0x14
4001e0: 00000003 sra zero,zero,0x0
4001e4: 474e5500 bz.w $w14,4155e8 <_end+0x4588>
4001e8: 2dd459bb sltiu s4,t6,22971
4001ec: eb089062 swc2 $8,-28574(t8)
4001f0: d1251b25 0xd1251b25
4001f4: 7ff6b1d7 0x7ff6b1d7
4001f8: 5b89d35a 0x5b89d35a

Disassembly of section .note.ABI-tag:

004001fc <__abi_tag>:
4001fc: 00000004 sllv zero,zero,zero
400200: 00000010 mfhi zero
400204: 00000001 movf zero,zero,$fcc0
400208: 474e5500 bz.w $w14,41560c <_end+0x45ac>
40020c: 00000000 nop
400210: 00000003 sra zero,zero,0x0
400214: 00000002 srl zero,zero,0x0
400218: 00000000 nop

Disassembly of section .dynamic:

0040021c <_DYNAMIC>:
40021c: 00000001 movf zero,zero,$fcc0
400220: 0000003d 0x3d
400224: 0000000c syscall
400228: 00400490 0x400490
40022c: 0000000d break
400230: 004007b0 tge v0,zero,0x1e
400234: 00000004 sllv zero,zero,zero
400238: 004002fc 0x4002fc
40023c: 00000005 lsa zero,zero,zero,0x1
400240: 004003c4 0x4003c4
400244: 00000006 srlv zero,zero,zero
400248: 00400334 teq v0,zero,0xc
40024c: 0000000a movz zero,zero,zero
400250: 00000097 0x97
400254: 0000000b movn zero,zero,zero
400258: 00000010 mfhi zero
40025c: 70000016 udi6 zero,zero,zero,0x0
400260: 00411010 0x411010
400264: 70000035 0x70000035
400268: 00010dac 0x10dac
40026c: 00000015 0x15
400270: 00000000 nop
400274: 00000003 sra zero,zero,0x0
400278: 00411020 add v0,v0,at
40027c: 70000001 maddu zero,zero
400280: 00000001 movf zero,zero,$fcc0
400284: 70000005 msubu zero,zero
400288: 00000002 srl zero,zero,0x0
40028c: 70000006 0x70000006
400290: 00400000 0x400000
400294: 7000000a 0x7000000a
400298: 00000006 srlv zero,zero,zero
40029c: 70000011 udi1 zero,zero,zero,0x0
4002a0: 00000009 jalr zero,zero
4002a4: 70000012 udi2 zero,zero,zero,0x0
4002a8: 0000001d 0x1d
4002ac: 70000013 udi3 zero,zero,zero,0x0
4002b0: 00000005 lsa zero,zero,zero,0x1
4002b4: 6ffffffe 0x6ffffffe
4002b8: 00400470 tge v0,zero,0x11
4002bc: 6fffffff 0x6fffffff
4002c0: 00000001 movf zero,zero,$fcc0
4002c4: 6ffffff0 0x6ffffff0
4002c8: 0040045c 0x40045c
...

链接后的代码依旧十分体积庞大。


Q2

自己编写的readelf并不能编译自身,并且通过实验发现若执行gcc -o hello hello.c后,./readelf hello依旧无输出。通过使用自带的readelf -h指令来查看信息,能够得到如下结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
% 使用MAKEFILE中的指令生成的可执行文件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
入口点地址: 0x8049600
程序头起点: 52 (bytes into file)
Start of section headers: 746252 (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: 35
Section header string table index: 34
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
% 使用gcc命令生成的可执行文件hello %
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
入口点地址: 0x1060
程序头起点: 64 (bytes into file)
Start of section headers: 13976 (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

发现二者的文件类型一个为ELF32一个为ELF64。因此初步推断自己编写的只能解析ELF32类型的文件。

因为其不能编译自身,因此查看编写的readelf信息如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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

发现其依旧为ELF64类型。因此验证了上述猜想——我们编写的 readelf 程序无法解析ELF64类型文件。


Q3

在内核启动时,首先进行硬件设备初始化,通过ROM中的bootloader执行。在第二阶段中,在ROM中初始化,读取载入内核。此时要执行引导程序,它能够将内核载入内存并跳转,从而保证内核入库能够被正确跳转到。



实验难点

  1. shdr的计算

    1
    shdr = (Elf32_Shdr *)(binary + ehdr->e_shoff + i * sh_entry_size);

    基地址加上ehdr->e_shoff,得到整个section的头地址,再加上偏移isection得到每一个段对应的首地址。

    值得注意的是,数据类型要转换成Shdr的指针。尽管指针指向的地址都是一些数字,但是因为数据类型不同,因此对地址的结息方式不同,因此一定要转化数据类型。


  1. 将节装填到对应位置

    通过阅读内存布局图,能够找到text的基地址为0x80010000,在找到这个位置后,后续的data以及bss顺序分配空间即可。

    1
    2
    3
    4
    . = 0x80010000 ;
    .text : { *(.text) }
    .data : { *(.data) }
    .bss : { *(.bss) }

  1. $sp指针的初始位置

    因此设置指向0x80400000即可

    1
    li sp, 0x80400000

  1. 注意printk()参数的初始化

    这个不算是难点,但是很容易忽略。我在起初编写就因为没有初始化而导致输出错误,且找了很久才找到这个问题。



心得体会

本次Lab的难度我个人感觉要高于Lab0,知识难度以及知识内容都要难理解且更多。对我个人而言,我认为printk()函数是这个任务中相对简单的,可能是因为我有一定的C语言基础。

而难点我认为是ELF结构的阅读理解。通过查看教程书中的表,理解段与节引用的地方一致但用处不同后,便能够对ELF有更好的认识。

  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
Runtime Display
  • Copyrights © 2023-2024 Lucas
  • 访问人数: | 浏览次数:

请我喝杯咖啡吧~

支付宝
微信