Beispiel #1
0
            private string GenerateCode(string namespaceName)
            {
                StringBuilder result = new StringBuilder();

                result.AppendLine("using System;");
                result.AppendLine("using System.Collections.Generic;");
                result.AppendLine();
                result.AppendLine("namespace " + namespaceName);
                result.AppendLine("{");
                result.AppendLine("    partial class NativeScript");
                result.AppendLine("    {");
                result.AppendLine("        public class Script_" + NativeScript.GetVersionName(version) + " : Script");
                result.AppendLine("        {");
                result.AppendLine("            public Script_" + NativeScript.GetVersionName(version) + "()");
                result.AppendLine("            {");
                result.AppendLine("                ScriptHash = \"" + GetScriptHash() + "\";");
                result.AppendLine("                GlobalsAddressOffset = " + GlobalsAddressOffset + ";");
                result.AppendLine("                Functions = new Dictionary<string, int>()");
                result.AppendLine("                {");
                foreach (KeyValuePair <Function, int> functionOffset in FunctionOffsets)
                {
                    result.AppendLine("                    { \"" + functionOffset.Key.Name + "\", " + functionOffset.Value + " },");
                }
                result.AppendLine("                };");
                result.AppendLine("                Buffer = new byte[]");
                result.AppendLine("                {");
                result.Append("                    ");
                for (int i = 0; i < Buffer.Length; i++)
                {
                    result.Append("0x" + Buffer[i].ToString("X2"));
                    if (i < Buffer.Length - 1)
                    {
                        result.Append(",");
                    }
                    if ((i + 1) % 16 == 0)
                    {
                        result.AppendLine();
                        result.Append("                    ");
                    }
                }
                result.AppendLine();
                result.AppendLine("                };");
                result.AppendLine("            }");
                result.AppendLine("        }");
                result.AppendLine("    }");
                result.AppendLine("}");
                return(result.ToString());
            }
Beispiel #2
0
        public static void Compile(GameVersion version, bool optimize)
        {
            string scriptPath = GetScriptPath();

            if (string.IsNullOrEmpty(scriptPath) || !File.Exists(scriptPath))
            {
                return;
            }

            string versionScriptPath = Path.ChangeExtension(scriptPath, NativeScript.GetVersionName(version) + ".c");

            if (string.IsNullOrEmpty(versionScriptPath) || !File.Exists(versionScriptPath))
            {
                return;
            }

            string text = File.ReadAllText(scriptPath);

            text = text.Replace(scriptReplaceStr, File.ReadAllText(versionScriptPath));
            string tempScriptPath = Path.ChangeExtension(scriptPath, "temp.c");

            File.WriteAllText(tempScriptPath, text);

            string[] lines = text.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);

            if (lines.Length < 2)
            {
                return;
            }

            string compiler = lines[0].Trim('/', ' ');
            string dumpbin  = lines[1].Trim('/', ' ');

            if (string.IsNullOrEmpty(compiler) || string.IsNullOrEmpty(dumpbin))
            {
                return;
            }

            if (!File.Exists(compiler))
            {
                compiler = Path.Combine(Path.GetDirectoryName(scriptPath), compiler);
            }

            if (!File.Exists(dumpbin))
            {
                dumpbin = Path.Combine(Path.GetDirectoryName(scriptPath), dumpbin);
            }

            if (!File.Exists(compiler) || !File.Exists(dumpbin))
            {
                return;
            }

            string scriptDir = Path.GetDirectoryName(scriptPath);
            string objPath   = Path.ChangeExtension(tempScriptPath, ".obj");

            string additionalArgs = "/GS- ";// disable buffer security check (security cookie stuff)

            if (optimize)
            {
                additionalArgs += "/O2";
            }

            string compileOutput, compileError;

            if (RunProcess(compiler, "/c " + additionalArgs + " \"" + tempScriptPath + "\"", scriptDir, out compileOutput, out compileError) &&
                !compileOutput.Contains("error") && File.Exists(objPath))
            {
                // Compile was successful, get the disasm

                string disasmOutput, disasmError;
                if (RunProcess(dumpbin, "\"" + objPath + "\" /disasm", scriptDir, out disasmOutput, out disasmError) &&
                    !disasmOutput.Contains("fatal error"))
                {
                    string lastLine = string.Empty;

                    Module   module           = new Module(version);
                    Function currentFunction  = null;
                    string   instructionStr   = string.Empty;
                    string   instructionBytes = string.Empty;

                    string[] splitted = disasmOutput.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
                    foreach (string line in splitted)
                    {
                        if (line.StartsWith("  0"))
                        {
                            if (lastLine.EndsWith(":") && !lastLine.StartsWith(" "))
                            {
                                Debug.Assert(currentFunction == null);
                                currentFunction = new Function(lastLine.Substring(0, lastLine.Length - 1));
                                module.Functions.Add(currentFunction.Name, currentFunction);
                            }

                            if (!string.IsNullOrEmpty(instructionStr))
                            {
                                currentFunction.AddInstruction(instructionBytes, instructionStr);
                            }

                            instructionBytes = string.Empty;
                            instructionStr   = string.Empty;
                            string str      = line.Substring(line.IndexOf(':') + 1);
                            int    bytesEnd = str.IndexOf("  ");
                            instructionBytes = str.Substring(0, bytesEnd).Trim();
                            instructionStr   = str.Substring(bytesEnd).Trim();

                            // Remove additional spacing between the mnemonic and the rest of the instruction
                            int firstSpace = instructionStr.IndexOf(' ');
                            while (true)
                            {
                                if (instructionStr[firstSpace + 1] == ' ')
                                {
                                    instructionStr = instructionStr.Remove(firstSpace + 1, 1);
                                }
                                else
                                {
                                    break;
                                }
                            }
                        }
                        else if (line == "  Summary")
                        {
                            break;
                        }
                        else if (line.StartsWith(" "))
                        {
                            instructionBytes += line.Trim();
                        }
                        else
                        {
                            if (!string.IsNullOrEmpty(instructionStr) && currentFunction != null)
                            {
                                currentFunction.AddInstruction(instructionBytes, instructionStr);
                            }

                            currentFunction  = null;
                            instructionBytes = string.Empty;
                            instructionStr   = string.Empty;
                        }

                        lastLine = line;
                    }

                    if (!string.IsNullOrEmpty(instructionStr))
                    {
                        currentFunction.AddInstruction(instructionBytes, instructionStr);
                    }

                    module.Build();
                }
            }
            else
            {
                Debug.WriteLine("Compile failed " + compileOutput);
                Debugger.Break();
            }
        }
Beispiel #3
0
            public void Build()
            {
                List <byte> buffer = new List <byte>();

                FunctionOffsets.Clear();

                GetGlobalsFunction   = null;
                GlobalsAddressOffset = -1;

                int offset = 0;

                foreach (Function function in Functions.Values)
                {
                    if (function.Name == getGlobalsFunctionName)
                    {
                        GetGlobalsFunction   = function;
                        GlobalsAddressOffset = offset + 2;
                        Debug.Assert(function.Instructions[0].CompleteInstruction == "mov rax,0AAAAAAAAAAAAAAAAh");
                        for (int i = 0; i < 8; i++)
                        {
                            function.Instructions[0].Bytes[i + 2] = 0;
                        }
                    }

                    int functionLen = 0;
                    foreach (Instruction instruction in function.Instructions)
                    {
                        functionLen += instruction.Bytes.Length;
                    }
                    FunctionOffsets.Add(function, offset);
                    offset += functionLen;
                }

                foreach (Function function in Functions.Values)
                {
                    foreach (Instruction instruction in function.Instructions)
                    {
                        if (instruction.IsCall && instruction.Bytes[0] == 0xE8)
                        {
                            string functionName = instruction.CompleteInstruction.Substring(
                                instruction.CompleteInstruction.IndexOf(' ') + 1).Trim();

                            int instructionOffset = FunctionOffsets[function] + instruction.Offset;
                            int targetFuncOffset  = FunctionOffsets[Functions[functionName]];

                            byte[] relativeAddr = BitConverter.GetBytes(targetFuncOffset - instructionOffset - 5);
                            instruction.Bytes[1] = relativeAddr[0];
                            instruction.Bytes[2] = relativeAddr[1];
                            instruction.Bytes[3] = relativeAddr[2];
                            instruction.Bytes[4] = relativeAddr[3];
                        }
                    }

                    function.BuildBytes();
                    buffer.AddRange(function.Bytes);
                }

                Buffer = buffer.ToArray();
                Code   = GenerateCode();

                string outputFilePath = GetSourceFilePath(Path.ChangeExtension(outputFileName, NativeScript.GetVersionName(version) + ".cs"));

                if (File.Exists(outputFilePath))
                {
                    string oldCode = File.ReadAllText(outputFilePath);
                    if (oldCode != Code)
                    {
                        File.WriteAllText(outputFilePath, Code);
                    }
                }
                else
                {
                    Debug.WriteLine(Code);
                    Debugger.Break();
                }
            }