title: Branching in Arm Assembly
body: <p>I'm using the GNU ARM toolchain (arm-elf-gcc). I have one assembly file and one c file that calls global methods defined in the assembly file. I can successfully call a single assembly method from c, but I cannot figure out how to call an assembly method that itself calls another assembly method. I'd like both assembly methods to be callable from c and be in the same file.</p>
  
  <p>Here are the two file. When I run the program, it never returns, so I know there's a problem in the branching.</p>
  
  <p><strong>mathLib.s</strong></p>
  
  <pre><code>@ ARM Assembler Library for absolute value
  
      .align 2                    @ Align to word boundary
      .arm                        @ This is ARM code
      .global asm_abs             @ This makes it a real symbol
      .global asm_two_abs         @ This makes it a real symbol
  
  @ ABS Func. Compiler just does "rsblt   r0, r0, #0" but this is more fun.
      asm_abs:                        @ Start of function definition
          mov     r2, #1              @ Set the least bit high in r2
          mov     r2, r2, lsl#31      @ Shift that bit all the way to the sign slot
          orr     r2, r2, r0          @ XOR with input (r0) to set ensure negative
          cmp     r2, r0              @ compare a for-sure neg input with input
          bne     asm_abs_ret         @ if not equal, input was pos, so return
          sub     r0, r0, r0, lsl#1   @ else set input = input - (2*input)
      asm_abs_ret:
          mov     pc, lr              @ Set program counter to lr (was set by caller)
  
      asm_two_abs:                        @ Start of function definition
          bl      asm_abs                 @ Should set r0 = abs(r0)
          mov     r2, r0                  @ set r2 = r0
          mov     r0, r1                  @ set r0 = r1
          bl      asm_abs                 @ Should set r0 = abs(r0)
          add     r0, r0, r2              @ set r0 = r0 + r2  
          mov     pc, lr                  @ Set program counter to lr (was set by caller)
  </code></pre>
  
  <p><strong>program.c</strong></p>
  
  <pre><code>#include &lt;stdio.h&gt;
  #include &lt;stdlib.h&gt;
  
  int main(int argc, char *argv[])
  {
      extern int asm_abs(int a);
      extern int asm_two_abs(int a, int b);
  
      int m = atoi(argv[1]);
      int n = atoi(argv[2]);
      int r = asm_two_abs(m, n); 
  
      printf("%d\n", r);
  
      return 0;
  }
  </code></pre>
  
  <p><strong>EDIT</strong></p>
  
  <p>Here is what I came up with in the end</p>
  
  <pre><code>@ ARM Assembler Library for absolute value
  
      .align 2                    @ Align to word boundary
      .arm                        @ This is ARM code
      .global asm_abs             @ This makes it a real symbol
      .global asm_mod             @ This makes it a real symbol
  
  
  @ ABS Func. Compiler just does "rsblt   r0, r0, #0" but this is more fun.
  @int asm_abs(int a)
  
  asm_abs:                        @ start of function definition
      mov     r2, #1              @ set the least bit high in r2
      mov     r2, r2, lsl#31      @ shift that bit all the way to the sign slot
      orr     r2, r2, r0          @ XOR with input a (r0) to set ensure negative
      cmp     r2, r0              @ compare a for-sure neg input with input a
      bne     asm_abs_ret         @ if not equal, input was pos, so return
      sub     r0, r0, r0, lsl#1   @ else set a = a - (2*a)
  asm_abs_ret:
      mov     pc, lr              @ set program counter to lr (was set by caller)
  
  @ Take two numbers, and return abs(a) + abs(b)
  @ int asm_two_abs(int a, int b)
  
  asm_two_abs:                        @ start of function definition
      stmfd   sp!, {r4-r6}        @ push the non-scratch registers we'll use on the stack
      mov     r4, lr              @ store link register in r4
      mov     r6, r1              @ store second argument b in r6
      bl      asm_abs             @ set a (r0) = abs(a)
      mov     r5, r0              @ store abs(a) in r5
      mov     r0, r6              @ set r0 = b
      bl      asm_abs             @ should set b = abs(b)
      add     r0, r0, r5          @ set r0 = abs(b) + abs(a)  
      mov     lr, r4              @ restore link register
      ldmfd   sp!, {r4-r6}        @ restore non-scratch registers we used
      mov     pc, lr              @ set program counter to lr (was set by caller)
  </code></pre>