title: Cannot write to ARM register R4: feature or bug?
body: <p>I've recently encountered a strange behaviour of ARM Cortex-A8 when programming it in Assembly. Whenever I <code>MOV</code> anything into R4, my program crashes (stack dump below)</p>
  
  <pre><code>10-14 09:48:43.117: INFO/DEBUG(3048): Build fingerprint: 'google/soju/crespo:2.3.6/GRK39F/189904:user/release-keys'
  10-14 09:48:43.121: INFO/DEBUG(3048): pid: 7082, tid: 7082  &gt;&gt;&gt; neontests &lt;&lt;&lt;
  10-14 09:48:43.121: INFO/DEBUG(3048): signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 00000001
  10-14 09:48:43.125: INFO/DEBUG(3048):  r0 00000001  r1 afa025b6  r2 00000000  r3 bec77051
  10-14 09:48:43.128: INFO/DEBUG(3048):  r4 00000001  r5 bec7704c  r6 00000001  r7 00000004
  10-14 09:48:43.128: INFO/DEBUG(3048):  r8 00000005  r9 00000000  10 4214cca4  fp 800a5368
  10-14 09:48:43.128: INFO/DEBUG(3048):  ip afa03110  sp bec77010  lr afa0133b  pc afd37b42  cpsr 60000030
  10-14 09:48:43.132: INFO/DEBUG(3048):  d0  0000000200000053  d1  0000000400000074
  10-14 09:48:43.132: INFO/DEBUG(3048):  d2  000000060000006f  d3  0000000800000070
  10-14 09:48:43.132: INFO/DEBUG(3048):  d4  006f0065006e002e  d5  007300650074006e
  10-14 09:48:43.136: INFO/DEBUG(3048):  d6  0000000c00000005  d7  0000002000000015
  10-14 09:48:43.136: INFO/DEBUG(3048):  d8  0000000c00000005  d9  0000002000000015
  10-14 09:48:43.140: INFO/DEBUG(3048):  d10 0000000000000000  d11 0000000000000000
  10-14 09:48:43.140: INFO/DEBUG(3048):  d12 0000000000000000  d13 0000000000000000
  10-14 09:48:43.140: INFO/DEBUG(3048):  d14 0000000000000000  d15 0000000000000000
  10-14 09:48:43.144: INFO/DEBUG(3048):  d16 800220e8401644a8  d17 bff0000000000000
  10-14 09:48:43.144: INFO/DEBUG(3048):  d18 3ff0000000000000  d19 0000000000000000
  10-14 09:48:43.148: INFO/DEBUG(3048):  d20 0000000000000000  d21 0000000000000000
  10-14 09:48:43.148: INFO/DEBUG(3048):  d22 3ff0000000000000  d23 0000000000000000
  10-14 09:48:43.148: INFO/DEBUG(3048):  d24 3ff0000000000000  d25 0000000000000000
  10-14 09:48:43.148: INFO/DEBUG(3048):  d26 0000000000000000  d27 0000000000000000
  10-14 09:48:43.148: INFO/DEBUG(3048):  d28 0000000000000000  d29 0000000000000000
  10-14 09:48:43.148: INFO/DEBUG(3048):  d30 0000000000000000  d31 0000000000000000
  10-14 09:48:43.148: INFO/DEBUG(3048):  scr 20000012
  10-14 09:48:43.195: INFO/DEBUG(3048):          #00  pc 00037b42  /system/lib/libc.so
  10-14 09:48:43.195: INFO/DEBUG(3048):          #01  pc 00001338  /system/lib/liblog.so
  10-14 09:48:43.199: INFO/DEBUG(3048):          #02  pc 00001482  /system/lib/liblog.so
  10-14 09:48:43.199: INFO/DEBUG(3048):          #03  pc 00000c54  /data/data/neontests/lib/libneon_tests.so
  10-14 09:48:43.199: INFO/DEBUG(3048):          #04  pc 00017e34  /system/lib/libdvm.so
  10-14 09:48:43.199: INFO/DEBUG(3048):          #05  pc 0004968c  /system/lib/libdvm.so
  10-14 09:48:43.199: INFO/DEBUG(3048):          #06  pc 0004ee62  /system/lib/libdvm.so
  10-14 09:48:43.199: INFO/DEBUG(3048):          #07  pc 0001d034  /system/lib/libdvm.so
  10-14 09:48:43.199: INFO/DEBUG(3048):          #08  pc 000220e4  /system/lib/libdvm.so
  10-14 09:48:43.199: INFO/DEBUG(3048):          #09  pc 00020fdc  /system/lib/libdvm.so
  10-14 09:48:43.199: INFO/DEBUG(3048):          #10  pc 0005fdde  /system/lib/libdvm.so
  10-14 09:48:43.203: INFO/DEBUG(3048):          #11  pc 00067b52  /system/lib/libdvm.so
  10-14 09:48:43.203: INFO/DEBUG(3048):          #12  pc 0001d034  /system/lib/libdvm.so
  10-14 09:48:43.203: INFO/DEBUG(3048):          #13  pc 000220e4  /system/lib/libdvm.so
  10-14 09:48:43.203: INFO/DEBUG(3048):          #14  pc 00020fdc  /system/lib/libdvm.so
  10-14 09:48:43.203: INFO/DEBUG(3048):          #15  pc 0005fc40  /system/lib/libdvm.so
  10-14 09:48:43.203: INFO/DEBUG(3048):          #16  pc 0004c126  /system/lib/libdvm.so
  10-14 09:48:43.203: INFO/DEBUG(3048):          #17  pc 00032572  /system/lib/libandroid_runtime.so
  10-14 09:48:43.203: INFO/DEBUG(3048):          #18  pc 0003341e  /system/lib/libandroid_runtime.so
  10-14 09:48:43.203: INFO/DEBUG(3048):          #19  pc 00008cca  /system/bin/app_process
  10-14 09:48:43.207: INFO/DEBUG(3048):          #20  pc 00014b52  /system/lib/libc.so
  10-14 09:48:43.207: INFO/DEBUG(3048): code around pc:
  10-14 09:48:43.207: INFO/DEBUG(3048): afd37b20 18801889 c003f810 c003f801 d2f93b01 
  10-14 09:48:43.207: INFO/DEBUG(3048): afd37b30 bf00bdf0 2200b510 3201e003 4618b90b 
  10-14 09:48:43.207: INFO/DEBUG(3048): afd37b40 5c83e004 42a35c8c 1b18d0f7 bf00bd10 
  10-14 09:48:43.207: INFO/DEBUG(3048): afd37b50 b152b530 5cc42300 42ac5ccd 1b60d001 
  10-14 09:48:43.207: INFO/DEBUG(3048): afd37b60 b114e004 429a3301 2000d1f5 bf00bd30 
  10-14 09:48:43.207: INFO/DEBUG(3048): code around lr:
  10-14 09:48:43.207: INFO/DEBUG(3048): afa01318 fffffff4 00001e20 b088b570 4615460c 
  10-14 09:48:43.207: INFO/DEBUG(3048): afa01328 b9099001 447c4c28 46204928 f7ff4479 
  10-14 09:48:43.207: INFO/DEBUG(3048): afa01338 2800edc4 4926d02e 22034620 f7ff4479 
  10-14 09:48:43.207: INFO/DEBUG(3048): afa01348 b338edc2 46204923 f7ff4479 b308edb6 
  10-14 09:48:43.207: INFO/DEBUG(3048): afa01358 46204921 f7ff4479 b1d8edb0 4620491f 
  10-14 09:48:43.207: INFO/DEBUG(3048): stack:
  10-14 09:48:43.207: INFO/DEBUG(3048):     bec76fd0  800a5368  
  10-14 09:48:43.207: INFO/DEBUG(3048):     bec76fd4  afd1c701  /system/lib/libc.so
  10-14 09:48:43.207: INFO/DEBUG(3048):     bec76fd8  bec771f0  
  10-14 09:48:43.207: INFO/DEBUG(3048):     bec76fdc  bec77051  
  10-14 09:48:43.207: INFO/DEBUG(3048):     bec76fe0  0000ce60  
  10-14 09:48:43.207: INFO/DEBUG(3048):     bec76fe4  000003fa  
  10-14 09:48:43.207: INFO/DEBUG(3048):     bec76fe8  ffff0208  
  10-14 09:48:43.207: INFO/DEBUG(3048):     bec76fec  bec7704c  
  10-14 09:48:43.207: INFO/DEBUG(3048):     bec76ff0  000003ff  
  10-14 09:48:43.207: INFO/DEBUG(3048):     bec76ff4  00000000  
  10-14 09:48:43.210: INFO/DEBUG(3048):     bec76ff8  00000003  
  10-14 09:48:43.210: INFO/DEBUG(3048):     bec76ffc  00000004  
  10-14 09:48:43.210: INFO/DEBUG(3048):     bec77000  80400d90  /data/data/neontests/lib/libneon_tests.so
  10-14 09:48:43.210: INFO/DEBUG(3048):     bec77004  bec7704c  
  10-14 09:48:43.210: INFO/DEBUG(3048):     bec77008  df002777  
  10-14 09:48:43.210: INFO/DEBUG(3048):     bec7700c  e3a070ad  
  10-14 09:48:43.210: INFO/DEBUG(3048): #00 bec77010  00000001  
  10-14 09:48:43.210: INFO/DEBUG(3048):     bec77014  afa0133b  /system/lib/liblog.so
  10-14 09:48:43.210: INFO/DEBUG(3048): #01 bec77018  80400420  /data/data/neontests/lib/libneon_tests.so
  10-14 09:48:43.210: INFO/DEBUG(3048):     bec7701c  00000004  
  10-14 09:48:43.210: INFO/DEBUG(3048):     bec77020  bec7701c  
  10-14 09:48:43.210: INFO/DEBUG(3048):     bec77024  00000001  
  10-14 09:48:43.210: INFO/DEBUG(3048):     bec77028  80400d90  /data/data/neontests/lib/libneon_tests.so
  10-14 09:48:43.210: INFO/DEBUG(3048):     bec7702c  00000014  
  10-14 09:48:43.210: INFO/DEBUG(3048):     bec77030  00000000  
  10-14 09:48:43.210: INFO/DEBUG(3048):     bec77034  00000000  
  10-14 09:48:43.210: INFO/DEBUG(3048):     bec77038  bec7704c  
  10-14 09:48:43.210: INFO/DEBUG(3048):     bec7703c  afd4d5c8  
  10-14 09:48:43.210: INFO/DEBUG(3048):     bec77040  00000001  
  10-14 09:48:43.210: INFO/DEBUG(3048):     bec77044  afa01487  /system/lib/liblog.so
  </code></pre>
  
  <p><em>Edit</em>: Stack dump above is the result of the following code (apologies, GNU Assembly highlighting seems to be a bit odd here):</p>
  
  <pre><code>.arm
  .global asm_test
  
  asm_test:
  
      mov r0, #4 @make sure r0 is not the same as r4   
      mov r4, #1 @move to r4 something different from r0
  
      mov pc, lr @return from function
  </code></pre>
  
  <p>I'm calling it from (native) C as follows:</p>
  
  <pre><code>#include &lt;jni.h&gt;
  #include &lt;string.h&gt;
  #include &lt;stdint.h&gt;
  #include &lt;stdlib.h&gt;
  #include &lt;arm_neon.h&gt;
  #include &lt;android/log.h&gt;
  #include "com_something_neontests_NativeLib.h"
  
  extern volatile int asm_test(void);
  
  JNIEXPORT jint JNICALL Java_com_something_neontests_NativeLib_asmTry
    (JNIEnv * env, jobject obj)
  {
  
      __android_log_print(ANDROID_LOG_INFO, "com.something.neontests", "Start!");
  
      asm_test();
  
      __android_log_print(ANDROID_LOG_INFO, "com.something.neontests", "Done!");
  
  
      return 0;
  }
  </code></pre>
  
  <p>Here are a few things I notice. First, whenever I assign anything to R4, be it <code>MOV R4, #2</code> or <code>ADD R4, R0, R1</code>, the result <em>does</em> end up in R4 before the program crashes, but the same result also always ends up in R0. I also found out that I can <code>POP</code> stuff from the stack into R4. No other registers exhibit this same behaviour. Assembly code compiles using Android NDK, which I believe uses GCC 4.4.3. I tested it on several Android phones and everything seems to be consistent.</p>
  
  <p>I know that all registers are sectioned such that R0-R3 take in arguments, R4-R12 are variable registers, then there are special registers and so on. Perhaps this behaviour is caused by some sort of C calling convention I've never heard about? Is there an explanation for this, is it expected?</p>
  
  <p>Cheers! = )</p>
  
  <p><em><strong>Update</em></strong>:</p>
  
  <p>As @Graham kindly pointed out, r4 (alternatively v1) is a variable register which should be preserved. However, in the <a href="http://infocenter.arm.com/help/topic/com.arm.doc.dui0040d/ch06s02s01.html" rel="nofollow">link</a> provided in his answer, ARM documentation itself makes use of the v1 register, by first saving its result on the stack along with value of another preserved register:</p>
  
  <pre><code>STMDB sp!,{v1,lr}
  LDR v1,[a2,#0]
  </code></pre>
  
  <p>and later retrieving their values. When I compile this code, it crashes the same way as my original, but</p>
  
  <pre><code>STMDB sp!,{v1,lr}
  LDR v2,[a2,#0]
  </code></pre>
  
  <p>doesn't (notice v2 instead of v1).</p>