1

I made this simple C program and compiled it without ASLR

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

int a = 10;
int b = 20;

int main(int argc, char *argv[])
{
    printf("%lx\n",&a);
    printf("%lx\n",&b);

    return 0;
}   

Every time I execute it, the result is the same:

555555558018 55555555801c

Because of that, I am thinking that the data section should start somewhere near to 0x555555558018.

However, when I list the segments of my binary I see the following:

Elf file type is DYN (Position-Independent Executable file)
Entry point 0x1050
There are 13 program headers, starting at offset 64

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  PHDR           0x0000000000000040 0x0000000000000040 0x0000000000000040
                 0x00000000000002d8 0x00000000000002d8  R      0x8
  INTERP         0x0000000000000318 0x0000000000000318 0x0000000000000318
                 0x000000000000001c 0x000000000000001c  R      0x1
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
  LOAD           0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000618 0x0000000000000618  R      0x1000
  LOAD           0x0000000000001000 0x0000000000001000 0x0000000000001000
                 0x0000000000000195 0x0000000000000195  R E    0x1000
  LOAD           0x0000000000002000 0x0000000000002000 0x0000000000002000
                 0x00000000000000e4 0x00000000000000e4  R      0x1000
  LOAD           0x0000000000002dd0 0x0000000000003dd0 0x0000000000003dd0
                 0x0000000000000250 0x0000000000000258  RW     0x1000
  DYNAMIC        0x0000000000002de0 0x0000000000003de0 0x0000000000003de0
                 0x00000000000001e0 0x00000000000001e0  RW     0x8
  NOTE           0x0000000000000338 0x0000000000000338 0x0000000000000338
                 0x0000000000000020 0x0000000000000020  R      0x8
  NOTE           0x0000000000000358 0x0000000000000358 0x0000000000000358
                 0x0000000000000044 0x0000000000000044  R      0x4
  GNU_PROPERTY   0x0000000000000338 0x0000000000000338 0x0000000000000338
                 0x0000000000000020 0x0000000000000020  R      0x8
  GNU_EH_FRAME   0x000000000000200c 0x000000000000200c 0x000000000000200c
                 0x000000000000002c 0x000000000000002c  R      0x4
  GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000  RW     0x10
  GNU_RELRO      0x0000000000002dd0 0x0000000000003dd0 0x0000000000003dd0
                 0x0000000000000230 0x0000000000000230  R      0x1

 Section to Segment mapping:
  Segment Sections...
   00     
   01     .interp 
   02     .interp .note.gnu.property .note.gnu.build-id .note.ABI-tag .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt 
   03     .init .plt .plt.got .text .fini 
   04     .rodata .eh_frame_hdr .eh_frame 
   05     .init_array .fini_array .dynamic .got .got.plt .data .bss 
   06     .dynamic 
   07     .note.gnu.property 
   08     .note.gnu.build-id .note.ABI-tag 
   09     .note.gnu.property 
   10     .eh_frame_hdr 
   11     
   12     .init_array .fini_array .dynamic .got                                          

There is not such an address. I think that maybe there is a difference between C pointers (I observe that they consist of 48 bits), and the Virtual Addresses of the segments (that consist of 64 bits). Where are the C pointers actually pointing to?

I have different hypothesis. Once I read that C pointers are actually offsets of their segments (not sure if this is true). The other thing I can think about, is that C pointers are logical addresses, while the segment's virtual addresses refer to the Linear Address Space. See the difference below:

Memory in x86

linux
  • 11
  • 2
  • 3
    `printf("%lx\n",&a);` is not the proper way to print an address. The proper format specifier is `%p`, and the address has to be cast to `void *`: `printf("%p\n", (void *) &a);` – Andrew Henle Jan 25 '23 at 16:54
  • 3
    This file, as it states, *Position-Independent Executable file*. So only offsets matter. – Eugene Sh. Jan 25 '23 at 16:56
  • 1
    The addresses are virtual, and there isn't a 48-bit type. – Weather Vane Jan 25 '23 at 16:59
  • I printed the addresses with %p and casting them to void*, and the result is the same (it just adds 0x at the beginning). – linux Jan 25 '23 at 17:09
  • Since I am not using ASLR, I understand that the program is always being loaded in the same place. This also explains why the results are always the same. How can I get it from the ELF? – linux Jan 25 '23 at 17:11
  • 1
    You can't. It's the OS who is deciding where to place it. – Eugene Sh. Jan 25 '23 at 17:12
  • @WeatherVane when you say virtual, do you refer to logical or linear addresses? – linux Jan 25 '23 at 17:13
  • I mean [logical](https://stackoverflow.com/questions/62997536/what-is-the-difference-between-linear-physical-logical-and-virtual-memory-addr) – Weather Vane Jan 25 '23 at 17:16
  • 1
    @EugeneSh. how does the OS decide the place? – linux Jan 25 '23 at 17:21
  • @linux Depending on the OS I guess. In a simplest case it might have a "hardcoded" memory address which is dedicated for loading PIEs. – Eugene Sh. Jan 25 '23 at 17:43
  • 1
    It is specifically the program loader that sets the addresses, and, with ASLR off, addresses start around 0x555555558000 because somebody divided part of the address space into three parts, and dividing 0x1000…000 by three gives you 0x0x555555555555, which is then rounded up to a page boundary. It is built into the program loader. – Eric Postpischil Jan 25 '23 at 22:11

0 Answers0