Why is my Rust executable mapped to such high addresses (near the stack) instead of 0x400000?

I am studying the layout of Linux memory space on x86_64 systems and wanted to print some addresses from some sections. I used this Rust code:

fn main() { let x = 3; // should be stored on stack let s = "hello"; // should be in the .data section println!("stack β‰ˆ {:p}", &x); println!(".text β‰ˆ {:p}", main as *const ()); println!(".data β‰ˆ {:p}", s); use std::io; let mut f = std::fs::File::open("/proc/self/maps").unwrap(); let out = io::stdout(); io::copy(&mut f, &mut out.lock()).unwrap(); } 

This code also outputs the file /proc/self/maps to stdout. I compiled this mem.rs file simply with rustc mem.rs He typed:

 stack β‰ˆ 0x7ffffbf82f2c .text β‰ˆ 0x7f45b7c0a2b0 .data β‰ˆ 0x7f45b7c4d35b 7f45b6800000-7f45b6c00000 rw-- 00000000 00:00 0 7f45b6de0000-7f45b6f9a000 rx- 00000000 00:00 664435 /lib/x86_64-linux-gnu/libc-2.19.so 7f45b6f9a000-7f45b6fa2000 ---- 001ba000 00:00 664435 /lib/x86_64-linux-gnu/libc-2.19.so [ ... more .so files] 7f45b7a22000-7f45b7a23000 r--- 00022000 00:00 663920 /lib/x86_64-linux-gnu/ld-2.19.so 7f45b7a23000-7f45b7a24000 rw-- 00023000 00:00 663920 /lib/x86_64-linux-gnu/ld-2.19.so 7f45b7a24000-7f45b7a25000 rw-- 00000000 00:00 0 7f45b7aa0000-7f45b7aa2000 rw-- 00000000 00:00 0 7f45b7ab0000-7f45b7ab2000 rw-- 00000000 00:00 0 7f45b7ac0000-7f45b7ac1000 rw-- 00000000 00:00 0 7f45b7ad0000-7f45b7ad1000 rw-- 00000000 00:00 0 7f45b7ae0000-7f45b7ae2000 rw-- 00000000 00:00 0 7f45b7c00000-7f45b7c5f000 rx- 00000000 00:00 1134580 /home/lukas/tmp/mem 7f45b7e5e000-7f45b7e62000 r--- 0005e000 00:00 1134580 /home/lukas/tmp/mem 7f45b7e62000-7f45b7e63000 rw-- 00062000 00:00 1134580 /home/lukas/tmp/mem 7f45b7e63000-7f45b7e64000 rw-- 00000000 00:00 0 7ffffb784000-7ffffb785000 ---- 00000000 00:00 0 [stack] 7ffffb785000-7ffffbf84000 rw-- 00000000 00:00 0 7ffffc263000-7ffffc264000 rx- 00000000 00:00 0 [vdso] 

At least the addresses that I typed myself seem to match what maps says. But when I execute cat /proc/self/maps in the terminal, I get this output:

 00400000-0040b000 rx- 00000000 00:00 107117 /bin/cat 0060a000-0060b000 r--- 0000a000 00:00 107117 /bin/cat 0060b000-0060c000 rw-- 0000b000 00:00 107117 /bin/cat 0071c000-0073d000 rw-- 00000000 00:00 0 [heap] 7f7deb933000-7f7debc30000 r--- 00000000 00:00 758714 /usr/lib/locale/locale-archive 7f7debc30000-7f7debdea000 rx- 00000000 00:00 664435 /lib/x86_64-linux-gnu/libc-2.19.so 7f7debdea000-7f7debdf2000 ---- 001ba000 00:00 664435 /lib/x86_64-linux-gnu/libc-2.19.so [ ... more .so files ...] 7f7dec222000-7f7dec223000 r--- 00022000 00:00 663920 /lib/x86_64-linux-gnu/ld-2.19.so 7f7dec223000-7f7dec224000 rw-- 00023000 00:00 663920 /lib/x86_64-linux-gnu/ld-2.19.so 7f7dec224000-7f7dec225000 rw-- 00000000 00:00 0 7f7dec250000-7f7dec252000 rw-- 00000000 00:00 0 7f7dec260000-7f7dec261000 rw-- 00000000 00:00 0 7f7dec270000-7f7dec272000 rw-- 00000000 00:00 0 7ffff09e8000-7ffff11e8000 rw-- 00000000 00:00 0 [stack] 7ffff1689000-7ffff168a000 rx- 00000000 00:00 0 [vdso] 

The last result corresponds to everything I read about this section: sections from the executable are displayed at the lower end of the virtual address space (starting from 0x400000).

I executed and compiled everything in the Linux subsystem for Windows (mostly Ubuntu 14.04). I know this is new and more, but I am sure that this is not a problem with the subsystem (please tell me if this is so!). Rust 1.14 is what matters (I doubt)

I also tried the same with C program (sorry, probably bad C):

 #include <stdio.h> #include <errno.h> #include <string.h> #include <stdlib.h> int main(int argc, char **argv) { FILE *test_file; char buf[4096]; if ((test_file = fopen ("/proc/self/maps", "r")) != NULL) { while (!feof (test_file)) { fgets (buf, sizeof (buf), test_file); puts (buf); } } return 0; } 

It outputs something similar to cat :

 00400000-00401000 rx- 00000000 00:00 1325490 /home/lukas/tmp/a.out 00600000-00601000 r--- 00000000 00:00 1325490 /home/lukas/tmp/a.out 00601000-00602000 rw-- 00001000 00:00 1325490 /home/lukas/tmp/a.out 

Why is the Rust executable mapped to large addresses near the stack?

+5
source share
1 answer

Using rustc -Z print-link-args addr.rs , you can see which linker call the Rust compiler uses. Since the current linker is cc , we can directly use these options for program C. Ignoring the irrelevant arguments and deleting each other one after another, I am left with this compiler call:

 gcc -fPIC -pie addr.c -o addr-c 

Compiling C code like this creates similar addresses, such as the Rust-compiled executable, indicating that one or both of these options are the likely culprit. This changes the question to "why do the -fPIC and / or -pie match such high addresses?"

I found another question and answer that seems to shed some light on this:

The PIE binary is associated with a shared library, so its default download address ( .p_vaddr first LOAD segment) is zero. It is expected that something will move this binary page from the zero page and load it at some random address.

Using readelf -e in the Rust executable, we see that the first LOAD segment has a virtual zero address:

 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flags Align LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000 0x000000000005e6b4 0x000000000005e6b4 RE 200000 LOAD 0x000000000005ead0 0x000000000025ead0 0x000000000025ead0 0x00000000000039d1 0x00000000000049e8 RW 200000 

I guess this then changes the question to β€œwhy are these random addresses selected”, but I'm not sure about this answer. ^ _ ^ Guess tells me that ASLR is coming into play. This other answer seems to confirm this:

PIE must support ASLR in executables.

ASLR is a security method that helps simplify programs against certain types of attacks, so it makes sense that Rust, with its safe approach, will try to enable something like this by default. Indeed, addresses change a small bit per call:

 root@97bcff9a925c :/# ./addr | grep 'r-xp' | grep 'addr' 5587cea9d000-5587ceafc000 r-xp 00000000 00:21 206 /addr 561d8aae2000-561d8ab41000 r-xp 00000000 00:21 206 /addr 555c30ffd000-555c3105c000 r-xp 00000000 00:21 206 /addr 55db249d5000-55db24a34000 r-xp 00000000 00:21 206 /addr 55e988572000-55e9885d1000 r-xp 00000000 00:21 206 /addr 560400e1b000-560400e7a000 r-xp 00000000 00:21 206 /addr 
+6
source

Source: https://habr.com/ru/post/1262505/


All Articles