2011-10-14 2 views
5

私は最近、アセンブリでプログラミングする際に、ARM Cortex-A8の奇妙な動作に遭遇しました。 R4へのI MOV何でも、私のプログラムがクラッシュ(スタック下記ダンプ)ARMレジスタ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をスタックから得ることができることを知った。他のレジスタはこの同じ動作を示しません。 GCC 4.4.3を使用していると思われるAndroid NDKを使用してアセンブリコードをコンパイルします。私はいくつかのAndroidの携帯電話でそれをテストし、すべてが一貫しているようだ。

私はすべてのレジスタがR0〜R3が引数を取り、R4〜R12が可変レジスタであり、特殊レジスタなどがあるようにセクション化されていることを知っています。おそらく、この動作は、私が聞いたことのない何らかのCの呼び出し規約によって引き起こされますか?これについての説明はありますか?

乾杯! =)

更新

@Grahamは親切に指摘したように、R4(あるいはV1)が保存されるべき変数レジスタです。

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

、後でその値を取得する:しかし、彼の答えで提供linkで、ARMのドキュメント自体は、最初に別の保存レジスタの値と一緒にスタック上にその結果を保存することで、V1レジスタを使用しています。このコードをコンパイルすると、オリジナルと同じ方法でクラッシュしますが、

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

(v1ではなくv2に注意してください)。

+0

クラッシュする可能性のある最小限のコードを表示できますか? 'fault addr 00000001'はあなたが' r4'に含まれているアドレスからロードしていることを示唆しています。 'r0 'に現れる同じ結果が奇妙に聞こえる。 – user786653

+0

@ user786653確かに、私の質問を編集する。 – Phonon

+0

私はまだすべての関連コードが表示されていないと感じています。あなたは、この動作を示す自己完結型の例を持っていますか? – user786653

答えて

8

はあなたが機能で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がそれらの周辺機能の1つに現れるまでそれを呼び出す関数とそれを呼び出す関数を追加しました。どのr4が使用されているか調べてください。

asm_test()呼び出し関数が、asm_test()呼び出しの前後に使用されるローカル変数を、オプティマイザがレジスタ内に保持するような方法で使用する場合は、その動作を変更することもできます。

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は(asm_testコールの周りに)この場合、変数eであるとR4めちゃくちゃで、あなたはどのような関数fun()が復帰を変更します。例えば、funへの呼び出しでその値が使用されなかった場合、r4の変更は気付かれなくなります。

コンパイラは呼び出し規約規則に従い、すべての呼び出し先も同様に期待していますが、クラッシュしたり失敗したりする方法が効果がないからかなり深刻なものになるため、これらの呼び出し規約に準拠する必要があります。あなたのasm。

+0

あなたが言っていることは、r4の値を高レベルの関数が期待しないものに変更し、関数が返ってきたときにプログラムがクラッシュするため、クラッシュするということです。正しい? – Phonon

+0

ありがとう、私は今それを得る! – Phonon

7

APCSによれば、R4は、保存する必要があるレジスタの1つです。それを使用する必要がある場合は、エントリのスタックに格納し、終了時に再びポップします。 R0-R3のようないくつかのレジスタがあり、それらはスクラッチレジスタです。あなたはそれらを保存せずにあなたのルーチンの中でこれらを壊すことが許されています。

See the docsあなたのルーチンから戻る前にどのレジスタを保存して復元する必要があるかについては、その説明を参照してください。

V1〜V8、[F4-F7]

これらはレジスタ変数として使用されます。それらは、呼び出された関数によって保持されなければならない。

V1R4用APCSの代替名です。我々が説明しようとしている何

+0

それは本当ですが、それは保存されなければならないという事実クラッシュを説明していない。私は私の答えを更新しました。見てください。 – Phonon

関連する問題