9

I want to print the memory location (address) of a variable with:

let x = 1;
println!("{:p}", &x);

This prints the hex value 0x7fff51ef6380 which in decimal is 140734568031104.

My computer has 16GB of RAM, so why this huge number? Does the x64 architecture use a big interval sequence instead of just simple 1 increment for accessing memory location?

In x86, usually the first location starts at 0, then 1, 2, etc. so the highest number you can have is around 4 billion, so the address number was always equals or less than 4 billion.

Why is this not the case with x64?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
John Smith
  • 1,848
  • 3
  • 13
  • 24

2 Answers2

16

What you see here is an effect of virtual memory. Memory management is hard and it becomes even harder when the operating system and tens of hundreds of processes have to share the memory. In order to handle this huge complexity, the concept of virtual memory was used. I'll just briefly explain the basics here; the topic is far more complex and you should read about it somewhere else, too.

On most modern computers, each process thinks that it owns (almost) the complete memory space. But processes never deal with physical addresses, but with virtual ones. These virtual addresses are mapped to physical ones each time the process actually reads from memory. This translation of addresses is done by the so called MMU (memory management unit). The rules for how to map the addresses are setup by the operating system.

When you boot your PC, the operating system creates an initial mapping. Every time you start a process, the operating system adds a few slices of physical memory to the process and modifies the mapping appropriately. That way, the process has memory to play with.

On x86_64, the address space is 64 bit wide, so each process thinks it owns all of those 2^64 addresses. This is not true, of course:

  1. There isn't a single PC on the world with that much memory. (In fact, most CPUs today can merely use 280 TB of RAM, since they internally can only use 48bit for addressing physical memory. And even these 280TB are enough for now, apparently.)
  2. Even if you had that much memory, there are other processes which use part of that memory, too.

So what happens when you try to read an address which isn't mapped (which in 64bit land, are the vast majority of the addresses)? The MMU triggers a page fault. This makes the CPU notify the operating system to handle this.

What I mean is that in x86, usually first location starts at 0, then 1, 2, etc. so the highest number you can have is around 4 billion.

That is true, but it is also true if your x86 system has less than 4GB of RAM. Virtual memory exists for quite some time already.


So that's a short summary of why you see such big addresses. Again, please note that I glossed over many details here.

Lukas Kalbertodt
  • 79,749
  • 26
  • 255
  • 305
  • BTW, it's a coincidence that current CPUs support 48-bit physical addresses. First-gen AMD64 chips supported 40 bits of physical addresses, and x86-64's page-table format can support [52-bit physical addresses](https://stackoverflow.com/questions/46509152/why-in-64bit-the-virtual-address-are-4-bits-short-48bit-long-compared-with-the). Also, virtual address space is really only 48-bits (and addresses must be canonical, see my answer). – Peter Cordes Oct 11 '17 at 20:08
  • re: point 2: no, every process has its own virtual address space. This is one of the major benefits of virtual memory. The kernel might reserve half of it for its own use (e.g. while in kernel mode from that process making a system call), but that's *all*. A process always has 47 (or logically 63, and also in reality if x86-64 is extended to real 64-bit virtual addresses). I know you're simplifying, but I think this point is important. A process has its virtual address space to itself. – Peter Cordes Oct 11 '17 at 20:13
  • @PeterCordes About point 2: I meant what you said (I even mentioned this advantage above), but I can now see that the way I wrote it, it is easy to misunderstand. Sorry about that. I'll fix it soon. Thanks! – Lukas Kalbertodt Oct 11 '17 at 20:34
  • Heh, I wondered if you meant "effects". I only skimmed before commenting. – Peter Cordes Oct 11 '17 at 20:42
  • 1
    Minor quibble: modern CPU cores don't have a separate "MMU". Support for virtual memory is completely baked-in to each CPU core, and [TLBs are intertwined with the level-1 caches](https://stackoverflow.com/questions/46480015/vipt-cache-connection-between-tlb-cache). x86 has dedicated page-walk hardware, so all the OS has to do is put a page-directory pointer into CR3, or modify the existing page tables in memory and invalidate any affected translations. – Peter Cordes Oct 11 '17 at 20:49
  • I get that talking about "the MMU" is a useful mental model for beginners, but then people wonder "[whether each core has its own MMU](https://stackoverflow.com/questions/34437371/is-the-tlb-shared-between-multiple-cores)"... I think I just wanted to rant about a pet peeve rather than get you to actually change your answer. :P But really the "MMU" functionality is split up into iTLB (coupled with L1I cache), dTLB (with L1D cache), a second-level TLB to service TLB misses from either L1TLB, and page-walk hardware to service L2 TLB misses. And the CR3 control register... – Peter Cordes Oct 11 '17 at 20:50
  • So behind the scenes the virtual memory address which could be a 64 bit number, is mapped with the physical location address which can only be as big as the memory size unless it is actually using an address mapped to a swap file . Right? – John Smith Oct 11 '17 at 22:11
  • @JohnSmith: Close, but physical address space doesn't include swap files. They're not physically hooked up to the memory bus! You can have files mmaped into virtual address space, and they will be faulted into a physical page on demand if they weren't already. This may need to evict other physical pages to make room. (So going back and accessing a virtual page you touched earlier might fault again.) – Peter Cordes Oct 12 '17 at 10:12
8

The pointers your program works with are in virtual address space. x86-64 uses 64-bit pointers. This was one of the major goals of AMD64, along with adding more integer and XMM registers. You are correct that i386 only has 32-bit pointers which only cover 4GB of address space in each process.

0x7fff51ef6380 looks like a stack pointer, which I guess makes sense for that code.

Linux on x86-64 (for example) puts the stack near the top of the lower canonical address range: current x86-64 hardware only implements 48-bit virtual addresses and this is the mechanism to prevent software from depending on it. This allows the address space to be extended in the future without breaking software.

The amount of phyiscal RAM in your system has nothing to do with this. You'd see (approximately) the same number on an x86-64 system with 128MB of RAM, +/- stack address space layout randomization (ASLR).

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847