无法写入ARM寄存器R4:功能或错误



我最近在Assembly中对ARM Cortex-A8进行编程时遇到了一个奇怪的行为。每当我把任何东西MOV放入R4时,我的程序就会崩溃(下面的堆栈转储(

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  >>> neontests <<<
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

编辑:上面的堆栈转储是以下代码的结果(抱歉,GNU程序集突出显示在这里似乎有点奇怪(:

.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

我从(本机(C调用它如下:

#include <jni.h>
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include <arm_neon.h>
#include <android/log.h>
#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;
}

以下是我注意到的一些事情。首先,每当我将任何东西分配给R4时,无论是MOV R4, #2还是ADD R4, R0, R1,结果都会在程序崩溃之前最终出现在R4中,但同样的结果也总是出现在R0中。我还发现我可以将堆栈中的POP填充到R4中。没有其他寄存器表现出同样的行为。汇编代码使用Android NDK编译,我相信它使用GCC 4.4.3。我在几部安卓手机上测试了它,一切似乎都是一致的。

我知道所有寄存器都是分段的,这样R0-R3接受自变量,R4-R12是可变寄存器,然后还有特殊寄存器等等。也许这种行为是由我从未听说过的某种C调用约定引起的?对此有什么解释吗?

干杯

更新

正如@Graham善意地指出的,r4(或者v1(是一个应该保留的变量寄存器。然而,在他的回答中提供的链接中,ARM文档本身使用了v1寄存器,首先将其结果与另一个保留寄存器的值一起保存在堆栈上:

STMDB sp!,{v1,lr}
LDR v1,[a2,#0]

以及随后检索它们的值。当我编译这个代码时,它和我原来的代码一样崩溃,但

STMDB sp!,{v1,lr}
LDR v2,[a2,#0]

没有(注意v2而不是v1(。

我们试图解释的是,如果您想在函数中使用r4,则需要这样做:

.globl asm_test
asm_test:
    stmdb r13!,{r4}
    mov r0, #4 @make sure r0 is not the same as r4
    mov r4, #1 @move to r4 something different from r0
    ldmia r13!,{r4}
    mov pc, lr @return from function

否则,你会留下一颗定时炸弹,在路上的某个时候爆炸。编译器已经为更高级别的函数中的某些东西分配了r4,根据规则,没有人可以更改该寄存器,这样更高级别调用就不必保护r4,通过在正确的时间和地点将其弄乱,你会产生问题,问题的表现取决于代码。并将解释为什么其他寄存器在这种情况下不敏感。有时,当你这样做的时候,你实际上不会崩溃,有时可能是一个字符串打印错误,或者循环重复或提前退出。

要了解发生了什么,请反汇编有问题的函数(不是源代码,而是反汇编(。加上调用它的函数和调用它直到r4出现在其中一个周围函数中的函数。检查r4的用途。

如果您的asm_test((调用函数具有在asm_est((调用前后使用的局部变量,则您也可以更改行为,这样优化器可以将它们保存在寄存器中,但也不会将代码一起删除:

void fun ( void )
{
  int r;
  r=10;
  asm_test();
  r++;
}

优化器会完全删除上面代码中的r,但是:

int fun ( int a, int b, int c, int d )
{
   int e;
   e=a+b+c+d;
   b=asm_test(a+d);
   e+=b; 
   return(e);
}

创建的内容足以迫使编译器构建堆栈帧。

00000000 <fun>:
   0:   e0811000    add r1, r1, r0
   4:   e92d4010    push    {r4, lr}
   8:   e0830000    add r0, r3, r0
   c:   e0814002    add r4, r1, r2
  10:   e0844003    add r4, r4, r3
  14:   ebfffffe    bl  0 <asm_test>
  18:   e0840000    add r0, r4, r0
  1c:   e8bd8010    pop {r4, pc}

在这种情况下,r4是变量e(围绕asm_test调用(,通过弄乱r4,您将更改函数fun((返回的内容。例如,如果在调用fun时从未使用过该值,那么您对r4的修改将不会被注意到。

编译器遵循调用约定规则,并期望所有被调用方也这样做,如果你搞砸了,它崩溃/失败的方式会从没有效果到非常严重,所以你需要在asm中遵守这些调用约定。

根据APCS,R4是必须保留的寄存器之一。如果您需要使用它,那么在进入时将其存储在堆栈中,在退出时将其再次弹出。有一些寄存器,例如R0-R3,它们是暂存寄存器;你可以在你的日常生活中破坏这些,而不保留它们。

有关从例程返回之前必须保留和恢复哪些寄存器的说明,请参阅文档。

v1-v8,[f4-f7]

这些被用作寄存器变量。它们必须由调用的函数保留。

v1R4的APCS替代名称。

相关内容

  • 没有找到相关文章

最新更新