您好,登錄后才能下訂單哦!
原文鏈接:https://source.android.com/devices/tech/dalvik/dalvik-bytecode.html
一、總體設計
(1)虛擬機模型(machine model)和調用規則(calling conventions)是為了更好的模仿普通真實的架構和C風格的調用規則:
a.虛擬機是基于寄存器的,并且框架(frames)被創建后大小是固定的。每一個框架(frame)組成部分包括:特定數量的寄存器(由方法指定)和任何在執行方法時需要的輔助數據,例如(但是并不僅限于)程序計數器和對包含該方法.dex文件的一個引用。
b.當用于位值(bit values)時(例如整數和浮點數),寄存器是由32 位的。寄存器對用于64位數值。對寄存器對的排列(aliggment)沒有要求。
c.當用于對象引用時,寄存器被認為有足夠的空間正確的存放該引用。
d.按位表示,(Object)null == (int)0.
e.對于方法中的N的參數,會按順序存放到方法執行框架(frame)中后N個寄存器中。較大參數使用使用兩個寄存器。實例方法第一個參數為this。
(2)指令流中的存儲單位是一段16位無符號bit。一些指令中的一些bit被棄用或者被置零。
(3)指令沒有必要被限制在一個特定類型。例如,指令move 32-bit并沒有指定移動的是int還是float。
(4)分別的枚舉和索引常量池,包括:String、types、fields、methods。
(5)指令流中的bitwise literal data被順序(in-line)表示。
(6)實際上,需要大于16個寄存器的方法是不常見的,并且由于需要大于8個寄存器是合理正常的,很多指令被限制僅尋址前16個寄存器。理論上,指令允許引用前256個寄存器。另外,一些指令的變體會需要更多的寄存器數量,其中全方位(catch-all)move指令可以尋址v0-v65536.在指令變體不可用的情況下尋址期望的寄存器,期望期存器的內容從原始寄存器移動到一個low寄存器(操作之前)及(或)從一個low結果寄存器移動到high寄存器(操作之后)。
(7)"pseudo-instruction"指令被用來存儲變長(variable-length)數據,被稱為regular instruction(例如:fill-array-data)。這些指令在正常的執行流期間從不會遇到。另外這些指令必須被位于偶數字節碼偏移量(也就是說4字節對齊)。為了滿足這個需求,dex生成工具必須發行一個額外的nop指令作為一個空間塊(spacer)用來對齊這些指令。最后,盡管不需要,人們期望大多說工具將選擇在方法的結尾發行這些指令,否則其他的指令會出現分歧。
(8)一旦被安裝到一個運行的系統中,一些指令也許會被改變,由于安裝時靜態鏈接優化會改變指令的形式。一旦知道可鏈接這些指令會被更快的執行。
(9)Humman-syntax 和 mnemonics(助記符)
a.參數的順序:dest then source
b.一些操作符有一個消除二義性名稱的后綴,來指明操作的類型:
I:普通類型32位操作符沒有標記;
II:普通類型64位操作符后綴為-wide;
III:特定類型的后綴是它們的類型(或是是簡單的縮寫):-boolean、-byte、-char、-short、
-int、-long、-float、-double、-object、-string、-class、-void;
c.一些操作符有消除二義性的后綴來分辨otherwise-identical操作,這些操作有不同的指令形式和選項。這些后綴用‘/’于主名稱(main name)分離并且大部分在生成可執行代碼中與靜態常量一對一映射(減少歧義)。
d.這里的描述中,一個數值的寬度(width)(例如一個常量的范圍或者被尋址的寄存器的數量)被強調使用每個字符使用4bit的寬度。
e.例如在指令:move-wide/from16 VAA,VBBBB
①:move,是基本操作符,說明基本的操作
②:wide,是名稱后綴,說明它操作的是64位數據
③:from16,是操作符后綴,說明具有16位寄存器變量的引用作為source
④:vAA,是目的寄存器(被操作隱藏,目的參數總是處于第一位),范圍:v0-v255;
⑤:vBBBB,是源寄存器,范圍:v0-v6535
二、字節碼集概述
Op & Format | Mnenonic/Syntax(助記符/語法) | Arguments(參數) | Description(說明) |
00 10x | nop | 空循環,沒有操作,表示一條指令執行的時間 | |
01 12x | move vA,vB | A:目標寄存器(4bit) B:源寄存器(4bit) | 將一個非對象寄存器的內容轉移到另一個寄存器中 |
02 22x | move/from16 vAA,vBBBB | A:目標寄存器(8bit) B:源寄存器(16bit) | 同上 |
03 32x | move/16 vAAAA,vBBBB | A:目標寄存器(16bit) B:源寄存器(16bit) | 同上 |
04 12x | move-wide vA,vB | A:目標寄存器(4bit) B:源寄存器對(4bit) | 將一個寄存器對中的內容移動到另一個寄存器對中。 注意:從vN移動到vN-1或者vN+1是合法的,所以在向寄存器對中寫數據之前,寄存器的兩部分必須是可讀的。 |
05 22x | move-wide/from16 vAA,vBBBB | A:目標寄存器對(8bit) B:源寄存器對(16bit) | 同上 |
06 32x | move-wide/16 vAAAA,vBBBB | A:目標寄存器對(16bit) B:源寄存器對(16bit) | 同上 |
07 12x | move-object vA,vB | A:目標寄存器(4bit) B:源寄存器(4bit) | 將對象寄存器中的內容轉移到另外一個寄存器中 |
08 22x | move-object/from16 vAA,vBBBB | A:目標寄存器(8bit) B:源寄存器(16bit) | 同上 |
09 32x | move-object/16 vAAAA,vBBBB | A:目標寄存器(16bit) B:源寄存器(16bit) | 同上 |
0a 11x | move-result vAA | A:目標寄存器(8bit) | 將最近invoke-kind指令的單字(single-word)、非對象(non-object)的結果轉移到指定的寄存器中。在invoke-kind指令(結果不可忽略)之后立即執行該指令;在其他地方執行是無效的 |
0b 11x | move-result-wide vAA | A:目標寄存器(8bit) | 將最近invoke-kind指令的雙字(double-word)結果轉移到指定的寄存器對。在invoke-kind指令(結果不可忽視)之后;在其他地方執行時無效的 |
0c 11x | move-result-object vAA | A:目標寄存器(8bit) | 將最近invoke-kind指令的object結果轉移到指定的寄存器中。該指令必須在invoke-kind或者filled-new-array之后立即執行,它們的(object)結果不可忽略并且在其他地方執行時無效 |
0d 11x | move-exception vAA | A:目標寄存器(8bit) | 將一個僅被catch到的異常保存到指定的寄存器中。該指令必須是任何異常處理的第一條指令,該異常處理捕獲到異常是不能忽略的,并且該指令必須只能作為異常處理器的第一條指令;其他地方執行時無效 |
0e 10x | return void | 從一個void方法返回 | |
0f 11x | return vAA | A:返回值寄存器(8bit) | 從一個32位、非對象、有返回值得方法中返回 |
10 11x | return-wide vAA | A:返回值寄存器對(8bit) | 從一個64位、有返回值的方法返回 |
11 11x | return-object vAA | A:返回值寄存器(8bit) | 從一個有對象返回的方法中返回 |
12 11n | const/4 vA,#+B | A:目標寄存器(4bit) B:有符號整數(4bit) | 將有符號字符數據(32bit)轉移到指定的寄存器中 |
13 21s | const/4 vAA,#+BBBB | A:目標寄存器(8bit) B:有符號整數(16bit) | 將給定的有符號總非數據(32bit)轉移到指定的寄存器中 |
14 31i | const vAA,#+BBBBBBBB | A:目標寄存器(8bit) B:任意32位常量 | 將執行的字符數值轉移到指定的寄存器中 |
15 21h | const/high26 vAA,#+BBBB0000 | A:目標寄存器(8bit) B:有符號的整數(16bit) | 將給定的字符值(right-zero-extended to 32)轉移到指定的寄存器中 |
16 21s | const-wide/16 vAA,#+BBBB | A:目標寄存器(8bit) B:有符號整數(16bit) | 將給定的字符值轉移到指定的寄存器對中 |
17 31i | const-wide/32 vAA,#+BBBBBBBB | A:目標寄存器(8bit) B:有符號整數(32位) | 將給定的字符值(有符號擴展到64位)轉移到指定的寄存器對中 |
18 51l | const-wide vAA,#+BBBBBBBBBBBBBBBB | A:目標寄存器(8bit) B:任意64位常量 | 將給定的字符值轉移到指定的寄存器對中 |
19 21h | const-wide/high26 vAA,#+BBBB000000000000 | A:目標寄存器(8bit) B:有符號整數(16bit) | 將給定的字符值(right-zero-extended to 64bit)轉移到特定的寄存器對中 |
1a 21c | const-string vAA,string@BBBB | A:目標寄存器(8bit) B:string index | 將通過給定的ndex指定的string引用轉移到指定的寄存器 中 |
1b 31c | const-string/jumbo vAA,string@BBBBBBBB | A:目標寄存器(8bit) B:字符串索引 | 同上 |
1c 21c | const-class vAA,type@BBBB | A:目標寄存器(8bit) B:類型索引 | 將指定索引的特定類型的引用轉移到特定寄存器中,在這種情況中指定類型是原始類型,該指令將會把原始類型的degenerate類 |
1d 11x | monitor-enter vAA | A:引用寄存器(8bit) | 獲取指定對象的monitor |
1e 11x | monitor-exit vAA | 同上 | 釋放指定對象的monitor; 注意:如果該指令需要拋出異常,它必須就像pc中那些先進的指令一樣。它可以有利于判斷該指令是否成功的執行,并且要不活該異常必須在該指令執行之后和下一個指令執行之前。這樣定義使得一個使用monitor的方法隨著monitor被代碼塊自己清楚而try-catch塊也被清除成為可能,as a way to handle the
arbitrary exceptions that might get thrown due to the historical
implementation of |
1f 21c | check-cast vAA,type@BBBB | A:存儲引用的寄存器(8bit) B:類型索引(16bit) | 如果給定寄存器中的引用不能轉化為指定的類型則拋出一個classCastException; 注意:因為A必須是一個引用(不是一個原始值),如果B是一個原始類型在runtime階段會拋出一個異常。 |
20 22c | instance-of vA,vB, type@CCCC | A:目標寄存器(4bit) B:引用寄存器(4bit) C:類型索引(16bit) | 如果指定引用是一個給定類型的實例則目標寄存器中存放1,否則存放0; 注意:因為B必須是一個引用(不是原始類型數值),如果是一個原始類型則寄存器的結果總是0; |
21 12x | array-length vA,vB | A:目標寄存器(4bit) B:數組引用寄存器(4bit) | 將指定數組的長度存儲到給定的目標寄存器中 |
22 21c | new-instance vAA,type@BBBB | A:目標寄存器(8bit) B:類型索引 | 構造一個指定類型的新實例,并將它的引用存放到指定目標寄存器中。該類型必須是非數組類 |
23 22c | new-array vA,vB,type@CCCC | A:目標寄存器(8bit) B:尺寸(size)寄存器 C:類型索引 | 構造一個執行類型和大小的新的數組,該類型必須是一個數組類型 |
24 35c | filled-new-array{vC,vD,vE,vF,vG},type@BBBB | A:數組大小和參數字數量(4bit) B:類型索引(16bit) C...G:參數寄存器(4bit) | 根據給定的類型和大小構造一個數組,用提供的內容賦值。類型必須是一個數組類型。數組的內容必須是單字(single-word)(也就是說沒有long或者double數組,但是引用類型是可以接受的)。構造實例被作為結果存儲起來,就像方法執行指令保存它們的結果一樣,所以構造出來的實例必須立即在隨后使用move-result-object指令轉移到一個寄存器中。 |
25 3rc | filled-new-array/range{vCCCC..vNNNN},type@BBBB | A:數組的膽小和參數字的數量(8bit) B:類型索引(16bit) C:第一個參數寄存器(16bit) N = A + C - 1 | 構造一個指定類型和大小的數組,使用指定的內容賦值。闡述和約束與filled-new-array一樣,同上 |
26 31t | fill-array-data vAA,+BBBBBBBB | A:數組的引用(8bit) B:signed "branch" offset to table data pseudo-instruction (32 bits) | 使用指定的數據給給定的數組賦值。該引用必須是一個原始數據數組并且數據表必須匹配它的類型并且表中的數據數量不多于數組的大小。也就是說數組大于表的大小,only the initial elements of the array are set, leaving the remainder alone |
27 11x | throw vAA | A:異常寄存器(8bit) | 拋出指定異常 |
28 10t | goto +AA | A:帶符號的分支偏移量(8bit) | 無條件的跳轉到指定的指令; 注意:分支的偏移量不可為0, |
29 20t | goto/16 +AAAA | A:帶符號的分支偏移量(16位) | 同上 |
2a 30t | goto/32 +AAAAAAAA | A:帶符號的分支偏移量(32位) | 同上 |
2b 31t | packed-switch vAA,+BBBBBBBB | A:測試寄存器 B:數據表偽指令有符號分支偏移量(32bit) | 在給定寄存器的基礎上跳轉到一個新的指令,使用一個偏移量表對應特定整數范圍中的每個值,或者如果沒有匹配的數值下一條指令會落空。 |
2c 31t | sparse-switch vAA,+BBBBBBBB | A:測試寄存器 B:數據表偽指令有符號分支偏移量(32bit) | 在給定寄存器的基礎上跳轉到一個新的指令,使用一個值-偏移量對的順序,或者如果沒有匹配的數值下一條指令會落空。 |
2d..31 23x | cmpkind vAA,vBB,vCC 2d:cmpl-float(lt bias) 2e:cmpg-float(gt bias) 2f:cmpl-double(lt bias) 30:cmpg-double(gt bias) 31:cmp-long | A:目標寄存器(8bit) B:第一個源寄存器或寄存器對 C:第二個源寄存器或寄存器對 | 執行指定浮點或long比較,如果b==c則a=0;如果b>c,a=1;ruguo b<c,a=-1.浮點操作的“bias”表明如何進行NaN比較:"gt bias"指令返回1,"lt bias"指令返回-1.例如,使用cmpg-float指令比較x<y,結果為-1表明測試正確,如果是其他結果則表明測試不正確或者無效(無效的比較或者其中一個為NaN) |
32..37 22t | if-test vA,vB,+CCCC 32:if-eq 33:if-ne 34:if-lt 35:if-ge 36:if-gt 37:if-le | A:測試的第一個寄存器(4bit) B:測試的第二個寄存器(4bit) C:有符號的分支偏移量(16bit) | 如果兩個寄存器的值比較結果確定則指定目標位置的分支確定。 注意:分支的偏移量不能為0; |
38..3d 21t | if-testz vAA,+BBBB 38:if-eqz 39:if-nez 3a:if-ltz 3b:if-gez 3c:if-gtz 3d:if-lez | A:測試寄存器(8bit) B:有符號的分支偏移量(16bit) | 如果兩個寄存器的值比較結果確定則指定目標位置的分支確定。 注意:分支的偏移量不能為0 |
3e..43 10x | 未使用 | 未使用 | |
44..5123c | arrayop vAA,vBB,vCC 44:aget 45:aget-wide 46:aget-object 47:aget-boolean 48:aget-byte 49:aget-char 4a:aget-short 4b:aput 4c:aput-wide 4d:aput-object 4e:aput-boolean 4f:aput-byte 50:aput-char 51:aput-short | A:值寄存器或寄存器對;可以是源也可以是目標(8bit) B:數組寄存器(8bit) C:索引寄存器(8bit) | 在給定數組指定的索引處執行指定的數組操作,把結果存到值寄存器中 |
52..5f 22c | iinstaceop vA,vB,field@CCCC 52:iget 53:iget-wide 54:iget-object 55:iget-boolean 56:iget-byte 57:iget-char 58:iget-short 59:iput 5a:iput-wide 5b:iput-object 5c:iput-boolean 5d:iput-byte 5e:iput-char 5f:iput-short | A:值寄存器或寄存器對,可以是源或者目標(4bit) B:對象寄存器(4bit) C:實例域的引用索引(16bit) | 執行擁有特定域的對象實例域的操作,將結果保存到值寄存器中。 注意:這些操作碼對靜態鏈接來說是合理的選擇,修改域參數將成為更直接的位移 |
60..6d 21c | sstaticop vAA,field@BBBB 60:sget 61:sget-wide 62:sget-object 63:sget-boolean 64:sget-byte 65:sget-char 66:sget-short 67:sput 68:sput-wide 69:sput-object 6a:sput-boolean 6b:sput-byte 6c:sput-char 6d:sput-short | A:值寄存器或寄存器對,可以使源或目標(8bit) B:靜態域引用的索引(16bit) | 執行擁有指定靜態域的對象的靜態域操作,保存結果到值寄存器中; 注意:同上 |
6e..72 35c | invoke-kind{vC,vD,vE,vF,vG},meth@BBBB 6e:invoke-virtual 6f:invoke-super 70:invoke-direct 71:invoke-static 72:invoke-interface | A:參數字數(4bit) B:方法的引用索引(16bit) C..G:參數寄存器(4bit) | 調用指定方法。在隨后立即執行的指令中使用合適的move-result*來保存結果。 invoke-virtual:被用來執行一個一般的virtual method(不是private/static/final,也不是一個構造方法); invoke-super:被用來執行一個最親近父類的virtual method(與調用類有相同的method_id)。與invoke-virtual有相同的方法約束。 invoke-direct:被用來執行一個非靜態的direct method(一個實例自己方法,非重寫的方法,或是一個私有的實例方法或者是構造方法) invoke-static:被用來執行一個靜態方法,且這個方法是一個direct method。 invoke-interface:用來執行interface method,也就是說一個具體類型未知的對象,使用一個接口的method_id. 注意:同上 |
73 10x | 未使用 | 未使用 | |
74..78 3rc | invoke-kind/range{vCCCC..cNNNN},meth@BBBB 74:invoke-virtual/range 75:invoke-super/range 76:invoke-direct/range 77:invoke-static/range 78:invoke-interface/range | A:參數字數(8bit) B:方法的引用索引(16bit) C:第一個參數寄存器(16bit) N=A+C-1 | 調用指定的方法。同上 |
79..7a 10x | 未使用 | 未使用 | |
7b..8f 12x | unop vA,vB 7b:neg-int 7c:not-int 7d:neg-long 7e:not-long 7f:neg-float 80:neg-double 81:int-to-long 82:int-to-float 83:int-to-double 84:long-to-int 85:long-to-float 86:long-to-double 87:float-to-int 88:float-to-long 89:float-to-double 8a:double-to-int 8b:double-to-long 8c:double-to-float 8d:int-to-byte 8e:int-to-char 8f:int-to-short | A:目標寄存器或寄存器對(4bit) B:源寄存器或寄存器對(4bit) | 在源寄存器上執行一個一元的操作,將結果保存到目標寄存器中 |
90..af 23x | binop vAA,vBB,vCC 90:add-int 91:sub-int 92:mul-int 93:div-int 94:rem-int 95:and-int 96:or-int 97:xor-int 98:shl-int 99:shr-int 9a:ushr-int 9b:add-long 9c:sub-long 9d:mul-long 9e:div-long 9f:erm-long a0:add-long a1:or-long a2:xor-long a3:shl-long a4:shr-long a5:ushr-long a6:add-float a7:sub-float a8:mul-float a9:div-float aa:rem-float ab:add-double ac:sub-double ad:mul-double ae:div-double af:rem-double | A:目標寄存器或寄存器對(8bit) B:第一個源寄存器或寄存器對(8bit) C:第二個源寄存器或寄存器對(8bit) | 在兩個源寄存器上執行指定的雙目操作,將結果存儲到目標寄存器中。 注意:與其他的-long數學操作(它們的第一和第二源都是寄存器對),shl-long,shr-long和ushr-long的第一個源使用寄存器對,但是第二個源使用單個寄存器。 |
b0..cf 12x | binop/2addr vA,vB b0:add-int/2addr b1:sub-int/2addr b2:mul-int/2addr b3:div-int/2addr b4:rem-int/2addr b5:and-int/2addr b6:or-int/2addr b7:xor-int/2addr b8:shl-int/2addr b9:shr-int/2addr ba:ushr-int/2addr bb:add-long/2addr bc:sub-long/2addr bd:mul-long/2addr be:div-long/2addr bf:erm-long/2addr c0:add-long/2addr c1:or-long/2addr c2:xor-long/2addr c3:shl-long/2addr c4:shr-long/2addr c5:ushr-long/2addr c6:add-float/2addr c7:sub-float/2addr c8:mul-float/2addr c9:div-float/2addr ca:rem-float/2addr cb:add-double/2addr cc:sub-double/2addr cd:mul-double/2addr ce:div-double/2addr cf:rem-double/2addr | A:目標和第一個源寄存器或寄存器對(4bit) B:第二個源寄存器或寄存器對(4bit) | 在兩個源寄存器上執行指定的雙目操作,并家結果保存到第一個源寄存器中。 注意:與其他的-long/2addr數學運算操作(它們目標或第一個源和第二個源都使用寄存器對)相反,shl-long/2addr,shr-long/2addr和ushr-long/2addr,它們的目標和第一個源都使用寄存器對,但是它們的第二個源使用單個寄存器 |
d0..d722s | binop/lit16 vA,vB,#+CCCC d0:add-int/lit16 d1:rsub-int(reverse subtract) d2:mul-int/lit16 d3:div-int/lit16 d4:rem-int/lit16 d5:and-int/lit16 d6:or-int/lit16 d7:xor-int/lit16 | A:目標寄存器(4bit) B:源寄存器(4bit) C:有符號的整數常量(16bit) | 在指定的寄存器和字符上執行指定的雙目操作,并將結果保存到目標寄存器中。 注意:rsub-int does not have a suffix since this version is the main opcode of its family. |
d8..e2 22b | binop/lit8 vAA,vBB,#+CC d8:add-int/lit8 d9:rsub-int/lit8 da:mul-int/lit8 db:div-int/lit8 dc:rem-int/lit8 dd:and-int/lit8 de:or-int/lit8 df:xor-int/lit8 e0:shl-int/lit8 e1:shr-int/lit8 e2:ushr-int/lit8 | A:目標寄存器(8bit) B:源寄存器(8bit) C:有符號的整數常量(8bit) | 同上 |
e3..ff 10x | 未使用 | 未使用 |
三、sparse-switch-payload format
四、fill-array-data-payload format
五、數學操作說明
注意:浮點操作必須符合IEEE754規則,using round-to-nearest and gradual underflow,except where stated otherwise
操作碼 | C 語義 | 注意 |
neg-int | int32 a; int32 result=-a; | 補碼 |
not-int | int32 a; int32 result=~a; | 反碼 |
neg-long | int64 a; int64 result=-a; | 補碼 |
not-long | int64 a; int64 result=~a; | 反碼 |
neg-float | float a; float result=-a; | negation |
neg-double | double a; double result=-a; | negation |
int-to-long | int32 a; int64 result=(int64)a; | 有符號的擴展:int32->int64 |
int-to-float | int32 a; float result=(float)a; | 使用round-to-nearest進行int32到float的轉換。會丟失精度。 |
int-to-double | int32 a; double result=(double)a; | int32->double |
long-to-int | int64 a; int32 result=(int32)a; | int64->int32 |
long-to-float | ||
long-to-double | ||
float-to-int | float a; int32 result=(int32)a; | |
float-to-long | float a; int64 result=(int64)a; | |
float-to-double | float a; double result = (double)a; | |
double-to-int | double a; int32 result = (int32)a; | |
double-to-long | double a; int64 result=(int64)a; | |
double-to-float | double a; float result=(float)a; | |
int-to-byte | int32 a; int32 result=(a<<24)>>24 | |
int-to-char | int32 a; int32 result=a&0xffff | |
int-to-short | int32 a; int32 result=(a<<16)>>16 | |
add-int | int32 a,b; int32 result = a + b; | |
sub-int | int32 a,b; int32 result = a-b; | |
rsub-int | int32 a,b; int32 result=b-a; | |
mul-int | int32 a,b; int32 result=a*b; | |
div-int | int32 a,b; int32 result=a/b; | |
rem-int | int32 a,b; int32 result = a%b; | |
and-int | int32 a,b; int32 result=a&b; | |
or-int | int32 a,b; int32 result=a|b; | |
xor-int | int32 a,b; int32 result=a^b; | |
shl-int | int32 a,b; int32 result=a<<(b&0x1f) | |
shr-int | int32 a,b; int32 result=a>>(b&0x1f) | |
ushr-int | uint32 a,b; int32 result=a>>(b&0x1f) | |
long...... | int64... | |
add-float | float a,b; float result = a+b; | |
sub-float | float a,b; float result = a-b; | |
mul-float | float a,b; float result = a*b; | |
div-float | float a,b; float result = a/b; | |
ren-float | float a,b; float result = a%b; | |
double... | double... |
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。