2012-12-31 17 views
5

Tôi đang cố gắng học smali và tôi có một vài câu hỏi mà tôi không thể tìm thấy bằng cách googling chúng.Làm thế nào để DalvikVM xử lý chuyển đổi và thử mã smali

1) Tôi đã tạo ra một trường hợp thử nghiệm đơn giản để giải thích rõ hơn bản thân mình

const-string v1, "Start" 
:try_start_0 
const-string v1, "Try Block" 
invoke-static {v1}, Lcom/example/test/Main;->print(Ljava/lang/String;)V 
:try_end_0 
.catchall {:try_start_0 .. :try_end_0} :catchall_0 

Tuyên bố .catch: không hai đối số có nghĩa là mất từ ​​đó nhãn nhãn đó và bắt nó (mã giữa hai nhãn) hoặc có nghĩa là bắt đầu thực hiện thử từ: try_start_0 cho đến khi nó đạt đến: try_end_0 (cho phép một bước nhảy goto để thực thi mã không nằm trong hai nhãn)?

Nhãn có luôn cố gắng ở định dạng try_start_% d hoặc chúng có thể là bất kỳ nhãn nào không?

2) Một trường hợp

packed-switch v0, :pswitch_data_0 

const-string v1, "Default Case" 

invoke-static {v1}, Lcom/example/test/Main;->print(Ljava/lang/String;)V 

:goto_0 

const-string v1, "The End" 

invoke-static {v1}, Lcom/example/test/Main;->print(Ljava/lang/String;)V 

return-void 

:pswitch_0 
const-string v1, "Case 1" 

invoke-static {v1}, Lcom/example/test/Main;->print(Ljava/lang/String;)V 

goto :goto_0 

:pswitch_data_0 
.packed-switch 0x1 
:pswitch_0 
.end packed-switch 

Lệnh switch: Liệu nó đòi hỏi rằng các báo cáo chuyển đổi nằm giữa dữ liệu chuyển đổi và các cuộc gọi chuyển đổi? và cũng một lần nữa việc đặt tên của các nhãn cố định hoặc chỉ để thuận tiện?

3) Nếu các nhãn có thể khác nhau, liệu baksmali có bao giờ sản xuất mã smali với các nhãn khác nhau không?

4) Các dòng tùy chọn không phải lúc nào cũng được hiển thị khi dịch ngược dex?

Tôi biết. Tham số và dòng. Là tùy chọn, nhưng tất cả những gì có thể không có ở đó?

Cảm ơn bạn trước.

Trả lời

4

1)

Hai nhãn đầu tiên (try_start_0 và try_end_0 trong ví dụ của bạn) xác định phạm vi của mã mà bìa khối try. Nếu một ngoại lệ xảy ra trong mã được bảo hiểm, thì việc thực thi ngay lập tức nhảy tới nhãn thứ ba (catchall_0). Tên của nhãn không quan trọng, nó có thể là bất kỳ mã định danh hợp lệ nào.

Ngoài ra còn có chỉ thị .catch, với cùng một thứ, ngoại trừ nó chỉ xử lý một loại ngoại lệ cụ thể (tương tự như câu lệnh bắt của java).

Một khối mã có thể được bao phủ bởi nhiều câu lệnh khai thác và tối đa là 1 bắt tất cả câu lệnh. Vị trí của câu lệnh .catch không quan trọng, tuy nhiên, thứ tự tương đối của các câu lệnh catch bao gồm cùng một mã được nhập khẩu. Ví dụ: nếu bạn có

.catch Ljava/lang/Exception; {:try_start_0 .. :try_end_0} :handler1 
.catch Ljava/lang/RuntimeException; {:try_start_0 .. :try_end_0} :handler2 

Câu lệnh bắt thứ hai sẽ không bao giờ được sử dụng. Nếu một RuntimeException được ném trong mã được bảo hiểm, bắt đầu tiên sẽ luôn được sử dụng, vì RuntimeException là một ngoại lệ.

Tuy nhiên, nếu chúng theo thứ tự ngược lại, nó sẽ hoạt động như bạn mong đợi - trình xử lý RuntimeException được sử dụng cho RuntimeExceptions và trình xử lý ngoại lệ được sử dụng cho bất kỳ loại ngoại lệ nào khác.

Và cuối cùng, không giống như java, phạm vi mã trong câu lệnh .catch không cần phải được lồng ghép một cách nghiêm ngặt. Ví dụ: hoàn toàn hợp pháp để có một cái gì đó như

:a 
const-string v1, "Start" 
:b 
const-string v1, "Try Block" 
:c 
invoke-static {v1}, Lcom/example/test/Main;->print(Ljava/lang/String;)V 
:d 
.catch Ljava/lang/RuntimeException; {:a .. :c} :d 
.catch Ljava/lang/Exception; {:b .. :d} :d 

Bạn cũng có thể có một số công trình khá kỳ lạ, như thế này.

.method public static main([Ljava/lang/String;)V 
    .registers 3 

    :second_handler 
    :first_try_start 
     new-instance v0, Ljava/lang/RuntimeException; 
     invoke-direct {v0}, Ljava/lang/RuntimeException;-><init>()V 
     throw v0 
    :first_try_end 
    .catch Ljava/lang/Exception; {:first_try_start .. :first_try_end} :first_handler 
    :first_handler 
    :second_try_start 
     new-instance v0, Ljava/lang/RuntimeException; 
     invoke-direct {v0}, Ljava/lang/RuntimeException;-><init>()V 
     throw v0 
    :second_try_end 
    .catch Ljava/lang/Exception; {:second_try_start .. :second_try_end} :second_handler 
.end method 

Không có ví dụ nào trên đây được tạo từ mã java đã biên dịch, nhưng bản thân bytecode cho phép nó.

2) Báo cáo chuyển đổi có thể là bất cứ nơi nào trong mối quan hệ với câu lệnh switch hoặc chuyển dữ liệu. Các tên nhãn ở đây cũng tùy ý.

3) Baksmali có thể tạo nhãn trong một trong 2 cách. Cách mặc định là sử dụng "loại" chung của nhãn và nối thêm địa chỉ bytecode của nhãn. Nếu bạn chỉ định tùy chọn -s/- sequential-labels, thay vì sử dụng địa chỉ bytecode, nó giữ một bộ đếm cho mỗi loại nhãn và tăng nó mỗi lần nó tạo ra một nhãn của kiểu đó.

4) Nói chung bất cứ điều gì đó là một phần của thông tin gỡ lỗi. .parameter, .line, .procalue, .epilogue, .source, .local, .restart local, .end local ... Tôi nghĩ rằng về việc che giấu nó.

+0

Cảm ơn bạn. Đây chính là điều tôi muốn biết. Tôi đặc biệt thích công trình "kỳ lạ" thứ hai của bạn :). Tôi biết mã java đã biên dịch sẽ không thể đưa ra điều đó, nhưng một chương trình tối ưu hóa có thể tối ưu hóa mã thành trạng thái không thể đạt được với mã java thông thường (giống như C/C++ goto cho phép "lạ" kiểm soát dòng chảy) ? – Xonar

+0

Trình tối ưu hóa - có thể là không. Tuy nhiên, nó có thể có nhiều khả năng từ một obfuscator – JesusFreke

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