mirror of
https://github.com/revanced/smali.git
synced 2025-05-09 10:54:29 +02:00
Iterative logic to handle embiggening of goto instructions, when subsequent code shifts are inserted. Layout logic creates a HashMap of predicted instruction replacements and nop insertions to be used later in writing method, which is more cromulent solution than simply replicating the logic, given its iterativeness.
This commit is contained in:
parent
15ae0affc4
commit
5df16db108
@ -50,6 +50,7 @@ import org.jf.util.ExceptionWithContext;
|
|||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class InstructionWriteUtil {
|
public class InstructionWriteUtil {
|
||||||
@ -58,6 +59,7 @@ public class InstructionWriteUtil {
|
|||||||
|
|
||||||
private List<Instruction> instructions;
|
private List<Instruction> instructions;
|
||||||
private ArrayList<Integer> codeOffsetShifts;
|
private ArrayList<Integer> codeOffsetShifts;
|
||||||
|
private HashMap<Integer,Format> offsetToNewInstructionMap;
|
||||||
|
|
||||||
private int codeUnitCount;
|
private int codeUnitCount;
|
||||||
private int outParamCount;
|
private int outParamCount;
|
||||||
@ -148,7 +150,11 @@ public class InstructionWriteUtil {
|
|||||||
if (codeOffsetShifts == null) {
|
if (codeOffsetShifts == null) {
|
||||||
codeOffsetShifts = new ArrayList<Integer>();
|
codeOffsetShifts = new ArrayList<Integer>();
|
||||||
}
|
}
|
||||||
|
if (offsetToNewInstructionMap == null) {
|
||||||
|
offsetToNewInstructionMap = new HashMap<Integer,Format>();
|
||||||
|
}
|
||||||
codeOffsetShifts.add(currentCodeOffset+instruction.getCodeUnits());
|
codeOffsetShifts.add(currentCodeOffset+instruction.getCodeUnits());
|
||||||
|
offsetToNewInstructionMap.put(currentCodeOffset, instruction.getOpcode().format);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
currentCodeOffset += instruction.getCodeUnits();
|
currentCodeOffset += instruction.getCodeUnits();
|
||||||
@ -162,38 +168,55 @@ public class InstructionWriteUtil {
|
|||||||
// since code offset delta is equivalent to the position of instruction's code offset in the shift list,
|
// since code offset delta is equivalent to the position of instruction's code offset in the shift list,
|
||||||
// we use it as a position here
|
// we use it as a position here
|
||||||
// we also check if we will have to insert nops to ensure 4-byte alignment for switch statements and packed arrays
|
// we also check if we will have to insert nops to ensure 4-byte alignment for switch statements and packed arrays
|
||||||
currentCodeOffset = 0;
|
boolean shiftsInserted;
|
||||||
for (Instruction instruction: methodImplementation.getInstructions()) {
|
do {
|
||||||
if (instruction.getOpcode().format.equals(Format.Format10t)) {
|
currentCodeOffset = 0;
|
||||||
int targetOffset = ((Instruction10t)instruction).getCodeOffset();
|
shiftsInserted = false;
|
||||||
int codeOffsetDelta = codeOffsetShift(currentCodeOffset);
|
for (Instruction instruction: methodImplementation.getInstructions()) {
|
||||||
int newTargetOffset = targetOffset + targetOffsetShift(currentCodeOffset, targetOffset);
|
if (instruction.getOpcode().format.equals(Format.Format10t) && !offsetToNewInstructionMap.containsKey(currentCodeOffset)) {
|
||||||
if ((byte)newTargetOffset != newTargetOffset) {
|
int targetOffset = ((Instruction10t)instruction).getCodeOffset();
|
||||||
if ((short)newTargetOffset != newTargetOffset) {
|
int codeOffsetDelta = codeOffsetShift(currentCodeOffset);
|
||||||
// handling very small (negligible) possibility of goto becoming goto/32
|
int newTargetOffset = targetOffset + targetOffsetShift(currentCodeOffset, targetOffset);
|
||||||
// we insert extra 1 code unit shift referring to the same position
|
if ((byte)newTargetOffset != newTargetOffset) {
|
||||||
// this will cause subsequent code offsets to be shifted by 2 code units
|
if ((short)newTargetOffset != newTargetOffset) {
|
||||||
|
// handling very small (negligible) possibility of goto becoming goto/32
|
||||||
|
// we insert extra 1 code unit shift referring to the same position
|
||||||
|
// this will cause subsequent code offsets to be shifted by 2 code units
|
||||||
|
codeOffsetShifts.add(codeOffsetDelta, currentCodeOffset+instruction.getCodeUnits());
|
||||||
|
offsetToNewInstructionMap.put(currentCodeOffset, Format.Format30t);
|
||||||
|
} else {
|
||||||
|
offsetToNewInstructionMap.put(currentCodeOffset, Format.Format20t);
|
||||||
|
}
|
||||||
codeOffsetShifts.add(codeOffsetDelta, currentCodeOffset+instruction.getCodeUnits());
|
codeOffsetShifts.add(codeOffsetDelta, currentCodeOffset+instruction.getCodeUnits());
|
||||||
}
|
shiftsInserted = true;
|
||||||
codeOffsetShifts.add(codeOffsetDelta, currentCodeOffset+instruction.getCodeUnits());
|
}
|
||||||
|
} else if (instruction.getOpcode().format.equals(Format.Format20t) && !offsetToNewInstructionMap.containsKey(currentCodeOffset)) {
|
||||||
|
int targetOffset = ((Instruction20t)instruction).getCodeOffset();
|
||||||
|
int codeOffsetDelta = codeOffsetShift(currentCodeOffset);
|
||||||
|
int newTargetOffset = targetOffsetShift(currentCodeOffset, targetOffset);
|
||||||
|
if ((short)newTargetOffset != newTargetOffset) {
|
||||||
|
codeOffsetShifts.add(codeOffsetDelta, currentCodeOffset+instruction.getCodeUnits());
|
||||||
|
offsetToNewInstructionMap.put(currentCodeOffset, Format.Format30t);
|
||||||
|
shiftsInserted = true;
|
||||||
|
}
|
||||||
|
} else if (instruction.getOpcode().format.equals(Format.ArrayPayload)
|
||||||
|
|| instruction.getOpcode().format.equals(Format.SparseSwitchPayload)
|
||||||
|
|| instruction.getOpcode().format.equals(Format.PackedSwitchPayload)) {
|
||||||
|
int codeOffsetDelta = codeOffsetShift(currentCodeOffset);
|
||||||
|
if ((currentCodeOffset+codeOffsetDelta)%2 != 0) {
|
||||||
|
if (codeOffsetShifts.contains(currentCodeOffset)) {
|
||||||
|
codeOffsetShifts.remove(codeOffsetDelta);
|
||||||
|
offsetToNewInstructionMap.remove(currentCodeOffset);
|
||||||
|
} else {
|
||||||
|
codeOffsetShifts.add(codeOffsetDelta, currentCodeOffset);
|
||||||
|
offsetToNewInstructionMap.put(currentCodeOffset, Format.Format10x);
|
||||||
|
shiftsInserted = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (instruction.getOpcode().format.equals(Format.Format20t)) {
|
currentCodeOffset += instruction.getCodeUnits();
|
||||||
int targetOffset = ((Instruction20t)instruction).getCodeOffset();
|
}
|
||||||
int codeOffsetDelta = codeOffsetShift(currentCodeOffset);
|
} while (shiftsInserted);
|
||||||
int newTargetOffset = targetOffsetShift(currentCodeOffset, targetOffset);
|
|
||||||
if ((short)newTargetOffset != newTargetOffset) {
|
|
||||||
codeOffsetShifts.add(codeOffsetDelta, currentCodeOffset+instruction.getCodeUnits());
|
|
||||||
}
|
|
||||||
} else if (instruction.getOpcode().format.equals(Format.ArrayPayload)
|
|
||||||
|| instruction.getOpcode().format.equals(Format.SparseSwitchPayload)
|
|
||||||
|| instruction.getOpcode().format.equals(Format.PackedSwitchPayload)) {
|
|
||||||
int codeOffsetDelta = codeOffsetShift(currentCodeOffset);
|
|
||||||
if ((currentCodeOffset+codeOffsetDelta)%2 != 0) {
|
|
||||||
codeOffsetShifts.add(codeOffsetDelta, currentCodeOffset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
currentCodeOffset += instruction.getCodeUnits();
|
|
||||||
}
|
|
||||||
|
|
||||||
codeUnitCount += codeOffsetShifts.size();
|
codeUnitCount += codeOffsetShifts.size();
|
||||||
}
|
}
|
||||||
@ -212,16 +235,15 @@ public class InstructionWriteUtil {
|
|||||||
Instruction10t instr = (Instruction10t)instruction;
|
Instruction10t instr = (Instruction10t)instruction;
|
||||||
int targetOffset = instr.getCodeOffset();
|
int targetOffset = instr.getCodeOffset();
|
||||||
int newTargetOffset = targetOffset + targetOffsetShift(currentCodeOffset, targetOffset);
|
int newTargetOffset = targetOffset + targetOffsetShift(currentCodeOffset, targetOffset);
|
||||||
if (newTargetOffset != targetOffset) {
|
Format newInstructionFormat = offsetToNewInstructionMap.get(currentCodeOffset);
|
||||||
if ((byte)newTargetOffset != newTargetOffset) {
|
if (newInstructionFormat != null) {
|
||||||
if ((short)newTargetOffset != newTargetOffset) {
|
if (newInstructionFormat.equals(Format.Format30t)) {
|
||||||
modifiedInstruction = new ImmutableInstruction30t(Opcode.GOTO_32, newTargetOffset);
|
modifiedInstruction = new ImmutableInstruction30t(Opcode.GOTO_32, newTargetOffset);
|
||||||
} else {
|
} else if (newInstructionFormat.equals(Format.Format20t)) {
|
||||||
modifiedInstruction = new ImmutableInstruction20t(Opcode.GOTO_16, newTargetOffset);
|
modifiedInstruction = new ImmutableInstruction20t(Opcode.GOTO_16, newTargetOffset);
|
||||||
}
|
|
||||||
} else {
|
|
||||||
modifiedInstruction = new ImmutableInstruction10t(instr.getOpcode(), newTargetOffset);
|
|
||||||
}
|
}
|
||||||
|
} else if (newTargetOffset != targetOffset) {
|
||||||
|
modifiedInstruction = new ImmutableInstruction10t(instr.getOpcode(), newTargetOffset);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -229,12 +251,11 @@ public class InstructionWriteUtil {
|
|||||||
Instruction20t instr = (Instruction20t)instruction;
|
Instruction20t instr = (Instruction20t)instruction;
|
||||||
int targetOffset = instr.getCodeOffset();
|
int targetOffset = instr.getCodeOffset();
|
||||||
int newTargetOffset = targetOffset + targetOffsetShift(currentCodeOffset, targetOffset);
|
int newTargetOffset = targetOffset + targetOffsetShift(currentCodeOffset, targetOffset);
|
||||||
if (newTargetOffset != targetOffset) {
|
Format newInstructionFormat = offsetToNewInstructionMap.get(currentCodeOffset);
|
||||||
if ((short)newTargetOffset != newTargetOffset) {
|
if (newInstructionFormat != null && newInstructionFormat.equals(Format.Format30t)) {
|
||||||
modifiedInstruction = new ImmutableInstruction30t(Opcode.GOTO_32, newTargetOffset);
|
modifiedInstruction = new ImmutableInstruction30t(Opcode.GOTO_32, newTargetOffset);
|
||||||
} else {
|
} else if (newTargetOffset != targetOffset) {
|
||||||
modifiedInstruction = new ImmutableInstruction20t(Opcode.GOTO_16, newTargetOffset);
|
modifiedInstruction = new ImmutableInstruction20t(Opcode.GOTO_16, newTargetOffset);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -321,7 +342,8 @@ public class InstructionWriteUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void alignPayload(int codeOffset) {
|
private void alignPayload(int codeOffset) {
|
||||||
if (codeOffsetShifts.contains(codeOffset)) {
|
Format newInstructionFormat = offsetToNewInstructionMap.get(codeOffset);
|
||||||
|
if (newInstructionFormat != null && newInstructionFormat.equals(Format.Format10x)) {
|
||||||
instructions.add(new ImmutableInstruction10x(Opcode.NOP));
|
instructions.add(new ImmutableInstruction10x(Opcode.NOP));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user