changeset 45:1b283cb77127

Perform mapping between calling conventions. Contributed-by: Remi Forax * dex/dexlib/DexLibDexReader.java: Correctly pass inWords and outWords. * rewriter/DexRewriter.java: Map Dalvik registers to Java slots correctly. * rewriter/Registers.java (packRegisters): New utility method.
author Michael Starzinger <michi@complang.tuwien.ac.at>
date Sat, 19 Mar 2011 15:37:50 +0100
parents e47fc744d6b4
children bac8d9297f30
files src/main/java/org/icedrobot/daneel/dex/dexlib/DexLibDexReader.java src/main/java/org/icedrobot/daneel/rewriter/DexRewriter.java src/main/java/org/icedrobot/daneel/rewriter/Registers.java
diffstat 3 files changed, 98 insertions(+), 22 deletions(-) [+]
line wrap: on
line diff
--- a/src/main/java/org/icedrobot/daneel/dex/dexlib/DexLibDexReader.java	Sat Mar 19 10:18:40 2011 +0100
+++ b/src/main/java/org/icedrobot/daneel/dex/dexlib/DexLibDexReader.java	Sat Mar 19 15:37:50 2011 +0100
@@ -39,6 +39,7 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.lang.reflect.Field;
 import java.util.HashMap;
 import java.util.List;
 
@@ -48,6 +49,7 @@
 import org.icedrobot.daneel.dex.DexMethodVisitor;
 import org.icedrobot.daneel.dex.DexReader;
 import org.icedrobot.daneel.dex.Opcode;
+import org.icedrobot.daneel.rewriter.Registers;
 import org.jf.dexlib.ClassDataItem;
 import org.jf.dexlib.ClassDataItem.EncodedField;
 import org.jf.dexlib.ClassDataItem.EncodedMethod;
@@ -235,14 +237,39 @@
 
                 // visit attribute
 
-                mv.visitCode(codeItem.getRegisterCount(), -1, -1); // FIXME
-                                                                   // insSize/outSize
+                int inWords, outWords;
+                try {
+                    inWords = IN_WORDS.getInt(codeItem);
+                    outWords = OUT_WORDS.getInt(codeItem);
+                } catch (IllegalArgumentException e) {
+                    throw (AssertionError) new AssertionError().initCause(e);
+                } catch (IllegalAccessException e) {
+                    throw (AssertionError) new AssertionError().initCause(e);
+                }
+
+                mv.visitCode(codeItem.getRegisterCount(), inWords, outWords);
                 acceptCode(codeItem, mv);
                 mv.visitEnd();
             }
         }
     }
 
+    private static final Field IN_WORDS;
+    private static final Field OUT_WORDS;
+    static {
+        Field inWords, outWords;
+        try {
+            inWords = CodeItem.class.getDeclaredField("inWords");
+            outWords = CodeItem.class.getDeclaredField("outWords");
+        } catch (NoSuchFieldException e) {
+            throw (AssertionError) new AssertionError().initCause(e);
+        }
+        inWords.setAccessible(true);
+        outWords.setAccessible(true);
+        IN_WORDS = inWords;
+        OUT_WORDS = outWords;
+    }
+
     private static String[] asDescriptorArray(ProtoIdItem protoIdItem) {
         TypeListItem parameters = protoIdItem.getParameters();
         if (parameters == null) {
@@ -358,17 +385,18 @@
 
         case INSTR_METHOD: {
             int va, vpacked, size;
-            if (instr instanceof RegisterRangeInstruction) {  // range
-        	RegisterRangeInstruction rangeInstr = (RegisterRangeInstruction)instr;
-        	size = rangeInstr.getRegCount();
-        	va = rangeInstr.getStartRegister();
-        	vpacked = 0;
+            if (instr instanceof RegisterRangeInstruction) { // range
+                RegisterRangeInstruction rangeInstr = (RegisterRangeInstruction) instr;
+                size = rangeInstr.getRegCount();
+                va = rangeInstr.getStartRegister();
+                vpacked = 0;
             } else { // packed
-        	FiveRegisterInstruction fiveInstr = (FiveRegisterInstruction)instr;
-        	size = fiveInstr.getRegCount();
-        	va = fiveInstr.getRegisterA();
-        	vpacked = fiveInstr.getRegisterG() << 12 | fiveInstr.getRegisterF() << 8
-        	| fiveInstr.getRegisterE() << 4 | fiveInstr.getRegisterD();
+                FiveRegisterInstruction fiveInstr = (FiveRegisterInstruction) instr;
+                size = fiveInstr.getRegCount();
+                va = fiveInstr.getRegisterA();
+                vpacked = Registers.packRegisters(fiveInstr.getRegisterD(),
+                        fiveInstr.getRegisterE(), fiveInstr.getRegisterF(),
+                        fiveInstr.getRegisterG());
             }
             InstructionWithReference refInstr = (InstructionWithReference) instr;
             MethodIdItem methodIdItem = (MethodIdItem) refInstr.getReferencedItem();
--- a/src/main/java/org/icedrobot/daneel/rewriter/DexRewriter.java	Sat Mar 19 10:18:40 2011 +0100
+++ b/src/main/java/org/icedrobot/daneel/rewriter/DexRewriter.java	Sat Mar 19 15:37:50 2011 +0100
@@ -140,11 +140,27 @@
         private Interpreter interpreter;
         private int returnRegisterType; // type of the register used to stored
                                         // the return value
+        private int locals;             // number of local variables
+        private int parameters;         // number of parameters
 
         public MethodRewriter(MethodVisitor mv) {
             this.mv = new PatchMethodVisitor(mv);
         }
 
+        /**
+         * Translate a register with Dalvik calling convention to a slot with
+         * Java calling convention
+         * 
+         * @param register the register
+         * @return the corresponding Java slot.
+         */
+        private int registerToSlot(int register) {
+            if (register >= locals) { // it's a parameter
+                return register - locals;
+            } // otherwise it's a local variable
+            return parameters + register;
+        }
+
         private static int getTypeFromASMType(Type type) {
             switch (type.getSort()) {
             case Type.BOOLEAN:
@@ -185,6 +201,8 @@
         @Override
         public void visitCode(int registerSize, int insSize, int outSize) {
             mv.visitCode();
+            this.locals = registerSize - insSize;
+            this.parameters = insSize;
             interpreter = new Interpreter(registerSize);
         }
 
@@ -205,6 +223,8 @@
         @Override
         public void visitInstrField(Opcode opcode, int vsrcOrDest, int vref,
                 String owner, String name, String desc) {
+            vsrcOrDest = registerToSlot(vsrcOrDest);
+            vref = registerToSlot(vref);
             owner = TypeUtil.convertDescToInternal(owner);
             if (opcode.compareTo(Opcode.IGET) >= 0
                     && opcode.compareTo(Opcode.IGET_SHORT) <= 0) {
@@ -241,6 +261,7 @@
 
         @Override
         public void visitInstrConstString(Opcode opcode, int vdest, String value) {
+            vdest = registerToSlot(vdest);
             mv.visitLdcInsn(value);
             mv.visitVarInsn(ASTORE, vdest);
             interpreter.store(vdest, OBJECT_TYPE);
@@ -289,7 +310,8 @@
             int r;
             if (erasedRangeOpcode != Opcode.INVOKE_STATIC) {
                 r = 1;
-                int register = (registers == null) ? va : registers[0];
+                int register = registerToSlot((registers == null) ? va
+                        : registers[0]);
                 mv.visitVarInsn(ALOAD, register);
                 interpreter.load(register, OBJECT_TYPE);
             } else {
@@ -299,7 +321,8 @@
             Type[] types = Type.getArgumentTypes(desc);
             for (Type asmType : types) {
                 int type = getTypeFromASMType(asmType);
-                int register = (registers == null) ? va + r : registers[r];
+                int register = registerToSlot((registers == null) ? va + r
+                        : registers[r]);
                 mv.visitVarInsn(Register.getJavaOpcode(type, ILOAD), register);
                 interpreter.load(register, type);
                 r += asmType.getSize();
@@ -316,40 +339,42 @@
                 Opcode.INVOKE_VIRTUAL.ordinal();
 
         @Override
-        public void visitInstrConstU32(Opcode opcode, final int vdest,
+        public void visitInstrConstU32(Opcode opcode, int vdest,
                 final int value) {
+            final int sdest = registerToSlot(vdest);
             mv.setPatchMode();
             mv.visitLdcInsn(value);
             final AbstractInsnNode ldc = mv.getLastInsnNode();
-            mv.visitVarInsn(ISTORE, vdest);
+            mv.visitVarInsn(ISTORE, sdest);
             final AbstractInsnNode istore = mv.getLastInsnNode();
-            interpreter.storeArbitraryType(vdest, U32_TYPE, new Patchable() {
+            interpreter.storeArbitraryType(sdest, U32_TYPE, new Patchable() {
                 @Override
                 protected void patch(int registerType) {
                     if (registerType == FLOAT_TYPE) {
                         mv.patch(ldc, new LdcInsnNode(Float
                                 .intBitsToFloat(value)));
-                        mv.patch(istore, new VarInsnNode(FSTORE, vdest));
+                        mv.patch(istore, new VarInsnNode(FSTORE, sdest));
                     }
                 }
             });
         }
 
         @Override
-        public void visitInstrConstU64(Opcode opcode, final int vdest,
+        public void visitInstrConstU64(Opcode opcode, int vdest,
                 final long value) {
+            final int sdest = registerToSlot(vdest);
             mv.setPatchMode();
             mv.visitLdcInsn(value);
             final AbstractInsnNode ldc = mv.getLastInsnNode();
-            mv.visitVarInsn(LSTORE, vdest);
+            mv.visitVarInsn(LSTORE, sdest);
             final AbstractInsnNode lstore = mv.getLastInsnNode();
-            interpreter.storeArbitraryType(vdest, U64_TYPE, new Patchable() {
+            interpreter.storeArbitraryType(sdest, U64_TYPE, new Patchable() {
                 @Override
                 protected void patch(int registerType) {
                     if (registerType == DOUBLE_TYPE) {
                         mv.patch(ldc,
                                 new LdcInsnNode(Double.longBitsToDouble(value)));
-                        mv.patch(lstore, new VarInsnNode(DSTORE, vdest));
+                        mv.patch(lstore, new VarInsnNode(DSTORE, sdest));
                     }
                 }
             });
@@ -364,35 +389,44 @@
         @Override
         public void visitInstrArray(Opcode opcode, int vsrcOrDest, int varray,
                 int vindex) {
+            vsrcOrDest = registerToSlot(vsrcOrDest);
             throw new UnsupportedOperationException("NYI " + opcode);
         }
 
         @Override
         public void visitInstrBinOp(Opcode opcode, int vdest, int vsrc,
                 int vsrc2) {
+            vdest = registerToSlot(vdest);
+            vsrc = registerToSlot(vsrc);
+            vsrc2 = registerToSlot(vsrc2);
             throw new UnsupportedOperationException("NYI " + opcode);
         }
 
         @Override
         public void visitInstrBinOpAndLiteral(Opcode opcode, int vdest,
                 int vsrc, int value) {
+            vdest = registerToSlot(vdest);
+            vsrc = registerToSlot(vsrc);
             throw new UnsupportedOperationException("NYI " + opcode);
         }
 
         @Override
         public void visitInstrClass(Opcode opcode, int vdest, String type) {
+            vdest = registerToSlot(vdest);
             throw new UnsupportedOperationException("NYI " + opcode);
         }
 
         @Override
         public void visitInstrFillArrayData(Opcode opcode, int vsrc,
                 Object arrayData) {
+            vsrc = registerToSlot(vsrc);
             throw new UnsupportedOperationException("NYI " + opcode);
         }
 
         @Override
         public void visitInstrFilledNewArray(Opcode opcode, int num, int va,
                 int vpacked, String type) {
+            // don't forget to use registerToSlot
             throw new UnsupportedOperationException("NYI " + opcode);
         }
 
@@ -404,39 +438,49 @@
         @Override
         public void visitInstrIfTest(Opcode opcode, int vsrc1, int vsrc2,
                 Label label) {
+            vsrc1 = registerToSlot(vsrc1);
+            vsrc2 = registerToSlot(vsrc2);
             throw new UnsupportedOperationException("NYI " + opcode);
         }
 
         @Override
         public void visitInstrIfTestZ(Opcode opcode, int vsrc, Label label) {
+            vsrc = registerToSlot(vsrc);
             throw new UnsupportedOperationException("NYI " + opcode);
         }
 
         @Override
         public void visitInstrInstanceof(Opcode opcode, int vdest, int vsrc,
                 String type) {
+            vdest = registerToSlot(vdest);
+            vsrc = registerToSlot(vsrc);
             throw new UnsupportedOperationException("NYI " + opcode);
         }
 
         @Override
         public void visitInstrNewArray(Opcode opcode, int vdest, int vsize,
                 String type) {
+            vdest = registerToSlot(vdest);
             throw new UnsupportedOperationException("NYI " + opcode);
         }
 
         @Override
         public void visitInstrOp(Opcode opcode, int srcOrDst) {
+            srcOrDst = registerToSlot(srcOrDst);
             throw new UnsupportedOperationException("NYI " + opcode);
         }
 
         @Override
         public void visitInstrSwitch(Opcode opcode, int vsrc,
                 Map<Integer, Label> labels) {
+            vsrc = registerToSlot(vsrc);
             throw new UnsupportedOperationException("NYI " + opcode);
         }
 
         @Override
         public void visitInstrUnaryOp(Opcode opcode, int vdest, int vsrc) {
+            vdest = registerToSlot(vdest);
+            vsrc = registerToSlot(vsrc);
             throw new UnsupportedOperationException("NYI " + opcode);
         }
 
--- a/src/main/java/org/icedrobot/daneel/rewriter/Registers.java	Sat Mar 19 10:18:40 2011 +0100
+++ b/src/main/java/org/icedrobot/daneel/rewriter/Registers.java	Sat Mar 19 15:37:50 2011 +0100
@@ -57,4 +57,8 @@
     public static int getRegisterG(int packed) {
         return (packed >> 12) & 0x0F;
     }
+
+    public static int packRegisters(int vd, int ve, int vf, int vg) {
+        return vg << 12 | vf << 8 | ve << 4 | vd;
+    }
 }