Commit 935d5f11 authored by Spencer Alves's avatar Spencer Alves

Now just brute-forcing variable linking

Disassembly output now includes the variable index next to every reference, which will be used on reassembly if present (can still be mixed with the old method). Reassembly still doesn't work fully because it turns out "Probably1" isn't always 1.
parent 8e0e7721
......@@ -123,14 +123,22 @@ namespace Altar.Decomp
case InstructionKind.Goto:
var g = iptr->Goto;
var a = g.Offset.UValue * 4;
if ((a & 0xFF000000) != 0)
if ((g.Offset.UValue&0x800000) != 0)
{
a &= 0x00FFFFFF;
a -= 0x01000000;
// there is precisely one place where this happens: gml_Object_obj_battlebomb_Alarm_3.gml
// and I have no clue what it could mean
}
else
{
var a = g.Offset.UValue * 4;
if ((a & 0xFF000000) != 0)
{
a &= 0x00FFFFFF;
a -= 0x01000000;
}
sb.Append(HEX_PRE).Append(Utils.ToHexSignString(relInstr + unchecked((int)a), HEX_FM6));
}
sb.Append(HEX_PRE).Append(Utils.ToHexSignString(relInstr + unchecked((int)a), HEX_FM6));
break;
#region set
......@@ -158,6 +166,13 @@ namespace Altar.Decomp
sb.Append(rdata.Variables[rdata.VarAccessors[(IntPtr)iptr]].Name);
sb.Append(s.DestVar.Type.ToPrettyString());
if (true)
{
sb.Append(' ');
sb.Append(rdata.VarAccessors[(IntPtr)iptr]);
}
break;
#endregion
#region push
......@@ -191,15 +206,22 @@ namespace Altar.Decomp
sb.Append(rdata.Variables[rdata.VarAccessors[(IntPtr)iptr]].Name);
sb.Append(rv.Type.ToPrettyString());
if (true)
{
sb.Append(' ');
sb.Append(rdata.VarAccessors[(IntPtr)iptr]);
}
break;
case DataType.Boolean:
sb.Append(((DwordBool*)&r)->ToPrettyString());
break;
case DataType.Double:
sb.Append(((double*)&r)->ToString(CultureInfo.InvariantCulture));
sb.Append(((double*)&r)->ToString("G16", CultureInfo.InvariantCulture));
break;
case DataType.Single:
sb.Append(((float*)&r)->ToString(CultureInfo.InvariantCulture));
sb.Append(((float*)&r)->ToString("G8", CultureInfo.InvariantCulture));
break;
case DataType.Int32:
sb.Append(unchecked((int)r).ToString(CultureInfo.InvariantCulture));
......
......@@ -394,7 +394,7 @@ namespace Altar
{
public uint Name;
public uint Length;
uint Probably1;
public uint Probably1;
public int BytecodeOffset;
uint Probably0;
}
......
......@@ -476,7 +476,7 @@ namespace Altar
if (eo.DumpAllChunks) chunks.Add((IntPtr)c.TexturePages);
if (eo.DumpAllChunks) chunks.Add((IntPtr)c.Code );
if (eo.DumpAllChunks) chunks.Add((IntPtr)c.Variables);
if (eo.DumpAllChunks) chunks.Add((IntPtr)c.Variables );
if (eo.DumpAllChunks) chunks.Add((IntPtr)c.Functions );
if (eo.DumpAllChunks) chunks.Add((IntPtr)c.Strings );
if (eo.DumpAllChunks) chunks.Add((IntPtr)c.Textures );
......@@ -568,12 +568,15 @@ namespace Altar
GMFile f = Deserialize.ReadFile(baseDir, projFile);
var stringsChunk = new BBData(new BinBuffer(), new int[0]);
Console.WriteLine($"Preparing strings...");
IDictionary<string, int> stringOffsets = SectionWriter.WriteStrings(stringsChunk, f.Strings);
var texpChunk = new BBData(new BinBuffer(), new int[0]);
Console.WriteLine($"Preparing textures...");
int[] texPagOffsets = SectionWriter.WriteTexturePages(texpChunk, f.TexturePages);
var codeChunk = new BBData(new BinBuffer(), new int[0]);
Console.WriteLine($"Preparing code...");
var codeChunkStringOffsetOffsets = SectionWriter.WriteCodes(codeChunk, f, stringOffsets);
var output = Path.GetFullPath(opt.OutputFile);
......
......@@ -527,7 +527,13 @@ namespace Altar.Recomp
case TokenType.Brf:
case TokenType.PushEnv:
case TokenType.PopEnv:
yield return new Branch { OpCode = TokenToOpCodes(nt), Label = LabelValue(Dequeue()) };
yield return new Branch
{
OpCode = TokenToOpCodes(nt),
Label = ((Peek() is IntToken) || (Peek() is WordToken)) ?
LabelValue(Dequeue()) :
null
};
break;
#endregion
#region set
......@@ -562,7 +568,26 @@ namespace Altar.Recomp
var n = ReadIdentifier();
var t3 = TryReadVariableType();
yield return new Set { OpCode = TokenToOpCodes(nt), Type1 = t1, Type2 = t2, InstanceType = instu.Item2, InstanceName = instu.Item1, TargetVariable = n, VariableType = t3 };
int variableIndex = -1;
{
SkipWhitespace();
var m = Peek();
if (m is IntToken)
{
variableIndex = (int)((IntToken)Dequeue()).Value;
}
}
yield return new Set {
OpCode = TokenToOpCodes(nt),
Type1 = t1,
Type2 = t2,
InstanceType = instu.Item2,
InstanceName = instu.Item1,
TargetVariable = n,
VariableType = t3,
VariableIndex = variableIndex
};
}
break;
#endregion
......@@ -589,7 +614,25 @@ namespace Altar.Recomp
var n = ReadIdentifier();
var t2 = TryReadVariableType();
yield return new PushVariable { OpCode = TokenToOpCodes(nt, 0, t1, instu.Item2), Type = t1, InstanceType = instu.Item2, InstanceName = instu.Item1, VariableName = n, VariableType = t2 };
int variableIndex = -1;
{
SkipWhitespace();
var m = Peek();
if (m is IntToken)
{
variableIndex = (int)((IntToken)Dequeue()).Value;
}
}
yield return new PushVariable {
OpCode = TokenToOpCodes(nt, 0, t1, instu.Item2),
Type = t1,
InstanceType = instu.Item2,
InstanceName = instu.Item1,
VariableName = n,
VariableType = t2,
VariableIndex = variableIndex
};
break;
default:
var v = InnerValue(Dequeue());
......
......@@ -66,6 +66,7 @@ namespace Altar.Recomp
public string TargetVariable;
public VariableType VariableType;
internal int VariableIndex;
public override string ToString() => base.ToString() + SR.SPACE_S + (InstanceName ?? InstanceType.ToPrettyString()) + SR.COLON + TargetVariable + VariableType.ToPrettyString();
}
......@@ -106,6 +107,7 @@ namespace Altar.Recomp
public string VariableName;
public VariableType VariableType;
internal int VariableIndex;
public override string ToString() => base.ToString() + SR.SPACE_S + (InstanceName ?? InstanceType.ToPrettyString()) + SR.COLON + VariableName + VariableType.ToPrettyString();
}
......
......@@ -494,7 +494,8 @@ namespace Altar.Repack
Name = setinst.TargetVariable,
InstanceType = setinst.InstanceType,
Instance = setinst.InstanceType == InstanceType.Local ? name : null,
VariableType = setinst.VariableType
VariableType = setinst.VariableType,
VariableIndex = setinst.VariableIndex
}, size));
break;
case InstructionKind.Push:
......@@ -513,7 +514,8 @@ namespace Altar.Repack
Name = p.VariableName,
InstanceType = p.InstanceType,
Instance = p.InstanceType == InstanceType.Local ? name : null,
VariableType = p.VariableType
VariableType = p.VariableType,
VariableIndex = p.VariableIndex
}, size));
}
else
......@@ -555,7 +557,8 @@ namespace Altar.Repack
{
Name = callinst.FunctionName,
InstanceType = InstanceType.StackTopOrGlobal,
VariableType = callinst.FunctionType
VariableType = callinst.FunctionType,
VariableIndex = -1
}, size));
break;
case InstructionKind.Break:
......@@ -605,6 +608,20 @@ namespace Altar.Repack
var s = (string)(gotoinst.Label);
// TODO
}
else if (gotoinst.Label == null)
{
bininst.Goto = new BranchInstruction
{
Offset = new Int24(0xF00000),
OpCode = op
};
break;
}
else
{
Console.WriteLine("Can't use label " + gotoinst.Label);
break;
}
var relTarget = (int)absTarget - (int)size;
uint offset = unchecked((uint)relTarget);
if (relTarget < 0)
......@@ -797,10 +814,6 @@ namespace Altar.Repack
f.Code[i] = DeserializeCodeFromFile(Path.Combine(baseDir, (string)(code[i])), f.General.BytecodeVersion,
stringIndices, objectIndices);
f.Code[i].Name = Path.GetFileNameWithoutExtension(Path.GetFileNameWithoutExtension((string)(code[i])));
/*if (f.Code[i].Name == "gml_Script_scr_namingscreen")
{
return f;
}*/
}
}
if (projFile.Has("sounds"))
......
......@@ -1093,6 +1093,8 @@ namespace Altar.Repack
{
bytecodeSize += ci.Size;
}
Console.WriteLine($"Assembling...");
BBData[] datas = new BBData[f.Code.Length];
for (int i = 0; i < f.Code.Length; i++)
......@@ -1124,6 +1126,8 @@ namespace Altar.Repack
offAcc += datas[i].Buffer.Size;
}
Console.WriteLine($"Linking...");
IList<Tuple<ReferenceSignature, uint>> functionReferences = new List<Tuple<ReferenceSignature, uint>>();
IList<Tuple<ReferenceSignature, uint>> variableReferences = new List<Tuple<ReferenceSignature, uint>>();
......@@ -1131,13 +1135,15 @@ namespace Altar.Repack
{
Name = "prototype",
InstanceType = InstanceType.Self,
VariableType = VariableType.Normal
VariableType = VariableType.Normal,
VariableIndex = 0
}, 0xFFFFFFFF));
variableReferences.Add(new Tuple<ReferenceSignature, uint>(new ReferenceSignature
{
Name = "@@array@@",
InstanceType = InstanceType.Self,
VariableType = VariableType.Normal
VariableType = VariableType.Normal,
VariableIndex = 1
}, 0xFFFFFFFF));
int[] bytecodeOffsets = null;
......@@ -1157,7 +1163,8 @@ namespace Altar.Repack
Name = "arguments",
InstanceType = InstanceType.Local,
Instance = f.Code[i].Name,
VariableType = VariableType.Normal
VariableType = VariableType.Normal,
VariableIndex = -1
}, 0xFFFFFFFF));
}
AddReferencesOffset(variableReferences, f.Code[i].variableReferences, data.Buffer.Position);
......@@ -1182,7 +1189,8 @@ namespace Altar.Repack
Name = "arguments",
InstanceType = InstanceType.Local,
Instance = f.Code[i].Name,
VariableType = VariableType.Normal
VariableType = VariableType.Normal,
VariableIndex = -1
}, 0xFFFFFFFF));
}
AddReferencesOffset(variableReferences, f.Code[i].variableReferences, data.Buffer.Position);
......@@ -1203,16 +1211,16 @@ namespace Altar.Repack
// I tried my best at guessing what these should be, but it wasn't enough.
// I suspect it may have to do with variable type, since getting
// one wrong resulted in "tried to index something that isn't an
// array."
// array" (or something to that effect).
for (int i = 0; i < variableStartOffsetsAndCounts.Count; i++)
{
var v = variableStartOffsetsAndCounts[i];
if (i < f.RefData.Variables.Length &&
v.Name == f.RefData.Variables[i].Name &&
(v.InstanceType == f.RefData.Variables[i].InstanceType || v.InstanceType >= InstanceType.StackTopOrGlobal))
v.Name == f.RefData.Variables[i].Name)// &&
//(v.InstanceType == f.RefData.Variables[i].InstanceType || v.InstanceType >= InstanceType.StackTopOrGlobal))
{
v.unknown2 = f.RefData.Variables[i].unknown2;
//v.InstanceType = f.RefData.Variables[i].InstanceType;
v.InstanceType = f.RefData.Variables[i].InstanceType;
variableStartOffsetsAndCounts[i] = v;
}
}
......@@ -1232,7 +1240,7 @@ namespace Altar.Repack
IList<Tuple<ReferenceSignature, uint>> references, IDictionary<string, uint> stringIndices, bool extended,
out IList<ReferenceDef> startOffsetsAndCounts)
{
startOffsetsAndCounts = new List<ReferenceDef>(references.Count);
startOffsetsAndCounts = new List<ReferenceDef>();
int localCount = 0;
int nonLocalCount = 0;
for (int i = 0; i < references.Count; i++)
......@@ -1243,7 +1251,7 @@ namespace Altar.Repack
uint count = 0;
var targetRef = references[i].Item1;
var start = references[i].Item2;
if (targetRef.InstanceType >= InstanceType.StackTopOrGlobal && extended)
if (targetRef.InstanceType >= InstanceType.StackTopOrGlobal && extended && targetRef.VariableIndex != -1)
{
for (InstanceType possibleInstanceType = InstanceType.Self; possibleInstanceType >= InstanceType.Local; possibleInstanceType--)
{
......@@ -1278,11 +1286,14 @@ namespace Altar.Repack
{
if (references[j].Item1.Name == targetRef.Name &&
(!extended ||
(targetRef.VariableIndex != -1) ||
(references[j].Item1.InstanceType >= InstanceType.StackTopOrGlobal) ||
(references[j].Item1.InstanceType == targetRef.InstanceType &&
//references[j].Item1.VariableType == targetRef.VariableType &&
(references[j].Item1.InstanceType != InstanceType.Local ||
references[j].Item1.Instance == targetRef.Instance))))
references[j].Item1.Instance == targetRef.Instance))) &&
((targetRef.VariableIndex == -1) ||
(targetRef.VariableIndex == references[j].Item1.VariableIndex)))
{
diff = (references[j].Item2 - last.Item2) & 0xFFFFFF;
data.Buffer.Position = (int)last.Item2 + 4;
......@@ -1302,7 +1313,7 @@ namespace Altar.Repack
existing = data.Buffer.ReadUInt32();
data.Buffer.Write(diff | existing);
}
startOffsetsAndCounts.Add(new ReferenceDef
var def = new ReferenceDef
{
FirstOffset = start,
HasExtra = extended,
......@@ -1311,9 +1322,19 @@ namespace Altar.Repack
Occurrences = count,
unknown2 = targetRef.InstanceType == InstanceType.Local ?
localCount : targetRef.VariableType == VariableType.StackTop ?
nonLocalCount : - 6,
nonLocalCount : -6,
VariableType = targetRef.VariableType
});
};
if (targetRef.VariableIndex == -1)
{
startOffsetsAndCounts.Add(def);
}
else
{
while (startOffsetsAndCounts.Count <= targetRef.VariableIndex)
startOffsetsAndCounts.Add(new ReferenceDef());
startOffsetsAndCounts[targetRef.VariableIndex] = def;
}
if (targetRef.InstanceType == InstanceType.Local)
{
localCount++;
......
......@@ -25,6 +25,7 @@ namespace Altar
public InstanceType InstanceType;
public string Instance;
public VariableType VariableType;
public int VariableIndex;
public override string ToString() => Name;
}
// ---
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment