Skip to content

Commit 1ada73f

Browse files
committed
2024秋冬季训练营第四阶段总结-Zoneshiyi.md
1 parent b0bf9e6 commit 1ada73f

File tree

1 file changed

+182
-0
lines changed

1 file changed

+182
-0
lines changed
Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
---
2+
title: 2024秋冬季训练营第四阶段总结-Zoneshiyi
3+
date: 2024-12-19 19:45:08
4+
tags:
5+
- author: Zoneshiyi
6+
---
7+
# mocklibc
8+
9+
## ELF结构
10+
11+
### ELF Header
12+
描述整个文件的组织。
13+
``` Rust
14+
pub struct Elf32_Ehdr {
15+
// Magic、Class(32-bit vs 64-bit)、Data(2's complement、endian)、ELF Version、OS/ABI、ABI Version
16+
pub e_ident: [u8; abi::EI_NIDENT],
17+
// Relocatable file、Executable file、Shared object file、Core file
18+
pub e_type: u16,
19+
// CPU 平台属性
20+
pub e_machine: u16,
21+
// ELF 版本号,通常为1
22+
pub e_version: u32,
23+
pub e_entry: u32,
24+
pub e_phoff: u32,
25+
pub e_shoff: u32,
26+
pub e_flags: u32,
27+
// Size of elf header
28+
pub e_ehsize: u16,
29+
// Size of ph entry
30+
pub e_phentsize: u16,
31+
// Number of ph
32+
pub e_phnum: u16,
33+
// Size of sh entry
34+
pub e_shentsize: u16,
35+
// Number of ph
36+
pub e_shnum: u16,
37+
// Section header string table index
38+
pub e_shstrndx: u16,
39+
}
40+
41+
pub struct Elf64_Ehdr {
42+
...
43+
pub e_entry: u64,
44+
pub e_phoff: u64,
45+
pub e_shoff: u64,
46+
...
47+
}
48+
```
49+
50+
### Sections 和 Segments
51+
segments是从运行的角度来描述elf文件,sections是从链接的角度来描述elf文件,在链接阶段,可以忽略program header table来处理此文件,在运行阶段可以忽略section header table来处理此程序(所以很多加固手段删除了section header table)。一个segment包含若干个section。
52+
#### Program Header Table
53+
描述文件中的各种segments,用来告诉系统如何创建进程映像的。
54+
```Rust
55+
pub struct ProgramHeader {
56+
/// Program segment type
57+
pub p_type: u32,
58+
/// Offset into the ELF file where this segment begins
59+
pub p_offset: u64,
60+
/// Virtual adress where this segment should be loaded
61+
pub p_vaddr: u64,
62+
/// Physical address where this segment should be loaded
63+
pub p_paddr: u64,
64+
/// Size of this segment in the file
65+
pub p_filesz: u64,
66+
/// Size of this segment in memory
67+
pub p_memsz: u64,
68+
/// Flags for this segment
69+
pub p_flags: u32,
70+
/// file and memory alignment
71+
pub p_align: u64,
72+
}
73+
```
74+
**p_type**
75+
```Rust
76+
/// Program header table entry unused
77+
pub const PT_NULL: u32 = 0;
78+
/// Loadable program segment
79+
pub const PT_LOAD: u32 = 1;
80+
/// Dynamic linking information
81+
pub const PT_DYNAMIC: u32 = 2;
82+
/// Program interpreter
83+
pub const PT_INTERP: u32 = 3;
84+
/// Auxiliary information
85+
pub const PT_NOTE: u32 = 4;
86+
/// Unused
87+
pub const PT_SHLIB: u32 = 5;
88+
/// The program header table
89+
pub const PT_PHDR: u32 = 6;
90+
/// Thread-local storage segment
91+
pub const PT_TLS: u32 = 7;
92+
/// GCC .eh_frame_hdr segment
93+
pub const PT_GNU_EH_FRAME: u32 = 0x6474e550;
94+
/// Indicates stack executability
95+
pub const PT_GNU_STACK: u32 = 0x6474e551;
96+
/// Read-only after relocation
97+
pub const PT_GNU_RELRO: u32 = 0x6474e552;
98+
/// The segment contains .note.gnu.property section
99+
pub const PT_GNU_PROPERTY: u32 = 0x6474e553;
100+
/// Values between [PT_LOOS, PT_HIOS] in this inclusive range are reserved for
101+
/// operating system-specific semantics.
102+
pub const PT_LOOS: u32 = 0x60000000;
103+
/// Values between [PT_LOOS, PT_HIOS] in this inclusive range are reserved for
104+
/// operating system-specific semantics.
105+
pub const PT_HIOS: u32 = 0x6fffffff;
106+
/// Values between [PT_LOPROC, PT_HIPROC] in this inclusive range are reserved
107+
/// for processor-specific semantics.
108+
pub const PT_LOPROC: u32 = 0x70000000;
109+
/// Values between [PT_LOPROC, PT_HIPROC] in this inclusive range are reserved
110+
/// for processor-specific semantics.
111+
pub const PT_HIPROC: u32 = 0x7fffffff;
112+
```
113+
#### Section Header Table
114+
```Rust
115+
pub struct SectionHeader {
116+
/// Section Name,对应字符串在string table段中的偏移
117+
pub sh_name: u32,
118+
/// Section Type
119+
pub sh_type: u32,
120+
/// Section Flags
121+
pub sh_flags: u64,
122+
/// in-memory address where this section is loaded
123+
pub sh_addr: u64,
124+
/// Byte-offset into the file where this section starts
125+
pub sh_offset: u64,
126+
/// Section size in bytes
127+
pub sh_size: u64,
128+
/// Defined by section type
129+
pub sh_link: u32,
130+
/// Defined by section type
131+
pub sh_info: u32,
132+
/// address alignment
133+
pub sh_addralign: u64,
134+
/// size of an entry if section data is an array of entries
135+
pub sh_entsize: u64,
136+
}
137+
```
138+
139+
## 自定义加载ELF
140+
141+
### 静态链接
142+
143+
**编译选项:**
144+
```bash
145+
STATIC_FLAG = \
146+
-nostdlib \
147+
-nostartfiles \
148+
-nodefaultlibs \
149+
-ffreestanding \
150+
-O0 \
151+
-mcmodel=medany \
152+
-static \
153+
-no-pie \
154+
-L./target/riscv64gc-unknown-linux-musl/release/ -lmocklibc
155+
156+
riscv64-linux-musl-gcc hello.c $(STATIC_FLAG) -o hello
157+
```
158+
159+
静态编译的可执行文件加载比较简单,直接将其加载到内存中的一块连续空间即可。
160+
161+
唯一要注意的是同时开启`-static``-no-pie`选项才能生产类型为EXEC (Executable file)的ELF文件,同时还需要通过linker.ld链接脚本正确设置起始地址。
162+
163+
### 动态链接
164+
165+
**编译选项:**
166+
```bash
167+
DYNAMIC_FLAG = \
168+
-nostdlib \
169+
-nostartfiles \
170+
-nodefaultlibs \
171+
-ffreestanding \
172+
-O0 \
173+
-mcmodel=medany \
174+
-L./target/riscv64gc-unknown-linux-musl/release/ -lmocklibc
175+
176+
riscv64-linux-musl-gcc hello.c $(DYNAMIC_FLAG) -o hello -Wl,-dynamic-linker /path/to/ld-musl-riscv64.so.1
177+
178+
```
179+
180+
linux加载动态链接的可执行文件流程比较复杂,一方面是系统在执行应用前有很多额外的处理,另一方面是加载器本身不提供函数,需要加载一系列的动态链接库。而在我们当前的Unikernel框架下,并不存在动态链接库,系统启动时所有函数都加载到了内存中,因此可以大幅简化加载流程。
181+
182+
首先解析program header将elf文件中类型为PT_LOAD的segment加载到内存中,然后解析.dynsym、.rela.plt节的信息可以知道需要动态链接的函数名,以及重定位条目在内存中的位置。在内核中建立了函数名到对于函数地址的映射,根据这些信息修改重定位条目就能让程序正确执行。

0 commit comments

Comments
 (0)