Rust Hacking - Compound Type (Part II)
2024-05-16
这次我们来看看在 Rust 中如何表示 Compound Type (内存中),新建示例项目,并打开 src/main.rs
写入如下代码:
1 #[derive(Debug)]
2 struct MyStruct {
3 a: i32,
4 b: u64,
5 c: String,
6 }
7
8 #[derive(Debug)]
9 enum MyEnum {
10 First(i32),
11 Second(usize),
12 }
13
14 impl MyStruct {
15 fn new(a: i32, b: u64, c: String) -> Self {
16 Self{a, b, c}
17 }
18 }
19
20 fn main() {
21 let my_struct = MyStruct::new(1, 2, String::from("hello"));
22 let my_first = MyEnum::First(3);
23 let my_second = MyEnum::Second(4);
24 let my_tuple = (5, 6, 7);
25 let my_array = [8, 9, 10];
26 println!("struct: {}, {}, {}", my_struct.a, my_struct.b, my_struct.c);
27 println!("tuple: {my_tuple:?}");
28 println!("array: {my_array:?}");
29 if let MyEnum::First(a) = my_first {
30 println!("enum: {a}");
31 }
32 if let MyEnum::Second(b) = my_second {
33 println!("enum: {b}");
34 }
35 }
Analysis
Rust 编译器会根据 Size 和 Alignment 调整结构中各个字段在内存中布局,详情可参考 https://doc.rust-lang.org/reference/type-layout.html.
Struct
GDB
加载编译的二进制,根据上次分析的入口,我们下断点到 compound_type::main
上, run
起程序即可断到程序入口,查看 main
的反汇编结果,可得出如下分析图:
可以看到,Rust 编译器 默认
情况下并未按照结构体定义的顺序放置各个字段(此处的顺序是 c, b, a)
Tuple && Array
紧挨着 Struct 的初始化就是 Tuple 和 Array, 在初始化时并未明确指明具体类型,此处编译器默认两者类型都是 i32
, 汇编中可得出这一推断:
Enum
继续往下,即是 Enum
的初始化,具体参考 Enum Memory Layout
总结
- Compound Type 基于 Scalar Type 组合起来,其基本内存布局符合预期
- 需要注意的是: 在未明确要求的情况下(without annotation),编译器不保证各个成员的布局与定义一致,所以在需要明确的布局时,务必使用
[repr()]
类注解