2011-10-14 30 views
5

Gần đây tôi đã gặp phải một hành vi kỳ lạ của ARM Cortex-A8 khi lập trình nó trong Assembly. Bất cứ khi nào tôi MOV bất cứ điều gì vào R4, treo chương trình của tôi (chồng đổ dưới)Không thể ghi vào sổ đăng ký ARM R4: tính năng hoặc lỗi?

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 

Sửa: Stack đổ trên là kết quả của đoạn mã sau (xin lỗi, GNU hội làm nổi bật vẻ là một chút kỳ lạ ở đây) :

.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 

tôi gọi đó là từ (bản địa) C như sau:

#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; 
} 

Dưới đây là một vài điều tôi chú ý. Đầu tiên, bất cứ khi nào tôi gán bất kỳ thứ gì cho R4, có thể là MOV R4, #2 hoặc ADD R4, R0, R1, kết quả làm kết thúc bằng R4 trước khi chương trình gặp sự cố, nhưng kết quả tương tự cũng luôn kết thúc bằng R0. Tôi cũng phát hiện ra rằng tôi có thể POP nội dung từ ngăn xếp vào R4. Không có đăng ký nào khác thể hiện hành vi tương tự này. Biên dịch mã hội sử dụng Android NDK, mà tôi tin rằng sử dụng GCC 4.4.3. Tôi đã thử nghiệm nó trên một số điện thoại Android và tất cả mọi thứ có vẻ là nhất quán.

Tôi biết rằng tất cả các thanh ghi được phân đoạn sao cho R0-R3 thực hiện các đối số, R4-R12 là các thanh ghi biến, sau đó có các thanh ghi đặc biệt và vv. Có lẽ hành vi này là do một số loại C gọi quy ước tôi đã không bao giờ nghe nói về? Có một lời giải thích cho điều này, là nó mong đợi?

Chúc mừng! =)

Cập nhật:

Như @Graham vui lòng chỉ ra, R4 (hoặc v1) là một thanh ghi biến mà cần được bảo tồn. Tuy nhiên, trong link cung cấp trong câu trả lời của mình, ARM tài liệu chính nó làm cho việc sử dụng đăng ký v1, bằng cách đầu tiên tiết kiệm kết quả của nó trên stack cùng với giá trị của người khác đăng ký bảo quản:

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

và sau đó lấy giá trị của họ. Khi tôi biên dịch mã này, mã này bị treo giống như cách ban đầu của tôi, nhưng

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

không (thông báo v2 thay vì v1).

+0

Bạn có thể hiển thị mã nhỏ nhất có thể bị lỗi không? 'fault addr 00000001' dường như gợi ý rằng bạn đang tải từ địa chỉ chứa trong' r4'. Kết quả tương tự hiển thị trong 'r0' âm thanh lẻ. – user786653

+0

@ user786653 Chắc chắn, đang chỉnh sửa câu hỏi của tôi. – Phonon

+0

Tôi vẫn có cảm giác rằng chúng tôi không hiển thị tất cả các mã có liên quan. Bạn có một ví dụ khép kín thể hiện hành vi này? – user786653

Trả lời

8

gì chúng tôi đang cố gắng để giải thích là bạn cần phải làm điều này nếu bạn muốn sử dụng R4 trong một chức năng:

.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 

Nếu không, bạn để lại một quả bom hẹn giờ mà đi ra tại một số điểm xuống đường. Trình biên dịch đã cấp phát R4 cho một thứ gì đó ở mức cao hơn, và bởi quy tắc không ai có thể thay đổi thanh ghi đó để cuộc gọi cấp cao hơn không phải bảo vệ r4, bằng cách sửa nó vào đúng thời điểm và đặt bạn tạo ra vấn đề, cách vấn đề hoạt động là phụ thuộc vào mã. Và sẽ giải thích tại sao các thanh ghi khác, trong trường hợp này, không nhạy cảm. Đôi khi khi bạn làm điều này bạn sẽ không thực sự sụp đổ, đôi khi có lẽ một chuỗi được in sai hoặc lặp lại lặp lại chính nó hoặc thoát ra sớm.

Để xem điều gì đang xảy ra, vui lòng tháo rời chức năng được đề cập (không phải mã nguồn nhưng tháo gỡ). cộng với các hàm gọi là nó và các hàm được gọi cho đến khi r4 xuất hiện ở một trong những hàm xung quanh đó. kiểm tra những gì r4 đang được sử dụng cho. Bạn cũng có thể thay đổi hành vi nếu hàm asm_test() của bạn có các biến cục bộ được sử dụng trước và sau cuộc gọi asm_test() theo cách mà trình tối ưu hóa giữ chúng trong sổ đăng ký, nhưng cũng như vậy ưu không loại bỏ mã tất cả cùng nhau:

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

các ưu hoàn toàn có thể loại bỏ r trong đoạn mã trên, nhưng:

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); 
} 

tạo ra nhiều hơn, đủ để buộc các trình biên dịch để xây dựng một khung stack.

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 là biến e trong trường hợp này (xung quanh cuộc gọi asm_test) và bằng cách làm rối r4 bạn sẽ thay đổi hàm fun() trả về. Nếu giá trị đó không bao giờ được sử dụng trên các cuộc gọi để vui vẻ ví dụ như sửa đổi của bạn của R4 sẽ không được chú ý. Các trình biên dịch tuân theo quy tắc quy ước gọi và mong đợi tất cả các callees là tốt, nếu bạn mess với những cách mà nó có thể sụp đổ/thất bại đi từ không có hiệu lực đến khá nghiêm trọng, vì vậy bạn cần phải phù hợp với những quy ước gọi điện thoại trong asm của bạn.

+0

Những gì bạn đang nói là nó bị treo vì tôi đã thay đổi giá trị của r4 thành một chức năng cấp cao hơn không mong đợi, và chương trình bị treo khi chức năng của tôi đã trở lại. Chính xác? – Phonon

+0

Cảm ơn, giờ tôi đã hiểu! – Phonon

7

Theo APCS, R4 là một trong những thanh ghi mà bạn phải bảo toàn. Nếu bạn cần sử dụng nó, sau đó lưu trữ nó trên ngăn xếp trên mục nhập, và bật nó ra một lần nữa khi thoát. Có một số thanh ghi, chẳng hạn như R0-R3, là các thanh ghi cào; bạn được phép tham nhũng những thứ này bên trong thói quen của bạn mà không cần bảo quản chúng.

See the docs để biết mô tả đăng ký, bạn phải giữ lại và khôi phục trước khi trở về thường lệ.

v1-v8, [f4-f7]

Chúng được sử dụng như là các biến đăng ký. Chúng phải được bảo toàn bằng các hàm được gọi.

v1 là tên thay thế APCS cho R4.

+0

Đó là tất cả sự thật, nhưng thực tế là nó phải được bảo tồn không giải thích sự cố. Tôi cập nhật câu trả lời của tôi, xin vui lòng có một cái nhìn. – Phonon

Các vấn đề liên quan