編輯:關於Android編程
0x00
這一節我們主要討論對象的拷貝構造函數的匯編實現。
0x01
我們直接看C++代碼:
Test.h:
#ifndef _TEST_H_ #define _TEST_H_ #include #define LOG_TAG "lesson5" #define ALOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) class Test { public: Test(); Test(int num); Test(const Test& other); void Display(); ~Test(); public: int num_; }; #endif// _TEST_H_
Test.cpp:
#include"Test.h" Test::Test() : num_(0) { //num_ = 0; ALOGD("Initializing Default\n"); } Test::Test(int num) : num_(num) { //num_ = num; ALOGD("Initializing:%d\n", num_); } Test::Test(const Test& other) : num_(other.num_) { //num_ = other.num_; ALOGD("Initializing with other:%d\n", num_); } Test::~Test() { ALOGD("Destroy:%d\n", num_); } void Test::Display() { ALOGD("num=:%d\n", num_); }Lesson5.cpp:
#include "com_example_ndkreverse5_Lesson5.h" #include "Test.h" Test TestFun(Test t) { t.num_=12; return t; } Test& TestFun2(Test t) { return t; } Test TestFun3(Test& t) { return t; } Test& TestFun4(Test& t) { return t; } JNIEXPORT void JNICALL Java_com_example_ndkreverse5_Lesson5_main (JNIEnv * env, jobject jobject) { Test t(10); Test t2 = TestFun(t); ALOGD("........\n"); }
0x02
下面我們使用ida來打開so,對匯編代碼做出解釋。
.text:00001010 EXPORT Java_com_example_ndkreverse5_Lesson5_main .text:00001010 Java_com_example_ndkreverse5_Lesson5_main .text:00001010 .text:00001010 var_C = -0xC .text:00001010 var_8 = -8 .text:00001010 .text:00001010 PUSH {R4-R7,LR} .text:00001012 LDR R4, =(__stack_chk_guard_ptr - 0x101C) .text:00001014 SUB SP, SP, #0x14 ;開辟20個字節的堆棧空間,sp指向堆棧的首地址 .text:00001016 ADD R6, SP, #0x14+var_C ;堆棧的首地址+8賦值給R6 .text:00001018 ADD R4, PC ; __stack_chk_guard_ptr .text:0000101A LDR R4, [R4] ; __stack_chk_guard .text:0000101C MOVS R1, #0xA ;R1為初始化值10 .text:0000101E LDR R3, [R4] .text:00001020 MOV R0, SP ;R0被賦值為堆棧的首地址 .text:00001022 STR R3, [SP,#0x14+var_8] ;把棧保護信息的值存入堆棧的首地址+0xC指向的空間 .text:00001024 ADD R7, SP, #4 ;R7被賦值為堆棧的首地址+4 .text:00001026 BL _ZN4TestC2Ei ; Test::Test(int) ;R0,R1是傳入構造函數的兩個參數,調用構造函數 .text:0000102A MOV R1, SP ;R1被賦值為堆棧的首地址 .text:0000102C MOVS R0, R6 ;R0被賦值為堆棧的首地址+8 .text:0000102E BL _ZN4TestC2ERKS_ ; Test::Test(Test const&) ;第一次調用拷貝構造函數 .text:00001032 MOVS R1, R6 ;R1被賦值為堆棧的首地址+8 .text:00001034 MOVS R0, R7 ;R0被賦值為堆棧的首地址+4 .text:00001036 BL _Z7TestFun4Test ; TestFun(Test) ;調用了TestFun函數 .text:0000103A MOVS R0, R6 ; this ;R0被賦值為堆棧的首地址+8 .text:0000103C BL _ZN4TestD2Ev ; Test::~Test() ;第一次調用析構函數 .text:00001040 LDR R1, =(aLesson5 - 0x104C) .text:00001042 LDR R2, =(a________ - 0x104A) .text:00001044 MOVS R0, #3 .text:00001046 ADD R2, PC ; "........\n" .text:00001048 ADD R1, PC ; "lesson5" .text:0000104A BL j_j___android_log_print .text:0000104E MOVS R0, R7 ; this ;R0被賦值為堆棧的首地址+4 .text:00001050 BL _ZN4TestD2Ev ; Test::~Test() ;第二次調用構造函數 .text:00001054 MOV R0, SP ; this ;R0被賦值為堆棧的首地址 .text:00001056 BL _ZN4TestD2Ev ; Test::~Test() .text:0000105A LDR R2, [SP,#0x14+var_8] .text:0000105C LDR R3, [R4] .text:0000105E CMP R2, R3 .text:00001060 BEQ loc_1066 .text:00001062 BL j_j___stack_chk_fail .text:00001066 ; --------------------------------------------------------------------------- .text:00001066 .text:00001066 loc_1066 ; CODE XREF: Java_com_example_ndkreverse5_Lesson5_main+50j .text:00001066 ADD SP, SP, #0x14 .text:00001068 POP {R4-R7,PC}調用構造函數:
.text:0000109C ; Test::Test(int) .text:0000109C EXPORT _ZN4TestC2Ei .text:0000109C _ZN4TestC2Ei ; CODE XREF: Java_com_example_ndkreverse5_Lesson5_main+16p .text:0000109C PUSH {R4,LR} .text:0000109E MOVS R4, R0 ;R4被賦值為堆棧的首地址 .text:000010A0 MOVS R3, R1 ;R3被賦值為初始化值10 .text:000010A2 STR R1, [R4] ;把10賦值給堆棧的首地址所指向的內存單元 .text:000010A4 LDR R2, =(aInitializingD - 0x10B0) .text:000010A6 LDR R1, =(aLesson5 - 0x10AE) .text:000010A8 MOVS R0, #3 .text:000010AA ADD R1, PC ; "lesson5" .text:000010AC ADD R2, PC ; "Initializing:%d\n" .text:000010AE BL j_j___android_log_print .text:000010B2 MOVS R0, R4 .text:000010B4 POP {R4,PC}第一次調用拷貝構造函數:
.text:000010C0 ; Test::Test(Test const&) .text:000010C0 EXPORT _ZN4TestC2ERKS_ .text:000010C0 _ZN4TestC2ERKS_ ; CODE XREF: TestFun(Test)+8p .text:000010C0 ; TestFun3(Test &)+4p ... .text:000010C0 PUSH {R4,LR} .text:000010C2 MOVS R4, R0 ;R4被賦值為堆棧的首地址+8 .text:000010C4 LDR R3, [R1] ;把堆棧首地址的內容也就是初始化值10賦值給R3 .text:000010C6 LDR R2, =(aInitializingWi - 0x10D0) .text:000010C8 LDR R1, =(aLesson5 - 0x10D2) .text:000010CA STR R3, [R0] ;把10賦值給堆棧的首地址+8所執行的內存單元 .text:000010CC ADD R2, PC ; "Initializing with other:%d\n" .text:000010CE ADD R1, PC ; "lesson5" .text:000010D0 MOVS R0, #3 .text:000010D2 BL j_j___android_log_print .text:000010D6 MOVS R0, R4 .text:000010D8 POP {R4,PC}調用Testfun函數:
.text:00000FF0 ; TestFun(Test) .text:00000FF0 EXPORT _Z7TestFun4Test .text:00000FF0 _Z7TestFun4Test ; CODE XREF: Java_com_example_ndkreverse5_Lesson5_main+26p .text:00000FF0 MOVS R3, #0xC ;R3被賦值為12 .text:00000FF2 PUSH {R4,LR} .text:00000FF4 MOVS R4, R0 ;R4被賦值為堆棧的首地址+4 .text:00000FF6 STR R3, [R1] ;12被賦值為堆棧的首地址+8所指向的內存單元 .text:00000FF8 BL _ZN4TestC2ERKS_ ; Test::Test(Test const&) ;第二次調用拷貝構造函數,R0為堆棧的首地址+4,R1為堆棧的首地址+8 .text:00000FFC MOVS R0, R4 .text:00000FFE POP {R4,PC}第二次調用拷貝構造函數:
.text:000010C0 ; Test::Test(Test const&) .text:000010C0 EXPORT _ZN4TestC2ERKS_ .text:000010C0 _ZN4TestC2ERKS_ ; CODE XREF: TestFun(Test)+8p .text:000010C0 ; TestFun3(Test &)+4p ... .text:000010C0 PUSH {R4,LR} .text:000010C2 MOVS R4, R0 ;R4被賦值為堆棧的首地址+4 .text:000010C4 LDR R3, [R1] ;把堆棧首地址+8的內容也就是12賦值給R3 .text:000010C6 LDR R2, =(aInitializingWi - 0x10D0) .text:000010C8 LDR R1, =(aLesson5 - 0x10D2) .text:000010CA STR R3, [R0] ;把12賦值給堆棧的首地址+4所執行的內存單元 .text:000010CC ADD R2, PC ; "Initializing with other:%d\n" .text:000010CE ADD R1, PC ; "lesson5" .text:000010D0 MOVS R0, #3 .text:000010D2 BL j_j___android_log_print .text:000010D6 MOVS R0, R4 ;把對象的地址(堆棧的首地址+4)返回去 .text:000010D8 POP {R4,PC}第一次調用析構函數:
.text:000010E4 ; _DWORD __fastcall Test::~Test(Test *__hidden this) .text:000010E4 EXPORT _ZN4TestD2Ev .text:000010E4 _ZN4TestD2Ev ; CODE XREF: Java_com_example_ndkreverse5_Lesson5_main+2Cp .text:000010E4 ; Java_com_example_ndkreverse5_Lesson5_main+40p ... .text:000010E4 PUSH {R4,LR} .text:000010E6 MOVS R4, R0 ;R4被賦值為堆棧的首地址+8 .text:000010E8 LDR R1, =(aLesson5 - 0x10F2) .text:000010EA LDR R2, =(aDestroyD - 0x10F4) .text:000010EC LDR R3, [R4] ;堆棧的首地址+8所指向的內存單元值12賦值給R3 .text:000010EE ADD R1, PC ; "lesson5" .text:000010F0 ADD R2, PC ; "Destroy:%d\n" .text:000010F2 MOVS R0, #3 .text:000010F4 BL j_j___android_log_print .text:000010F8 MOVS R0, R4 .text:000010FA POP {R4,PC}總結:一共生成了三個對象,第一個對象存儲在堆棧首地址所指向的內存中,第二個對象存儲在堆棧首地址+8所指向的內存中,第三個對象存儲在堆棧的首地址+4所指向的內存中。析構時,當從Testfun函數返回時,首先析構了第二個對象,從main函數返回時,先析構了第三個對象,最後析構了第一個對象。
0x03
如果Lesson5.cpp,Java_com_example_ndkreverse5_Lesson5_main調用的函數變成如下的形式:
#include "com_example_ndkreverse5_Lesson5.h" #include "Test.h" Test TestFun(Test t) { t.num_=12; return t; } Test& TestFun2(Test t) { return t; } Test TestFun3(Test& t) { return t; } Test& TestFun4(Test& t) { return t; } JNIEXPORT void JNICALL Java_com_example_ndkreverse5_Lesson5_main (JNIEnv * env, jobject jobject) { Test t(10); TestFun(t); ALOGD("........\n"); }那麼打印出的log為:
D/lesson5 ( 4437): Initializing:10 D/lesson5 ( 4437): Initializing with other:10 D/lesson5 ( 4437): Initializing with other:12 D/lesson5 ( 4437): Destroy:12 D/lesson5 ( 4437): Destroy:12 D/lesson5 ( 4437): ........ D/lesson5 ( 4437): Destroy:10匯編代碼有什麼不同呢?
.text:00001010 EXPORT Java_com_example_ndkreverse5_Lesson5_main .text:00001010 Java_com_example_ndkreverse5_Lesson5_main .text:00001010 .text:00001010 var_10 = -0x10 .text:00001010 var_8 = -8 .text:00001010 .text:00001010 PUSH {R4-R7,LR} .text:00001012 LDR R4, =(__stack_chk_guard_ptr - 0x101C) .text:00001014 SUB SP, SP, #0x14 .text:00001016 ADD R6, SP, #0x14+var_10 .text:00001018 ADD R4, PC ; __stack_chk_guard_ptr .text:0000101A LDR R4, [R4] ; __stack_chk_guard .text:0000101C MOVS R1, #0xA .text:0000101E LDR R3, [R4] .text:00001020 MOV R0, SP .text:00001022 STR R3, [SP,#0x14+var_8] .text:00001024 ADD R7, SP, #8 .text:00001026 BL _ZN4TestC2Ei ; Test::Test(int) .text:0000102A MOV R1, SP .text:0000102C MOVS R0, R6 .text:0000102E BL _ZN4TestC2ERKS_ ; Test::Test(Test const&) .text:00001032 MOVS R1, R6 .text:00001034 MOVS R0, R7 .text:00001036 BL _Z7TestFun4Test ; TestFun(Test) .text:0000103A MOVS R0, R7 ; this .text:0000103C BL _ZN4TestD2Ev ; Test::~Test() .text:00001040 MOVS R0, R6 ; this .text:00001042 BL _ZN4TestD2Ev ; Test::~Test() .text:00001046 LDR R1, =(aLesson5 - 0x1052) .text:00001048 LDR R2, =(a________ - 0x1050) .text:0000104A MOVS R0, #3 .text:0000104C ADD R2, PC ; "........\n" .text:0000104E ADD R1, PC ; "lesson5" .text:00001050 BL j_j___android_log_print .text:00001054 MOV R0, SP ; this .text:00001056 BL _ZN4TestD2Ev ; Test::~Test() .text:0000105A LDR R2, [SP,#0x14+var_8] .text:0000105C LDR R3, [R4] .text:0000105E CMP R2, R3 .text:00001060 BEQ loc_1066 .text:00001062 BL j_j___stack_chk_fail .text:00001066 ; --------------------------------------------------------------------------- .text:00001066 .text:00001066 loc_1066 ; CODE XREF: Java_com_example_ndkreverse5_Lesson5_main+50j .text:00001066 ADD SP, SP, #0x14 .text:00001068 POP {R4-R7,PC}一切都一樣,唯一不同的是由於沒有TestFun(t);沒有接管的對象,所以從TestFun函數執行完,這兩個對象就析構了。
0x04
如果Lesson5.cpp,Java_com_example_ndkreverse5_Lesson5_main調用的函數變成如下的形式:
#include "com_example_ndkreverse5_Lesson5.h" #include "Test.h" Test TestFun(Test t) { t.num_=12; return t; } Test& TestFun2(Test t) { return t; } Test TestFun3(Test& t) { return t; } Test& TestFun4(Test& t) { return t; } JNIEXPORT void JNICALL Java_com_example_ndkreverse5_Lesson5_main (JNIEnv * env, jobject jobject) { Test t(10); Test t2 = TestFun2(t); ALOGD("........\n"); }
那麼log輸出如下:
D/lesson5 ( 4841): Initializing:10 D/lesson5 ( 4841): Initializing with other:10 D/lesson5 ( 4841): Initializing with other:10 D/lesson5 ( 4841): Destroy:10 D/lesson5 ( 4841): ........ D/lesson5 ( 4841): Destroy:10 D/lesson5 ( 4841): Destroy:10匯編代碼有什麼不同呢?
.text:00001010 EXPORT Java_com_example_ndkreverse5_Lesson5_main .text:00001010 Java_com_example_ndkreverse5_Lesson5_main .text:00001010 .text:00001010 var_24 = -0x24 .text:00001010 var_20 = -0x20 .text:00001010 var_1C = -0x1C .text:00001010 .text:00001010 PUSH {R4-R7,LR} .text:00001012 LDR R4, =(__stack_chk_guard_ptr - 0x101C) .text:00001014 SUB SP, SP, #0x14 .text:00001016 ADD R6, SP, #0x28+var_20 .text:00001018 ADD R4, PC ; __stack_chk_guard_ptr .text:0000101A LDR R4, [R4] ; __stack_chk_guard .text:0000101C MOVS R1, #0xA .text:0000101E LDR R3, [R4] .text:00001020 MOV R0, SP .text:00001022 STR R3, [SP,#0x28+var_1C] .text:00001024 BL _ZN4TestC2Ei ; Test::Test(int) ;在堆棧首地址處生成第一個對象 .text:00001028 MOV R1, SP .text:0000102A MOVS R0, R6 .text:0000102C BL _ZN4TestC2ERKS_ ; Test::Test(Test const&) ;在堆棧首地址+8處生成第二個對象 .text:00001030 MOVS R0, R6 .text:00001032 BL _Z8TestFun24Test ; TestFun2(Test) ; 什麼都沒做 .text:00001036 ADD R7, SP, #0x28+var_24 .text:00001038 MOVS R1, R0 .text:0000103A MOVS R0, R7 .text:0000103C BL _ZN4TestC2ERKS_ ; Test::Test(Test const&) ;從TestFun2返回後在堆棧首地址+4處生成第三個對象 .text:00001040 MOVS R0, R6 ; this .text:00001042 BL _ZN4TestD2Ev ; Test::~Test() ;首先析構了第二個對象 .text:00001046 LDR R1, =(aLesson5 - 0x1052) .text:00001048 LDR R2, =(a________ - 0x1050) .text:0000104A MOVS R0, #3 .text:0000104C ADD R2, PC ; "........\n" ;打印出...... .text:0000104E ADD R1, PC ; "lesson5" .text:00001050 BL j_j___android_log_print .text:00001054 MOVS R0, R7 ; this .text:00001056 BL _ZN4TestD2Ev ; Test::~Test() ;然後析構了第三個對象 .text:0000105A MOV R0, SP ; this .text:0000105C BL _ZN4TestD2Ev ; Test::~Test() ;然後析構了第一個對象 .text:00001060 LDR R2, [SP,#0x28+var_1C] .text:00001062 LDR R3, [R4] .text:00001064 CMP R2, R3 .text:00001066 BEQ loc_106C .text:00001068 BL j_j___stack_chk_fail .text:0000106C ; --------------------------------------------------------------------------- .text:0000106C .text:0000106C loc_106C ; CODE XREF: Java_com_example_ndkreverse5_Lesson5_main+56j .text:0000106C ADD SP, SP, #0x14 .text:0000106E POP {R4-R7,PC}
.text:00001000 ; TestFun2(Test) .text:00001000 EXPORT _Z8TestFun24Test .text:00001000 _Z8TestFun24Test ; CODE XREF: Java_com_example_ndkreverse5_Lesson5_main+22p .text:00001000 BX LR在TestFun2中沒有做任何操作,函數返回後再調用拷貝構造函數生成第二個對象。
0x05
如果Lesson5.cpp,Java_com_example_ndkreverse5_Lesson5_main調用的函數變成如下的形式:
#include "com_example_ndkreverse5_Lesson5.h" #include "Test.h" Test TestFun(Test t) { t.num_=12; return t; } Test& TestFun2(Test t) { return t; } Test TestFun3(Test& t) { return t; } Test& TestFun4(Test& t) { return t; } JNIEXPORT void JNICALL Java_com_example_ndkreverse5_Lesson5_main (JNIEnv * env, jobject jobject) { Test t(10); Test t2 = TestFun3(t); ALOGD("........\n"); }那麼log輸出如下:
D/lesson5 ( 5255): Initializing:10 D/lesson5 ( 5255): Initializing with other:10 D/lesson5 ( 5255): ........ D/lesson5 ( 5255): Destroy:10 D/lesson5 ( 5255): Destroy:10匯編代碼有什麼不同呢?
.text:00001010 EXPORT Java_com_example_ndkreverse5_Lesson5_main .text:00001010 Java_com_example_ndkreverse5_Lesson5_main .text:00001010 .text:00001010 var_1C = -0x1C .text:00001010 var_18 = -0x18 .text:00001010 var_14 = -0x14 .text:00001010 .text:00001010 PUSH {R0-R6,LR} .text:00001012 LDR R4, =(__stack_chk_guard_ptr - 0x101C) .text:00001014 ADD R5, SP, #0x20+var_1C .text:00001016 MOVS R1, #0xA .text:00001018 ADD R4, PC ; __stack_chk_guard_ptr .text:0000101A LDR R4, [R4] ; __stack_chk_guard .text:0000101C ADD R6, SP, #0x20+var_18 .text:0000101E MOVS R0, R5 .text:00001020 LDR R3, [R4] .text:00001022 STR R3, [SP,#0x20+var_14] .text:00001024 BL _ZN4TestC2Ei ; Test::Test(int) ;構造了第一個對象 .text:00001028 MOVS R0, R6 ; Test * .text:0000102A MOVS R1, R5 .text:0000102C BL _Z8TestFun3R4Test ; TestFun3(Test &) ;調用TestFun3 .text:00001030 LDR R1, =(aLesson5 - 0x103C) .text:00001032 LDR R2, =(a________ - 0x103A) .text:00001034 MOVS R0, #3 .text:00001036 ADD R2, PC ; "........\n" ;輸出...... .text:00001038 ADD R1, PC ; "lesson5" .text:0000103A BL j_j___android_log_print .text:0000103E MOVS R0, R6 ; this .text:00001040 BL _ZN4TestD2Ev ; Test::~Test() ;首先析構了第二個對象 .text:00001044 MOVS R0, R5 ; this .text:00001046 BL _ZN4TestD2Ev ; Test::~Test() ;然後析構了第一個對象 .text:0000104A LDR R2, [SP,#0x20+var_14] .text:0000104C LDR R3, [R4] .text:0000104E CMP R2, R3 .text:00001050 BEQ locret_1056 .text:00001052 BL j_j___stack_chk_fail .text:00001056 ; --------------------------------------------------------------------------- .text:00001056 .text:00001056 locret_1056 ; CODE XREF: Java_com_example_ndkreverse5_Lesson5_main+40j .text:00001056 POP {R0-R6,PC}
.text:00001002 ; _DWORD __fastcall TestFun3(Test *) .text:00001002 EXPORT _Z8TestFun3R4Test .text:00001002 _Z8TestFun3R4Test ; CODE XREF: Java_com_example_ndkreverse5_Lesson5_main+1Cp .text:00001002 PUSH {R4,LR} .text:00001004 MOVS R4, R0 .text:00001006 BL _ZN4TestC2ERKS_ ; Test::Test(Test const&) ;利用拷貝構造函數生成了第二個對象 .text:0000100A MOVS R0, R4 .text:0000100C POP {R4,PC}
如果Lesson5.cpp,Java_com_example_ndkreverse5_Lesson5_main調用的函數變成如下的形式:
#include "com_example_ndkreverse5_Lesson5.h" #include "Test.h" Test TestFun(Test t) { t.num_=12; return t; } Test& TestFun2(Test t) { return t; } Test TestFun3(Test& t) { return t; } Test& TestFun4(Test& t) { return t; } JNIEXPORT void JNICALL Java_com_example_ndkreverse5_Lesson5_main (JNIEnv * env, jobject jobject) { Test t(10); Test t2 = TestFun4(t); ALOGD("........\n"); }那麼,輸出的log如下:
D/lesson5 ( 5719): Initializing:10 D/lesson5 ( 5719): Initializing with other:10 D/lesson5 ( 5719): ........ D/lesson5 ( 5719): Destroy:10 D/lesson5 ( 5719): Destroy:10對應的反匯編有什麼不同呢?
.text:00001010 EXPORT Java_com_example_ndkreverse5_Lesson5_main .text:00001010 Java_com_example_ndkreverse5_Lesson5_main .text:00001010 .text:00001010 var_1C = -0x1C .text:00001010 var_18 = -0x18 .text:00001010 var_14 = -0x14 .text:00001010 .text:00001010 PUSH {R0-R6,LR} .text:00001012 LDR R4, =(__stack_chk_guard_ptr - 0x101C) .text:00001014 ADD R5, SP, #0x20+var_1C .text:00001016 MOVS R1, #0xA .text:00001018 ADD R4, PC ; __stack_chk_guard_ptr .text:0000101A LDR R4, [R4] ; __stack_chk_guard .text:0000101C MOVS R0, R5 .text:0000101E LDR R3, [R4] .text:00001020 ADD R6, SP, #0x20+var_18 .text:00001022 STR R3, [SP,#0x20+var_14] .text:00001024 BL _ZN4TestC2Ei ; Test::Test(int) ;生成第一個對象 .text:00001028 MOVS R0, R5 .text:0000102A BL _Z8TestFun4R4Test ; TestFun4(Test &) ;調用TestFun4,是一個空實現 .text:0000102E MOVS R1, R0 .text:00001030 MOVS R0, R6 .text:00001032 BL _ZN4TestC2ERKS_ ; Test::Test(Test const&) ;從TestFun4返回後,調用拷貝構造函數生成了第二個對象 .text:00001036 LDR R1, =(aLesson5 - 0x1042) .text:00001038 LDR R2, =(a________ - 0x1040) .text:0000103A MOVS R0, #3 .text:0000103C ADD R2, PC ; "........\n" 輸出...... .text:0000103E ADD R1, PC ; "lesson5" .text:00001040 BL j_j___android_log_print .text:00001044 MOVS R0, R6 ; this .text:00001046 BL _ZN4TestD2Ev ; Test::~Test() ;析構第二個對象 .text:0000104A MOVS R0, R5 ; this .text:0000104C BL _ZN4TestD2Ev ; Test::~Test() ;析構第一個對象 .text:00001050 LDR R2, [SP,#0x20+var_14] .text:00001052 LDR R3, [R4] .text:00001054 CMP R2, R3 .text:00001056 BEQ locret_105C .text:00001058 BL j_j___stack_chk_fail .text:0000105C ; --------------------------------------------------------------------------- .text:0000105C .text:0000105C locret_105C ; CODE XREF: Java_com_example_ndkreverse5_Lesson5_main+46j .text:0000105C POP {R0-R6,PC} .text:0000100E ; TestFun4(Test &) .text:0000100E EXPORT _Z8TestFun4R4Test .text:0000100E _Z8TestFun4R4Test ; CODE XREF: Java_com_example_ndkreverse5_Lesson5_main+1Ap .text:0000100E BX LRmain函數從TestFun4返回後,才會調用拷貝構造函數生成第二個對象。首選析構第二個對象,然後析構第一個對象。
Activity的啟動;Intent intent = new Intent(this,A.class);startActivity(intent);startActiv
onLayout方法是ViewGroup中子View的布局方法,用於放置子View的位置。放置子View很簡單,只需在重寫onLayout方法,然後獲取子View的實例,
android大家都有很多需要用戶上傳頭像的需求,有的是選方形,有的是圓角矩形,有的是圓形。首先我們要做一個處理圖片的自定義控件,把傳入的圖片,經過用戶選擇區域,處理成一
概述:此部分內容涉及到android的自定義View、自定義屬性和Android圖形圖像處理的綜合應用:Bitmap、Path、Matrix、Canvas。圖片打碼以及如