2011-10-14 63 views
5

在Assembly中編程時,我最近遇到了ARM Cortex-A8的奇怪行爲。每當我MOV任何東西到R4,我的程序崩潰(堆棧轉儲以下)無法寫入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, #2ADD R4, R0, R1,結果確實結束了在R4的程序崩潰之前,但同樣的結果也始終在R0結束。我也發現,我可以從堆棧中的東西POP到R4。沒有其他寄存器顯示相同的行爲。彙編代碼使用Android NDK編譯,我相信它使用GCC 4.4.3。我在幾款Android手機上進行了測試,一切似乎都一致。

我知道,所有的寄存器分段,使得R0-R3參加爭論,R4-R12是可變的寄存器,然後有特殊寄存器等。也許這種行爲是由我從未聽說過的某種C調用慣例造成的?有沒有對此的解釋,是否預期?

乾杯! =)

更新

作爲@Graham麻煩指出,R4(或者V1)是一個應該被保留的可變寄存器。然而,在他的回答中提供的link,ARM文檔本身利用了V1寄存器,通過與另一保存寄存器的值一起先保存在棧上的結果:

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

後來檢索它們的值。當我編譯此代碼時,它與我的原始代碼一樣崩潰,但是

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

不(注意v2而不是v1)。

+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出現在其中一個周圍的函數中。檢查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是在這種情況下,變量e(圍繞asm_test調用)和搞亂R4你會有什麼變化的函數fun()返回。如果這個值從未用於有趣的調用,例如您對r4的修改將不被注意。

編譯器遵循調用約定的規則,並期望所有被調用者也如此,如果你搞砸了它可能崩潰/失敗的方式從無效果變爲非常嚴重,所以你需要符合那些調用約定你的asm。

+0

你說的是它崩潰了,因爲我改變了r4的值到一個更高級別的函數不期望的東西,並且當我的函數返回時程序崩潰。正確? – Phonon

+0

謝謝,我現在明白了! – Phonon

7

據APCS,R4是必須保留的寄存器中的一個。如果您需要使用它,則在入口處將其存儲在堆棧中,並在退出時再次彈出。有一些寄存器,如R0-R3,它們是臨時寄存器;你可以在日常生活中腐蝕這些東西,而不必保存它們。

See the docs爲其寄存器必須從您的例程返回之前保護和恢復的說明。

V1-V8,[F4-F7]

這些被用作寄存器變量。它們必須通過所謂的功能來保存。

V1R4的APCS的替代名稱。

+0

這都是事實,但它必須保留的事實確實如此不解釋崩潰。我更新了我的答案,請看看。 – Phonon