Handle unresolvable instructions in a more intellegent manner

Don't replace an unresolvable instruction with replacement instruction(s) that
are larger, to avoid inserting extra bytes, and possibly moving jump type
instructions too far from their targets.

git-svn-id: https://smali.googlecode.com/svn/trunk@497 55b6fa8a-2a1e-11de-a435-ffa8d773f76a
This commit is contained in:
JesusFreke@JesusFreke.com 2009-12-23 05:24:27 +00:00
parent b6ce091ae3
commit e24e70f9ad
4 changed files with 83 additions and 6 deletions

View File

@ -34,6 +34,16 @@ import org.antlr.stringtemplate.StringTemplateGroup;
import org.antlr.stringtemplate.StringTemplate;
public class UnresolvedNullReferenceMethodItem extends InstructionFormatMethodItem<UnresolvedNullReference> {
private boolean isLastInstruction;
public boolean getIsLastInstruction() {
return isLastInstruction;
}
public void setIsLastInstruction(boolean isLastInstruction) {
this.isLastInstruction = isLastInstruction;
}
public UnresolvedNullReferenceMethodItem(CodeItem codeItem, int offset, StringTemplateGroup stg,
UnresolvedNullReference instruction) {
super(codeItem, offset, stg, instruction);
@ -41,5 +51,15 @@ public class UnresolvedNullReferenceMethodItem extends InstructionFormatMethodIt
protected void setAttributes(StringTemplate template) {
template.setAttribute("Register", formatRegister(instruction.ObjectRegisterNum));
switch (instruction.OriginalInstruction.opcode)
{
case INVOKE_VIRTUAL_RANGE_QUICK:
case INVOKE_SUPER_RANGE_QUICK:
template.setAttribute("UseInvokeRange", 1);
if (isLastInstruction) {
template.setAttribute("AddGoto", 1);
}
}
}
}

View File

@ -227,6 +227,23 @@ public class MethodDefinition {
offset += instruction.getSize()/2;
}
/*
* Look for the last uncommented instruction. If it is an UnresolvedNullReference,
* then set IsLastInstruction, so a goto will be added after it, to avoid validation
* issues
*/
for (int i=this.instructions.size()-1; i>=0; i--) {
MethodItem ins = this.instructions.get(i);
if (ins instanceof UnresolvedNullReferenceMethodItem) {
((UnresolvedNullReferenceMethodItem)ins).setIsLastInstruction(true);
break;
}
if (!(ins instanceof CommentedOutMethodItem)) {
break;
}
}
} else {
final byte[] encodedInstructions = codeItem.getEncodedInstructions();
@ -543,7 +560,7 @@ public class MethodDefinition {
if (index < 0) {
index = (index * -1) - 1;
}
//index should never by 0, so this should be safe
//index should never be 0, so this should be safe
if (index == instructions.size()) {
//if the end address is the same as the address of the last instruction, then
//this try item ends at the next to last instruction.

View File

@ -288,16 +288,20 @@ CommentedOutMethodItem(MethodItem) ::=
#<MethodItem>
>>
UnresolvedNullReference(Opcode, Register) ::=
UnresolvedNullReference(Opcode, Register, UseInvokeRange, AddGoto) ::=
<<
#Couldn't resolve optimized instruction while deodexing, due to the object register
#always being null. Replaced with generic method call
<if(UseInvokeRange)>
#Replaced unresolvable optimized invoke-*-range-quick instruction
#with a generic method call that will throw a NullPointerException
invoke-virtual/range {<Register> .. <Register>}, Ljava/lang/Object;->hashCode()I
goto/32 0
<if(AddGoto)>goto/32 0<endif>
<else>
#Replaced unresolvable optimized instruction with a throw
throw <Register>
<endif>
>>
ArrayData(Opcode, ElementWidth, Values) ::=
<<
.array-data <ElementWidth>

View File

@ -72,3 +72,39 @@
return-void
.end method
.method public static UnresolvedInstructionTest1()Lsuperclass;
.registers 2
const v0, 0
#this is an unresolvable instruction, due to v0 always being null
#this instruction should be replaced with "throw v0", followed by
#a "goto/32 0", since it would otherwise be the last instruction
#in the method, which isn't allowed
invoke-virtual/range {v0 .. v0}, Lrandomclass;->getSuperclass()Lsuperclass;
#the following instructions should be commented out
move-result-object v1
return-object v1
.end method
.method public static UnresolvedInstructionTest2()Lsuperclass;
.registers 2
const v0, 0
if-eqz v0, :here
#this is an unresolvable instruction, due to v0 always being null
#this instruction should be replaced with "throw v0". There shouldn't
#be a "goto/32 0" afterwards, since it won't be the last instruction
#in the method.
invoke-virtual/range {v0 .. v0}, Lrandomclass;->getSuperclass()Lsuperclass;
#the following instructions should be commented out
move-result-object v1
return-object v1
#and now back to our normal programming
:here
return-object v0
.end method