dex2jar源码解析----解析dex文件<三>

本文深入解析dex2jar工具的源码,从解析dex文件到生成IR,再到IR转换为JVM指令,详细介绍了dex2ir和ir2j过程,包括指令转换、帧初始化和指令重构等关键步骤。
摘要由CSDN通过智能技术生成

接上篇,我们从convertCode开始看

    public void convertCode(DexMethodNode methodNode, MethodVisitor mv) {
        IrMethod irMethod = dex2ir(methodNode);//主要是创建了它的stmts 把dex类型的指令转换为ir类型的指令
        optimize(irMethod);//对ir类型的指令进行优化
        ir2j(irMethod, mv);//把优化后的Ir指令转换为java虚拟机指令
    }
主要是3步,上面注释写的比较详细了

先看dex2ir

    public IrMethod dex2ir(DexMethodNode methodNode) {
        return new Dex2IRConverter()
                .convert(0 != (methodNode.access & DexConstants.ACC_STATIC), methodNode.method, methodNode.codeNode);
    }
新建一个Dex2IRConverter并调用它的convert

public IrMethod convert(boolean isStatic, Method method, DexCodeNode dexCodeNode) {
        this.dexCodeNode = dexCodeNode;//设置DexCodeNode
        IrMethod irMethod = new IrMethod();//创建一个IrMethod
        irMethod.args = method.getParameterTypes();
        irMethod.ret = method.getReturnType();
        irMethod.owner = method.getOwner();
        irMethod.name = method.getName();
        irMethod.isStatic = isStatic;
        target = irMethod;


        insnList = dexCodeNode.stmts;
        for (int i = 0; i < insnList.size(); i++) {//是否有标签
            DexStmtNode stmtNode = insnList.get(i);
            stmtNode.__index = i;//设置 __index
            if (stmtNode instanceof DexLabelStmtNode) {
                DexLabelStmtNode dexLabelStmtNode = (DexLabelStmtNode) stmtNode;
                labelMap.put(dexLabelStmtNode.label, dexLabelStmtNode);
            }
        }

        fixExceptionHandlers();//异常处理指令相关

        BitSet[] exBranch = new BitSet[insnList.size()];
        parentCount = new int[insnList.size()];
        initParentCount(parentCount);//初始化parentCount

        BitSet handlers = new BitSet(insnList.size());
        initExceptionHandlers(dexCodeNode, exBranch, handlers);

        DvmInterpreter<DvmValue> interpreter = buildInterpreter();//创建一个DvmInterpreter
        frames = new Dex2IrFrame[insnList.size()];//frames是指令的大小
        emitStmts = new ArrayList[insnList.size()];//
        BitSet access = new BitSet(insnList.size());//已经访问过的指令

        dfs(exBranch, handlers, access, interpreter);


        StmtList stmts = target.stmts;
        stmts.addAll(preEmit);
        for (int i = 0; i < insnList.size(); i++) {
            DexStmtNode p = insnList.get(i);
            if (access.get(i)) {
                List<Stmt> es = emitStmts[i];
                if (es != null) {
                    stmts.addAll(es);//添加到stmts
                }
            } else {
                if (p instanceof DexLabelStmtNode) {
                    stmts.add(getLabel(((DexLabelStmtNode) p).label));
                }
            }
        }
        emitStmts = null;//emitStmts重新设置为null


        Queue<DvmValue> queue = new LinkedList<>();

        for (int i1 = 0; i1 < frames.length; i1++) {
            Dex2IrFrame frame = frames[i1];
            if (parentCount[i1] > 1 && frame != null && access.get(i1)) {
                for (int j = 0; j < frame.getTotalRegisters(); j++) {
                    DvmValue v = frame.getReg(j);
                    addToQueue(queue, v);
                }
            }

        }

        while (!queue.isEmpty()) {
            DvmValue v = queue.poll();
            getLocal(v);
            if (v.parent != null) {
                if (v.parent.local == null) {
                    queue.add(v.parent);
                }
            }
            if (v.otherParent != null) {
                for (DvmValue v2 : v.otherParent) {
                    if (v2.local == null) {
                        queue.add(v2);
                    }
                }
            }
        }

        Set<com.googlecode.dex2jar.ir.expr.Value> phiValues = new HashSet<>();
        List<LabelStmt> phiLabels = new ArrayList<>();
        for (int i = 0; i < frames.length; i++) {
            Dex2IrFrame frame = frames[i];
            if (parentCount[i] > 1 && frame != null && access.get(i)) {
                DexStmtNode p = insnList.get(i);
                LabelStmt labelStmt = getLabel(((DexLabelStmtNode) p).label);
                List<AssignStmt> phis = new ArrayList<>();
                for (int j = 0; j < frame.getTotalRegisters(); j++) {
                    DvmValue v = frame.getReg(j);
                    addPhi(v, phiValues, phis);
                }

                labelStmt.phis = phis;
                phiLabels.add(labelStmt);
            }
        }
        if (phiLabels.size() > 0) {
            target.phiLabels = phiLabels;//好像主要是后面指令优化时候要用
        }

        return target;
    }

这个函数比较长,主要做了如下几件事:

1、新建一个IrMethod

2、处理标签

3、处理异常指令

4、初始化parentCount,主要跟跳转等有关

5、调用dfs进行指令转换

6、把处理完的指令添加到target.stmts

我们看下dfs函数

 private void dfs(BitSet[] exBranch, BitSet handlers, BitSet access, DvmInterpreter<DvmValue> interpreter) {
        currentEmit = preEmit;

        Dex2IrFrame first = initFirstFrame(dexCodeNode, target);//初始化第一个帧
        if (parentCount[0] > 1) {
            merge(first, 0);
        } else {
            frames[0] = first;
        }
        Stack<DexStmtNode> stack = new Stack<>();
        stack.push(insnList.get(0));
        Dex2IrFrame tmp = new Dex2IrFrame(dexCodeNode.totalRegister);//创建一个临时的帧


        while (!stack.isEmpty()) {
            DexStmtNode p = stack.pop();
            int index = p.__index;//获取指令的索引index
            if (!access.get(index)) {//是否已经处理过
                access.set(index);
            } else {
                continue;
        }
        Dex2IrFrame frame = frames[index];//frames大小为dex指令的大小
        setCurrentEmit(index);//如果为空则新建一个

            if (p instanceof DexLabelStmtNode) {//标签指令节点
                emit(getLabel(((DexLabelStmtNode) p).label));
                if (handlers.get(index)) {
                    Local ex = newLocal();
                    emit(Stmts.nIdentity(ex, Exprs.nExceptionRef("Ljava/lang/Throwable;")));
                    frame.setTmp(new DvmValue(ex));
                }
            }
            BitSet ex = exBranch[index];//跳转
            if (ex != null) {
                for (int i = ex.nextSetBit(0); i >= 0; i = ex.nextSetBit(i + 1)) {
                    merge(frame, i);
                    stack.push(insnList.get(i));
                }
            }

            tmp.init(frame);//用frame初始化tmp
            try {
                if (p.op != null) {
                    switch (p.op) {
                        case RETURN_VOID:
                            emit(nReturnVoid());//添加一个ReturnVoidStmt
                            break;
                        case GOTO:
                        case GOTO_16:
                        case GOTO_32:
                            emit(nGoto(getLabel(((JumpStmtNode) p).label)));
                            break;
                        case NOP:
                            emit(nNop());
                            break;
                        case BAD_OP:
                            emit(nThrow(nInvokeNew(new Value[]{nString("bad dex opcode")}, new String[]{
                                            "Ljava/lang/String;"},
                                    "Ljava/lang/VerifyError;")));
                            break;
                        default:
                            tmp.execute(p, interpreter);//缺省情况执行execute tmp为Dex2IrFrame
                            break;
                    }
                }
            } catch (Exception exception) {
                throw new RuntimeException("Fail on Op " + p.op + " index " + index, exception);
            }


            if (p.op != null) {
                Op op = p.op;
                if (op.canBranch()) {//分支指令,则把条件不满足时的指令偏移入栈
                    JumpStmtNode jump = (JumpStmtNode) p;
                    int targetIndex = indexOf(jump.label);
                    stack.push(insnList.get(targetIndex));
                    merge(tmp, targetIndex);
                }
                if (op.canSwitch()) {
                    BaseSwitchStmtNode switchStmtNode = (BaseSwitchStmtNode) p;
                    for (DexLabel label : switchStmtNode.labels) {
                        int targetIndex = indexOf(label);
                        stack.push(insnList.get(targetIndex));
                        merge(tmp, targetIndex);
                    }
                }
                if (op.canContinue()) {//继续下一条
                    stack.push(insnList.get(index + 1));//下一条指令入栈
                    merge(tmp, index + 1);//把temp和index+1进行merge
                }
            } else {

                stack.push(insnList.get(index + 1));
                merge(tmp, index + 1);

            }
            // cleanup frame it is useless
            if (parentCount[index] <= 1) {//重新设置为null
                frames[index] = null;
            }

        }

    }

这个函数也是比较长,主要做了如下工作:

1、调用initFirstFrame初始化第一个帧

2、依次处理各条指令

我们先看initFirstFrame

 private Dex2IrFrame initFirstFrame(DexCodeNode methodNode, IrMethod target) {
        Dex2IrFrame first = new Dex2IrFrame(methodNode.totalRegister);//总的寄存器个数
        int x = methodNode.totalRegister - methodArgCount(target.args);//减去参数使用的寄存器个数
        if (!target.isStatic) {// not static 非静态方法第一个参数是this
            Local thiz = newLocal();
            emit(Stmts.nIdentity(thiz, Exprs.nThisRef(target.owner)));//新建一个this变量
            first.setReg(x - 1, new DvmValue(thiz));//参数的前面一个寄存器摄者为this
        }
        for (int i = 0; i < target.args.length; i++) {//依次对应参数到寄存器,寄存器的下标依据添加的顺序
            Local p = newLocal();
            emit(Stmts.nIdentity(p, Exprs.nParameterRef(target.args[i], i)));
            first.setReg(x, new DvmValue(p));
            x += sizeofType(target.args[i]);//递增它的类型大小
        }

        if (initAllToZero) {//把所有寄存器的初始值设置为0
            for (int i
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值