1

I'm running the below block of code on my computer.

/* Example code for Think OS.

Copyright 2014 Allen Downey
License: GNU GPLv3

*/

#include <stdio.h>
#include <stdlib.h>

int var1;

int main ()
{
    int var2 = 5;
    void *p = malloc(128);
    void *p2 = malloc(128);
    char *s = "Hello, World";

    printf ("Address of main is %p\n", main);
    printf ("Address of var1 is %p\n", &var1);
    printf ("Address of var2 is %p\n", &var2);
    printf ("p points to %p\n", p);
    printf ("p2 points to %p\n", p2);
    printf ("s points to %p\n", s);

    return 0;
}

Here is a table of the resulting addresses:

| Stack     | var2           | 0x7fff58cf28d8 |
| Heap      | p2             | 0x7fb4c2d032d0 |
| Heap      | p              | 0x7fb4c2d03250 |
| Globals   | var1           |    0x106f0e020 |
| Constants | "Hello, World" |    0x106f0df34 |
| Code      | main           |    0x106f0de30 |

My mental model is that the heap should start right after the Globals section and grow up in address space. It grows up, but I don't understand the gap.

Why is there such a big gap between var1 and p?

gdb doesn't have a great tool to visualize the entire address space (so if you have tools that could help I'm open to suggestions).

user2460234
  • 95
  • 1
  • 10
  • It is an implementation choice, nothing to do with C itself. – Weather Vane Mar 15 '18 at 23:50
  • Implementation choice of the compiler or the OS? – user2460234 Mar 16 '18 at 00:00
  • 2
    They may be in different memory segments, which these days are virtual so the apparent addresses have no comparison. The C language itself has no concept of stacks or heaps only how the code should perform. The compiler will implement the code according to what platform it will run on; so both, but the OS has no say in how the code is compiled. – Weather Vane Mar 16 '18 at 00:02
  • Ask your linker and OS loader. – Martin James Mar 16 '18 at 09:28

2 Answers2

1

You do not specify your operating system. However, there are multiple forces at work here.

  • Linker
  • Loader
  • Operating System

The linker determines the layout of the data defined by the program. That includes, all static data, code, and global variables.

The loader positions the segments defined by the linker in memory.

The combination of linker and loader then give the address of your main, var1, and data referenced by s. Traditionally, the loader tries to place the application as as low in the address space as possible. However, it is becoming common for loads to place code at random locations.

The loader usually allocates the initial stack for the process as well. That gives the location of var2 and s. Stacks generally grow downwards so the loader tries to place them as far away from the program data as possible to keep them from colliding.

The operating system allocates dynamic memory to process. Heap is just memory. You can have multiple heaps and heaps split over different locations. It just so happens when your heap manager allocates pages from the operating system, it is getting them at high locations in memory.

user3344003
  • 20,574
  • 3
  • 26
  • 62
0

I messed up my copy and paste.

Running the code again I get something like this:

Address of main is 0x4005d6
Address of var1 is 0x60104c
Address of var2 is 0x7fffd328785c
p points to 0x1d1f010
p2 points to 0x1d1f0a0
s points to 0x400744

which immediately made me realize my mistake. In the table displayed in my question I had copied the address of the variable p, not what p points to.

Edit: still open to tools for viewing memory. Something similar to this Xcode tool, but preferably a CLI or something that can attach to C processes.

user2460234
  • 95
  • 1
  • 10