Den*_*ive 3 gdb heap-memory rust
我是 Rust 新手,我试图弄清楚东西分配在哪里。
1.64.0我在 Ubuntu 上使用 Rust 22.04.0( jammy):
$ rustc --version
rustc 1.64.0 (a55dd71d5 2022-09-19)
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 22.04.1 LTS
Release: 22.04
Codename: jammy
Run Code Online (Sandbox Code Playgroud)
我尝试通过编译这个非常基本的 Rust 程序来探索可执行文件:
fn tester() {
let borrowed_string: &str = "world";
println!("{}", borrowed_string);
}
fn main() { tester(); }
Run Code Online (Sandbox Code Playgroud)
编译(好吧,这有点矫枉过正了......但我想确保我拥有使用 GDB 所需的一切):
$ cargo build --config "profile.dev.debug=true" --config "profile.dev.opt-level=0" --profile=dev
Compiling variables v0.1.0 (/home/denis/Documents/github/rust-playground/variables)
Finished dev [unoptimized + debuginfo] target(s) in 0.71s
Run Code Online (Sandbox Code Playgroud)
Run rust-gdb,设置断点并运行程序:
$ rust-gdb target/debug/variables
GNU gdb (Ubuntu 12.0.90-0ubuntu1) 12.0.90
...
Reading symbols from target/debug/variables...
(gdb) b 3
Breakpoint 1 at 0x7959: file src/main.rs, line 3.
(gdb) r
Starting program: /home/denis/Documents/github/rust-playground/variables/target/debug/variables
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 1, variables::tester () at src/main.rs:3
3 println!("{}", borrowed_string);
(gdb)
s
Run Code Online (Sandbox Code Playgroud)
打印内存映射;
(gdb) info proc map
process 6985
Mapped address spaces:
Start Addr End Addr Size Offset Perms objfile
0x555555554000 0x55555555a000 0x6000 0x0 r--p /home/denis/Documents/github/rust-playground/variables/target/debug/variables
0x55555555a000 0x555555591000 0x37000 0x6000 r-xp /home/denis/Documents/github/rust-playground/variables/target/debug/variables
0x555555591000 0x55555559f000 0xe000 0x3d000 r--p /home/denis/Documents/github/rust-playground/variables/target/debug/variables
0x5555555a0000 0x5555555a3000 0x3000 0x4b000 r--p /home/denis/Documents/github/rust-playground/variables/target/debug/variables
0x5555555a3000 0x5555555a4000 0x1000 0x4e000 rw-p /home/denis/Documents/github/rust-playground/variables/target/debug/variables
0x5555555a4000 0x5555555c5000 0x21000 0x0 rw-p [heap]
0x7ffff7d5c000 0x7ffff7d5f000 0x3000 0x0 rw-p
0x7ffff7d5f000 0x7ffff7d87000 0x28000 0x0 r--p /usr/lib/x86_64-linux-gnu/libc.so.6
0x7ffff7d87000 0x7ffff7f1c000 0x195000 0x28000 r-xp /usr/lib/x86_64-linux-gnu/libc.so.6
0x7ffff7f1c000 0x7ffff7f74000 0x58000 0x1bd000 r--p /usr/lib/x86_64-linux-gnu/libc.so.6
0x7ffff7f74000 0x7ffff7f78000 0x4000 0x214000 r--p /usr/lib/x86_64-linux-gnu/libc.so.6
0x7ffff7f78000 0x7ffff7f7a000 0x2000 0x218000 rw-p /usr/lib/x86_64-linux-gnu/libc.so.6
0x7ffff7f7a000 0x7ffff7f87000 0xd000 0x0 rw-p
0x7ffff7f87000 0x7ffff7f8a000 0x3000 0x0 r--p /usr/lib/x86_64-linux-gnu/libgcc_s.so.1
0x7ffff7f8a000 0x7ffff7fa1000 0x17000 0x3000 r-xp /usr/lib/x86_64-linux-gnu/libgcc_s.so.1
0x7ffff7fa1000 0x7ffff7fa5000 0x4000 0x1a000 r--p /usr/lib/x86_64-linux-gnu/libgcc_s.so.1
0x7ffff7fa5000 0x7ffff7fa6000 0x1000 0x1d000 r--p /usr/lib/x86_64-linux-gnu/libgcc_s.so.1
0x7ffff7fa6000 0x7ffff7fa7000 0x1000 0x1e000 rw-p /usr/lib/x86_64-linux-gnu/libgcc_s.so.1
0x7ffff7fb8000 0x7ffff7fb9000 0x1000 0x0 ---p
0x7ffff7fb9000 0x7ffff7fbd000 0x4000 0x0 rw-p
0x7ffff7fbd000 0x7ffff7fc1000 0x4000 0x0 r--p [vvar]
0x7ffff7fc1000 0x7ffff7fc3000 0x2000 0x0 r-xp [vdso]
0x7ffff7fc3000 0x7ffff7fc5000 0x2000 0x0 r--p /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
0x7ffff7fc5000 0x7ffff7fef000 0x2a000 0x2000 r-xp /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
0x7ffff7fef000 0x7ffff7ffa000 0xb000 0x2c000 r--p /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
0x7ffff7ffb000 0x7ffff7ffd000 0x2000 0x37000 r--p /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
0x7ffff7ffd000 0x7ffff7fff000 0x2000 0x39000 rw-p /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
0x7ffffffde000 0x7ffffffff000 0x21000 0x0 rw-p [stack]
0xffffffffff600000 0xffffffffff601000 0x1000 0x0 --xp [vsyscall]
(gdb)
Run Code Online (Sandbox Code Playgroud)
我们有:
HEAP: [0x5555555A4000, 0x5555555C4FFF]
STACK: [0x7FFFFFFDE000, 0x7FFFFFFFEFFF]
Run Code Online (Sandbox Code Playgroud)
我假设数据“世界”是在堆中分配的。因此,让我们找出答案......但看看我得到了什么!
(gdb) find 0x5555555A4000, 0x5555555C4FFF, "world"
0x5555555a4ba0
1 pattern found.
(gdb) find 0x5555555A4000, 0x5555555C4FFF, "world"
0x5555555a4be0
1 pattern found.
(gdb) find 0x5555555A4000, 0x5555555C4FFF, "world"
0x5555555a4c20
1 pattern found.
(gdb) find 0x5555555A4000, 0x5555555C4FFF, "world"
0x5555555a4c60
1 pattern found.
(gdb) find 0x5555555A4000, 0x5555555C4FFF, "world"
0x5555555a4ca0
1 pattern found.
(gdb)
Run Code Online (Sandbox Code Playgroud)
请注意:
0x5555555A4BA0 -> 0x5555555A4BE0 => 64
0x5555555A4BE0 -> 0x5555555A4C20 => 64
0x5555555A4C20 -> 0x5555555A4C60 => 64
Run Code Online (Sandbox Code Playgroud)
问题:为什么数据的位置从一次扫描到下一次扫描会发生变化?
(这个问题可能与 Rust 无关。)
(gdb) p borrowed_string
$1 = "world"
(gdb) ptype borrowed_string
type = struct &str {
data_ptr: *mut u8,
length: usize,
}
(gdb) p borrowed_string.data_ptr
$2 = (*mut u8) 0x555555591000
(gdb) x/5c 0x555555591000
0x555555591000: 119 'w' 111 'o' 114 'r' 108 'l' 100 'd'
Run Code Online (Sandbox Code Playgroud)
我们有:
0x5555555A4000:堆的开始(包含)0x5555555C5000:堆的末尾(不包括),以及“未知”内存区域的开始0x555555591000:数据“world”的地址0x7FFFF7D5F000:“未知”内存领域的终结问题:0x5555555C5000(包含)和 0x7FFFF7D5F000(排除)之间的“未知”内存区域是什么?
编辑:
正如下面的评论中提到的,我犯了一个错误。数据“世界”位于堆“之前”......这些评论是有道理的。谢谢。
问题:0x5555555C5000(包含)和 0x7FFFF7D5F000(排除)之间的“未知”内存区域是什么?
没什么。这是未映射的内存。
“str”值分配在哪里?是在堆里吗?
你的内存映射回答了这个问题:
Run Code Online (Sandbox Code Playgroud)0x555555591000 0x55555559f000 0xe000 0x3d000 r--p /home/denis/Documents/github/rust-playground/variables/target/debug/variables
这是二进制文件本身被映射的区域之一。最有可能的是可执行文件的“rodata”段。字符串文字通常在二进制文件本身中“分配”,然后加载静态引用。
更一般地说str,值不会被分配,它们是对其他地方的数据的引用,这些数据可能位于堆上(如果引用是从一个String或Box<str>多个指针获得的),在二进制文件中(文字,静态包含),甚至是在堆栈(例如,您可以在堆栈上创建一个数组,然后将其传递std::str::from_utf8并&str从中取出)
我们有:堆:[0x5555555A4000,0x5555555C4FFF]
坦率地说,这并不是真正有帮助、有用或真实的:现代系统已经很大程度上从线性堆转向内存映射堆。虽然 Linux 软件仍然对 (s)brk 进行一些有限的使用,但 BSD 将它们称为“历史珍品”。如果您假设堆包含在这些范围内,您将面临很多意外。
问题:为什么每次扫描数据的位置会发生变化?
因为调试器正在程序的上下文中分配东西,我想?所以您可能会发现 gdb 本身正在存储的数据。