xLua icon indicating copy to clipboard operation
xLua copied to clipboard

Hotfix导致部分注入函数IL报错

Open lizhengde opened this issue 2 years ago • 2 comments

  1. Hotfix.cs中fixBranch短格式跳转指令偏移计算与Mono.Ceil不一样,当刚好处于边界值时,会导致注入的函数运行时IL报错(超出sbyte范围)

  2. 修改短格式指令会导致前后其他短格式相对偏移量加大,需要再次遍历并修改

修改前

void fixBranch(ILProcessor processor, Mono.Collections.Generic.Collection<Instruction> instructions, Dictionary<Instruction, Instruction> originToNewTarget, HashSet<Instruction> noCheck)
{
    foreach(var instruction in instructions)
    {
        Instruction target = instruction.Operand as Instruction;
        if (target != null && !noCheck.Contains(instruction))
        {
            if (originToNewTarget.ContainsKey(target))
            {
                instruction.Operand = originToNewTarget[target];
            }
        }
    }

    int offset = 0;
    for (int i = 0; i < instructions.Count; i++)
    {
        var instruction = instructions[i];
        instruction.Offset = offset;
        offset += instruction.GetSize();
    }

    for (int i = 0; i < instructions.Count; i++)
    {
        var instruction = instructions[i];
        Instruction target = instruction.Operand as Instruction;
        
        if (target != null)
        {
            int diff = target.Offset - instruction.Offset;
            if ((diff > sbyte.MaxValue || diff < sbyte.MinValue) && shortToLong.ContainsKey(instruction.OpCode))
            {
                instructions[i] = processor.Create(shortToLong[instruction.OpCode], target);
            }
        }
    }
}

修改后

void fixBranch(ILProcessor processor, Mono.Collections.Generic.Collection<Instruction> instructions, Dictionary<Instruction, Instruction> originToNewTarget, HashSet<Instruction> noCheck)
{
    foreach(var instruction in instructions)
    {
        Instruction target = instruction.Operand as Instruction;
        if (target != null && !noCheck.Contains(instruction))
        {
            if (originToNewTarget.ContainsKey(target))
            {
                instruction.Operand = originToNewTarget[target];
            }
        }
    }

    // 添加变量changed,当指令有变化时,重新计算一遍
    bool changed;
    do
    {
        changed = false;
        int offset = 0;
        for (int i = 0; i < instructions.Count; i++)
        {
            var instruction = instructions[i];
            if (instruction.Offset != offset)
            {
                instruction.Offset = offset;
                changed = true;
            }
            offset += instruction.GetSize();
        }

        for (int i = 0; i < instructions.Count; i++)
        {
            var instruction = instructions[i];
            Instruction target = instruction.Operand as Instruction;

            if (target != null)
            {
                // 这里修改了
                int diff = target.Offset - (instruction.Offset + instruction.OpCode.Size + 1);
                if ((diff > sbyte.MaxValue || diff < sbyte.MinValue) && shortToLong.ContainsKey(instruction.OpCode))
                {
                    instructions[i] = processor.Create(shortToLong[instruction.OpCode], target);
                    changed = true;
                }
            }
        }
    }
    while (changed);
}

lizhengde avatar Jul 15 '22 11:07 lizhengde

没有测过,所以提个issue

lizhengde avatar Jul 15 '22 11:07 lizhengde

感觉你的逻辑是对的

huanlinghuan avatar Jul 27 '22 08:07 huanlinghuan