1

Why in the following example the global variables are stored in the heap segment, instead of the data/bss segment?

From the following output of the maps pseudo-file, the data/bss segment is the 3rd line. This is because it is read/write, and anonymous. The following 2 entries are the heap (as the label indicates).

This is the output of the /proc//maps:

00400000-00405000 r-xp 00000000 08:02 17962770                       myexec
00604000-00605000 r--p 00004000 08:02 17962770                       myexec
00605000-00606000 rw-p 00005000 08:02 17962770                       myexec
00606000-00607000 rw-p 00000000 00:00 0                              [heap]
00607000-00642000 rw-p 00000000 00:00 0                              [heap]
7ffff7a15000-7ffff7bd0000 r-xp 00000000 08:02 22282470               ..libc2.19.so
7ffff7bd0000-7ffff7dcf000 ---p 001bb000 08:02 22282470               ..libc-.19.so
7ffff7dcf000-7ffff7dd3000 r--p 001ba000 08:02 22282470               ..libc-.19.so
7ffff7dd3000-7ffff7dd5000 rw-p 001be000 08:02 22282470               ..libc-.19.so
7ffff7dd5000-7ffff7dda000 rw-p 00000000 00:00 0 
7ffff7dda000-7ffff7dfd000 r-xp 00000000 08:02 22282466               ..ld-2.19.so
7ffff7fec000-7ffff7fef000 rw-p 00000000 00:00 0 
7ffff7ff6000-7ffff7ff7000 rw-p 00000000 00:00 0 
7ffff7ff7000-7ffff7ffa000 rw-p 00000000 00:00 0 
7ffff7ffa000-7ffff7ffc000 r-xp 00000000 00:00 0                       [vdso]
7ffff7ffc000-7ffff7ffd000 r--p 00022000 08:02 22282466                ..ld-2.19.so
7ffff7ffd000-7ffff7ffe000 rw-p 00023000 08:02 22282466                ..ld-2.19.so
7ffff7ffe000-7ffff7fff000 rw-p 00000000 00:00 0 
7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0                       [stack]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0               [vsyscall]

However, when I print the location of 2 global variables, I get the following addresses that belong to the heap vm area:

glb1:6061b0 glb2:6061c0

I print the locations using:

printf("glb1:%lx glb2:%lx\n", (uint64_t) &glb1, (uint64_t) &glb2);
trincot
  • 317,000
  • 35
  • 244
  • 286
Paschalis
  • 11,929
  • 9
  • 52
  • 82
  • Shouldn't you print the location using `printf("%p", (void*)&glb1)` ? – Weather Vane Apr 16 '15 at 17:35
  • Do you mind showing how the variables are declared? Also a look into the map file can help – Eugene Sh. Apr 16 '15 at 17:49
  • @EugeneSh. they are declared outside the main function. `int gbl1, glb2;` – Paschalis Apr 16 '15 at 18:06
  • 1
    despite the label, I don't agree that's the heap (you probably wouldn't be satisfied with a 4k limited heap). I've done a quick test program which shows similar lines than yours, but mine shows the executable name there. – mfro Apr 16 '15 at 18:08
  • @WeatherVane the addresses are `uint64_t` in my case. So printing it using `%lx` or `%p` it does not matter. With `%p` the addresses just have `0x` prefix. The map file? I have already attached the output of `/proc//maps` – Paschalis Apr 16 '15 at 18:10
  • @mfro the heap size in this case is ~241k, not 4. Keep in mind that there are 2 entries for the heap. I still believe that data/bss segment is at `00605000-00606000`, but it might extend on the next segment, which linux says it is the heap.. What do you guys think? – Paschalis Apr 16 '15 at 18:13
  • Something to do with keeping a particular alignment? – Cong Ma Apr 16 '15 at 18:20
  • 1
    I was just being syntactically correct: http://stackoverflow.com/questions/9053658/correct-format-specifier-to-print-pointer-address – Weather Vane Apr 16 '15 at 18:22
  • 1
    @Paschalis: it might well be the case that libc is using the rest of the 4k page after the global variables as start of dynamic memory to save memory, so this _might_ be the heap, but for sure it's also the .bss and .data segments (link your program with `-Wl,-Map -Wl mapfile, this will tell you were the segments are put by the linker). – mfro Apr 16 '15 at 18:24
  • 1
    @Paschalis: No, `uint64_t` is an integer type, not a pointer type. And `%lx` isn't the right format to print a `uint64_t` value anyway. Just use `printf("glb1:%p glb1: %p\n", (void*)&glb1, (void*)&glb2);`. It's likely that your way will work, but by printing pointers as pointers we don't have to worry about it. – Keith Thompson Apr 16 '15 at 18:52

1 Answers1

3

The BSS/DATA is the segment with all the globally defined variables, initialized to a specific value or to zero by default. This segment is part of the executable image.

The heap "segment" is just the amount of additional storage that will be allocated at program load. It is not contained in the image. This amount follows at the end of the BSS/DATA segment.

Hence the BSS/DATA and heap segment have the same base address. Think of the heap segment as virtual/as a virtual extentsion of the bss/data segment of the image.

Lastly, note that often the stack "segment" is added again to this amount and, whereas the heap grows up, the stack grows down. (This may be compiler dependent.)

Paul Ogilvie
  • 25,048
  • 4
  • 23
  • 41