mirror of
https://github.com/revanced/smali.git
synced 2025-05-21 00:17:05 +02:00
Add support for the invoke-object-init/range opcode in ICS
This commit is contained in:
parent
5967598d01
commit
ea7afb0265
@ -1069,6 +1069,9 @@ public class MethodAnalyzer {
|
|||||||
case INVOKE_DIRECT_EMPTY:
|
case INVOKE_DIRECT_EMPTY:
|
||||||
analyzeInvokeDirectEmpty(analyzedInstruction);
|
analyzeInvokeDirectEmpty(analyzedInstruction);
|
||||||
return true;
|
return true;
|
||||||
|
case INVOKE_OBJECT_INIT_RANGE:
|
||||||
|
analyzeInvokeObjectInitRange(analyzedInstruction);
|
||||||
|
return true;
|
||||||
case IGET_QUICK:
|
case IGET_QUICK:
|
||||||
case IGET_WIDE_QUICK:
|
case IGET_WIDE_QUICK:
|
||||||
case IGET_OBJECT_QUICK:
|
case IGET_OBJECT_QUICK:
|
||||||
@ -1568,6 +1571,7 @@ public class MethodAnalyzer {
|
|||||||
case EXECUTE_INLINE:
|
case EXECUTE_INLINE:
|
||||||
case EXECUTE_INLINE_RANGE:
|
case EXECUTE_INLINE_RANGE:
|
||||||
case INVOKE_DIRECT_EMPTY:
|
case INVOKE_DIRECT_EMPTY:
|
||||||
|
case INVOKE_OBJECT_INIT_RANGE:
|
||||||
case IGET_QUICK:
|
case IGET_QUICK:
|
||||||
case IGET_WIDE_QUICK:
|
case IGET_WIDE_QUICK:
|
||||||
case IGET_OBJECT_QUICK:
|
case IGET_OBJECT_QUICK:
|
||||||
@ -3470,6 +3474,17 @@ public class MethodAnalyzer {
|
|||||||
analyzeInstruction(analyzedInstruction);
|
analyzeInstruction(analyzedInstruction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void analyzeInvokeObjectInitRange(AnalyzedInstruction analyzedInstruction) {
|
||||||
|
Instruction3rc instruction = (Instruction3rc)analyzedInstruction.instruction;
|
||||||
|
|
||||||
|
Instruction3rc deodexedInstruction = new Instruction3rc(Opcode.INVOKE_DIRECT_RANGE,
|
||||||
|
(short)instruction.getRegCount(), instruction.getStartRegister(), instruction.getReferencedItem());
|
||||||
|
|
||||||
|
analyzedInstruction.setDeodexedInstruction(deodexedInstruction);
|
||||||
|
|
||||||
|
analyzeInstruction(analyzedInstruction);
|
||||||
|
}
|
||||||
|
|
||||||
private boolean analyzeIputIgetQuick(AnalyzedInstruction analyzedInstruction) {
|
private boolean analyzeIputIgetQuick(AnalyzedInstruction analyzedInstruction) {
|
||||||
Instruction22cs instruction = (Instruction22cs)analyzedInstruction.instruction;
|
Instruction22cs instruction = (Instruction22cs)analyzedInstruction.instruction;
|
||||||
|
|
||||||
|
@ -117,7 +117,8 @@ public class Instruction3rc extends InstructionWithReference implements Register
|
|||||||
if (type.charAt(1) == 'J' || type.charAt(1) == 'D') {
|
if (type.charAt(1) == 'J' || type.charAt(1) == 'D') {
|
||||||
throw new RuntimeException("The type cannot be an array of longs or doubles");
|
throw new RuntimeException("The type cannot be an array of longs or doubles");
|
||||||
}
|
}
|
||||||
} else if (opcode.value >= INVOKE_VIRTUAL_RANGE.value && opcode.value <= INVOKE_INTERFACE_RANGE.value) {
|
} else if (opcode.value >= INVOKE_VIRTUAL_RANGE.value && opcode.value <= INVOKE_INTERFACE_RANGE.value ||
|
||||||
|
opcode == INVOKE_OBJECT_INIT_RANGE) {
|
||||||
//check data for invoke-*/range opcodes
|
//check data for invoke-*/range opcodes
|
||||||
MethodIdItem methodIdItem = (MethodIdItem) item;
|
MethodIdItem methodIdItem = (MethodIdItem) item;
|
||||||
int parameterRegisterCount = methodIdItem.getPrototype().getParameterRegisterCount();
|
int parameterRegisterCount = methodIdItem.getPrototype().getParameterRegisterCount();
|
||||||
|
@ -267,6 +267,7 @@ public enum Opcode
|
|||||||
EXECUTE_INLINE((short)0xee, "execute-inline", ReferenceType.none, Format.Format35mi, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
|
EXECUTE_INLINE((short)0xee, "execute-inline", ReferenceType.none, Format.Format35mi, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
|
||||||
EXECUTE_INLINE_RANGE((short)0xef, "execute-inline/range", ReferenceType.none, Format.Format3rmi, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
|
EXECUTE_INLINE_RANGE((short)0xef, "execute-inline/range", ReferenceType.none, Format.Format3rmi, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
|
||||||
INVOKE_DIRECT_EMPTY((short)0xf0, "invoke-direct-empty", ReferenceType.method, Format.Format35s, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
|
INVOKE_DIRECT_EMPTY((short)0xf0, "invoke-direct-empty", ReferenceType.method, Format.Format35s, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
|
||||||
|
INVOKE_OBJECT_INIT_RANGE((short)0xf0, "invoke-object-init/range", ReferenceType.method, Format.Format3rc, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
|
||||||
IGET_QUICK((short)0xf2, "iget-quick", ReferenceType.none, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_QUICK | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
|
IGET_QUICK((short)0xf2, "iget-quick", ReferenceType.none, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_QUICK | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
|
||||||
IGET_WIDE_QUICK((short)0xf3, "iget-wide-quick", ReferenceType.none, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_QUICK | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
|
IGET_WIDE_QUICK((short)0xf3, "iget-wide-quick", ReferenceType.none, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_QUICK | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
|
||||||
IGET_OBJECT_QUICK((short)0xf4, "iget-object-quick", ReferenceType.none, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_QUICK | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
|
IGET_OBJECT_QUICK((short)0xf4, "iget-object-quick", ReferenceType.none, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_QUICK | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
|
||||||
@ -351,13 +352,16 @@ public enum Opcode
|
|||||||
opcodesByName = new HashMap<Integer, Opcode>();
|
opcodesByName = new HashMap<Integer, Opcode>();
|
||||||
|
|
||||||
for (Opcode opcode: Opcode.values()) {
|
for (Opcode opcode: Opcode.values()) {
|
||||||
if (((opcode.value >> 8) & 0xFF) == 0x00) {
|
//INVOKE_DIRECT_EMPTY was changed to INVOKE_OBJECT_INIT_RANGE in ICS
|
||||||
opcodesByValue[opcode.value & 0xFF] = opcode;
|
if (opcode != INVOKE_DIRECT_EMPTY) {
|
||||||
} else {
|
if (((opcode.value >> 8) & 0xFF) == 0x00) {
|
||||||
assert ((opcode.value >> 8) & 0xFF) == 0xFF;
|
opcodesByValue[opcode.value & 0xFF] = opcode;
|
||||||
expandedOpcodesByValue[opcode.value & 0xFF] = opcode;
|
} else {
|
||||||
|
assert ((opcode.value >> 8) & 0xFF) == 0xFF;
|
||||||
|
expandedOpcodesByValue[opcode.value & 0xFF] = opcode;
|
||||||
|
}
|
||||||
|
opcodesByName.put(opcode.name.hashCode(), opcode);
|
||||||
}
|
}
|
||||||
opcodesByName.put(opcode.name.hashCode(), opcode);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -386,6 +390,18 @@ public enum Opcode
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void addOpcodes(Opcode... toAdd) {
|
||||||
|
for (Opcode opcode: toAdd) {
|
||||||
|
if (((opcode.value >> 8) & 0xFF) == 0x00) {
|
||||||
|
opcodesByValue[opcode.value & 0xFF] = opcode;
|
||||||
|
} else {
|
||||||
|
assert ((opcode.value >> 8) & 0xFF) == 0xFF;
|
||||||
|
expandedOpcodesByValue[opcode.value & 0xFF] = opcode;
|
||||||
|
}
|
||||||
|
opcodesByName.put(opcode.name.hashCode(), opcode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This will add/remove/replace various opcodes in the value/name maps as needed,
|
* This will add/remove/replace various opcodes in the value/name maps as needed,
|
||||||
* based on the idiosyncrasies of that api level
|
* based on the idiosyncrasies of that api level
|
||||||
@ -411,7 +427,9 @@ public enum Opcode
|
|||||||
SGET_JUMBO, SGET_WIDE_JUMBO, SGET_OBJECT_JUMBO, SGET_BOOLEAN_JUMBO, SGET_BYTE_JUMBO,
|
SGET_JUMBO, SGET_WIDE_JUMBO, SGET_OBJECT_JUMBO, SGET_BOOLEAN_JUMBO, SGET_BYTE_JUMBO,
|
||||||
SGET_CHAR_JUMBO, SGET_SHORT_JUMBO, SPUT_JUMBO, SPUT_WIDE_JUMBO, SPUT_OBJECT_JUMBO,
|
SGET_CHAR_JUMBO, SGET_SHORT_JUMBO, SPUT_JUMBO, SPUT_WIDE_JUMBO, SPUT_OBJECT_JUMBO,
|
||||||
SPUT_BOOLEAN_JUMBO, SPUT_BYTE_JUMBO, SPUT_CHAR_JUMBO, SPUT_SHORT_JUMBO, INVOKE_VIRTUAL_JUMBO,
|
SPUT_BOOLEAN_JUMBO, SPUT_BYTE_JUMBO, SPUT_CHAR_JUMBO, SPUT_SHORT_JUMBO, INVOKE_VIRTUAL_JUMBO,
|
||||||
INVOKE_SUPER_JUMBO, INVOKE_DIRECT_JUMBO, INVOKE_STATIC_JUMBO, INVOKE_INTERFACE_JUMBO);
|
INVOKE_SUPER_JUMBO, INVOKE_DIRECT_JUMBO, INVOKE_STATIC_JUMBO, INVOKE_INTERFACE_JUMBO,
|
||||||
|
INVOKE_OBJECT_INIT_RANGE);
|
||||||
|
addOpcodes(INVOKE_DIRECT_EMPTY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -680,6 +680,9 @@ INSTRUCTION_FORMAT3rc_METHOD
|
|||||||
| 'invoke-static/range'
|
| 'invoke-static/range'
|
||||||
| 'invoke-interface/range';
|
| 'invoke-interface/range';
|
||||||
|
|
||||||
|
INSTRUCTION_FORMAT3rc_METHOD_ODEX
|
||||||
|
: 'invoke-object-init/range';
|
||||||
|
|
||||||
INSTRUCTION_FORMAT3rc_TYPE
|
INSTRUCTION_FORMAT3rc_TYPE
|
||||||
: 'filled-new-array/range';
|
: 'filled-new-array/range';
|
||||||
|
|
||||||
|
@ -827,6 +827,11 @@ instruction returns [int size]
|
|||||||
| //e.g. invoke-virtual/range {v25..v26}, java/lang/StringBuilder/append(Ljava/lang/String;)Ljava/lang/StringBuilder;
|
| //e.g. invoke-virtual/range {v25..v26}, java/lang/StringBuilder/append(Ljava/lang/String;)Ljava/lang/StringBuilder;
|
||||||
INSTRUCTION_FORMAT3rc_METHOD OPEN_BRACE register_range CLOSE_BRACE COMMA fully_qualified_method {$size = Format.Format3rc.size;}
|
INSTRUCTION_FORMAT3rc_METHOD OPEN_BRACE register_range CLOSE_BRACE COMMA fully_qualified_method {$size = Format.Format3rc.size;}
|
||||||
-> ^(I_STATEMENT_FORMAT3rc_METHOD[$start, "I_STATEMENT_FORMAT3rc_METHOD"] INSTRUCTION_FORMAT3rc_METHOD register_range fully_qualified_method)
|
-> ^(I_STATEMENT_FORMAT3rc_METHOD[$start, "I_STATEMENT_FORMAT3rc_METHOD"] INSTRUCTION_FORMAT3rc_METHOD register_range fully_qualified_method)
|
||||||
|
| //e.g. invoke-object-init/range {p0}, Ljava/lang/Object;-><init>()V
|
||||||
|
INSTRUCTION_FORMAT3rc_METHOD_ODEX OPEN_BRACE register_list CLOSE_BRACE COMMA fully_qualified_method
|
||||||
|
{
|
||||||
|
throwOdexedInstructionException(input, $INSTRUCTION_FORMAT3rc_METHOD_ODEX.text);
|
||||||
|
}
|
||||||
| //e.g. filled-new-array/range {v0..v6}, I
|
| //e.g. filled-new-array/range {v0..v6}, I
|
||||||
INSTRUCTION_FORMAT3rc_TYPE OPEN_BRACE register_range CLOSE_BRACE COMMA nonvoid_type_descriptor {$size = Format.Format3rc.size;}
|
INSTRUCTION_FORMAT3rc_TYPE OPEN_BRACE register_range CLOSE_BRACE COMMA nonvoid_type_descriptor {$size = Format.Format3rc.size;}
|
||||||
-> ^(I_STATEMENT_FORMAT3rc_TYPE[$start, "I_STATEMENT_FORMAT3rc_TYPE"] INSTRUCTION_FORMAT3rc_TYPE register_range nonvoid_type_descriptor)
|
-> ^(I_STATEMENT_FORMAT3rc_TYPE[$start, "I_STATEMENT_FORMAT3rc_TYPE"] INSTRUCTION_FORMAT3rc_TYPE register_range nonvoid_type_descriptor)
|
||||||
|
@ -550,6 +550,10 @@ Type = {PrimitiveType} | {ClassDescriptor} | {ArrayDescriptor}
|
|||||||
return newToken(INSTRUCTION_FORMAT3rc_METHOD);
|
return newToken(INSTRUCTION_FORMAT3rc_METHOD);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"invoke-object-init/range" {
|
||||||
|
return newToken(INSTRUCTION_FORMAT3rc_METHOD_ODEX);
|
||||||
|
}
|
||||||
|
|
||||||
"filled-new-array/range" {
|
"filled-new-array/range" {
|
||||||
return newToken(INSTRUCTION_FORMAT3rc_TYPE);
|
return newToken(INSTRUCTION_FORMAT3rc_TYPE);
|
||||||
}
|
}
|
||||||
|
@ -210,6 +210,7 @@ invoke-static
|
|||||||
invoke-interface
|
invoke-interface
|
||||||
filled-new-array
|
filled-new-array
|
||||||
invoke-direct-empty
|
invoke-direct-empty
|
||||||
|
invoke-object-init/range
|
||||||
throw-verification-error
|
throw-verification-error
|
||||||
execute-inline
|
execute-inline
|
||||||
invoke-virtual-quick
|
invoke-virtual-quick
|
||||||
|
@ -210,6 +210,7 @@ INSTRUCTION_FORMAT35c_METHOD("invoke-static")
|
|||||||
INSTRUCTION_FORMAT35c_METHOD("invoke-interface")
|
INSTRUCTION_FORMAT35c_METHOD("invoke-interface")
|
||||||
INSTRUCTION_FORMAT35c_TYPE("filled-new-array")
|
INSTRUCTION_FORMAT35c_TYPE("filled-new-array")
|
||||||
INSTRUCTION_FORMAT35s_METHOD("invoke-direct-empty")
|
INSTRUCTION_FORMAT35s_METHOD("invoke-direct-empty")
|
||||||
|
INSTRUCTION_FORMAT3rc_METHOD_ODEX("invoke-object-init/range")
|
||||||
INSTRUCTION_FORMAT20bc("throw-verification-error")
|
INSTRUCTION_FORMAT20bc("throw-verification-error")
|
||||||
INSTRUCTION_FORMAT35mi_METHOD("execute-inline")
|
INSTRUCTION_FORMAT35mi_METHOD("execute-inline")
|
||||||
INSTRUCTION_FORMAT35ms_METHOD("invoke-virtual-quick")
|
INSTRUCTION_FORMAT35ms_METHOD("invoke-virtual-quick")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user