xLua
xLua copied to clipboard
Hotfix导致部分注入函数IL报错
-
Hotfix.cs中fixBranch短格式跳转指令偏移计算与Mono.Ceil不一样,当刚好处于边界值时,会导致注入的函数运行时IL报错(超出sbyte范围)
-
修改短格式指令会导致前后其他短格式相对偏移量加大,需要再次遍历并修改
修改前
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);
}
没有测过,所以提个issue
感觉你的逻辑是对的