title: GNU as: how to load a .bss/.data symbol to a register?
body: <p>My problem is very basic. I'm making my first bare-metal program in assembler. The architecture is ARMv7-M and I'm using GNU as and I'm writing in UAL.</p>
  
  <p>I have a variable in .bss (or .data, doesn't matter) declared as follows:</p>
  
  <pre><code>.lcomm a_variable, 4
  </code></pre>
  
  <p>Then I want to read its value somewhere in the program. For that I first load its address into a register and then load the value of the variable itself into another register:</p>
  
  <pre><code>adr     r0, a_variable
  ldr     r1, [r0, #0]
  </code></pre>
  
  <p>So far so good. The compiled object contains my <em>a_variable</em> symbol:</p>
  
  <pre><code>00000000 b a_variable
  </code></pre>
  
  <p>And the generated instructions look like this:</p>
  
  <pre><code>0:  f2af 0004   subw    r0, pc, #4
  4:  6801        ldr     r1, [r0, #0]
  </code></pre>
  
  <p><strong>The problem</strong> begins when I want to link the object into resulting image. ld relocates <em>a_variable</em> symbol into the final .bss section at a new address:</p>
  
  <pre><code>20001074 b a_variable
  </code></pre>
  
  <p>But the final code <strong>remains the same</strong> and the program really tries to read <em>a_variable</em> from address 0x0 but not from 0x20001074.</p>
  
  <p>I expect that ld somehow substitutes the new address because it seems to do so when you link objects compiled by GCC. I mean if I write a piece of C code doing something similar:</p>
  
  <pre><code>static int a_variable;
  void foo(void)
  {
      a_variable = 5;
  }
  </code></pre>
  
  <p>...then I get the following instructions in the object file:</p>
  
  <pre><code>0:  f240 0300   movw    r3, #0
  4:  f2c0 0300   movt    r3, #0
  8:  2005        movs    r0, #5
  a:  6018        str r0, [r3, #0]
  </code></pre>
  
  <p>...but the final image looks like this:</p>
  
  <pre><code>800c:       f242 338c       movw    r3, #9100       ; 0x238c
  8010:       f2c0 0301       movt    r3, #1
  8014:       2005            movs    r0, #5
  8016:       6018            str     r0, [r3, #0]
  </code></pre>
  
  <p>So ld appears to have substituted the real address for the placeholder which as left.</p>
  
  <p>My question is why doesn't this work in case of hand-written assembler code? What do I miss?</p>