title: Memory mapping and variable location of shared library compiled with -fPIC
body: <p>I am using a Linux box and I want to figure out the addresses of symbols inside a Position-Independent-Code shared library during runtime, now I can achieve that according to some observation, however, I still have some questions about the program/library loading (yeah, I know how but I don't know why). Assume we have the following two C source files:</p>
  
  <pre><code>// file: main.c
  #include &lt;stdio.h&gt;
  
  extern int global_field;
  void main() {
      printf("global field(%p) = %d\n", &amp;global_field, global_field);
  }
  
  // file: lib.c
  int global_field = 1;
  </code></pre>
  
  <p>And we compile the above code with follow command:</p>
  
  <pre><code>gcc -fPIC -g -c lib.c -o lib.o      # note the -fPIC flag here
  gcc -fPIC -g -c main.c -o main.o    # note the -fPIC flag here
  gcc -shared -o lib.so lib.o
  gcc -o main main.o ./lib.so
  </code></pre>
  
  <p>And <code>readelf -sW lib.so</code> shows the <code>global_field</code> symbol:</p>
  
  <pre><code>Num:    Value          Size Type    Bind   Vis      Ndx Name
    ...
    8: 0000000000201028     4 OBJECT  GLOBAL DEFAULT   21 global_field
    ...
  </code></pre>
  
  <p>And <code>readelf -lW lib.so</code> outputs the following program headers:</p>
  
  <pre><code>...
  Program Headers:
    Type           Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
    LOAD           0x000000 0x0000000000000000 0x0000000000000000 0x00065c 0x00065c R E 0x200000
    LOAD           0x000df8 0x0000000000200df8 0x0000000000200df8 0x000234 0x000238 RW  0x200000
    DYNAMIC        0x000e18 0x0000000000200e18 0x0000000000200e18 0x0001c0 0x0001c0 RW  0x8
    NOTE           0x000190 0x0000000000000190 0x0000000000000190 0x000024 0x000024 R   0x4
    GNU_STACK      0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW  0x10
    GNU_RELRO      0x000df8 0x0000000000200df8 0x0000000000200df8 0x000208 0x000208 R   0x1
  </code></pre>
  
  <p>And now we run the program, it outputs the following:</p>
  
  <pre><code>global field(0x7ffff7dda028) = 1
  </code></pre>
  
  <p>And <code>cat /proc/&lt;pid&gt;/maps</code> outputs the following:</p>
  
  <pre><code>...
  7ffff7bd9000-7ffff7bda000 r-xp 00000000 fd:02 18650951    /.../lib.so
  7ffff7bda000-7ffff7dd9000 ---p 00001000 fd:02 18650951    /.../lib.so
  7ffff7dd9000-7ffff7dda000 r--p 00000000 fd:02 18650951    /.../lib.so
  7ffff7dda000-7ffff7ddb000 rw-p 00001000 fd:02 18650951    /.../lib.so
  ...
  </code></pre>
  
  <p>Sorry it's a little too much code here... Now my questions are:</p>
  
  <ol>
  <li><p>As you see, there are <strong>TWO</strong> <code>LOAD</code> segments in program headers, but there are <strong>FOUR</strong> memory mappings, why there are two more mappings?</p></li>
  <li><p>For the two <code>LOAD</code> segments, how to figure out which segment maps to which memory region? Is there any standard or any manual?</p></li>
  <li><p>the symbol <code>global_field</code>'s value is <code>0000000000201028</code> (see the output of <code>readelf -sW lib.so</code>), however, according to the ELF standard:</p></li>
  </ol>
  
  <blockquote>
    <p><strong>In executable and shared object files, <code>st_value</code> holds a virtual address</strong>. To make these files' symbols more useful for the runtime
    linker, the section offset (file interpretation) gives way to a
    virtual address (memory interpretation) for which the section number
    is irrelevant.</p>
  </blockquote>
  
  <p>I know this is Position-Independent-Code, it CANNOT be virtual address and MUST be some kind of offset. Subtract <code>global_field</code>'s address with the symbol's value: <code>0x7ffff7dda028 - 0x201028 = 0x7ffff7bd9000</code>, it seems that the offset is based on the beginning address of the lowest memory mapping (see the output of <code>cat /proc/&lt;pid&gt;/maps</code>). However, is there any standard telling us that, how to detect the symbols' value type (virtual address or offset) programmatically? And if it's an offset, why should the offset base on that and why doesn't it base on its own memory region (I guess its own region is the last one, as it has the write permission)?</p>