Exemplo n.º 1
0
        private void AssembleCode()
        {
            //resolve external dependencies
            try
            {
                foreach (string s in imports)
                {
                    CodeInformation.SymbolInformation si = new CodeInformation.SymbolInformation
                    {
                        LibraryName = s + ".dll",
                        Functions   = new List <CodeInformation.FunctionInformation>()
                    };

                    //import values
                    string[] lines = null;


                    string temp = "libraries/" + s + ".export";


                    //.exe is in root directory
                    if (File.Exists(temp))
                    {
                        lines = File.ReadAllLines(temp);
                    }
                    //.exe is in a /bin/ directory
                    else if (File.Exists(temp = "../" + temp))
                    {
                        lines = File.ReadAllLines(temp);
                    }
                    //.exe is in Visual Studio's /bin/debug or /bin/release
                    else if (File.Exists(temp = "../" + temp))
                    {
                        lines = File.ReadAllLines(temp);
                    }
                    else
                    {
                        throw new FileNotFoundException("Fatal Error: Cannot find file '" + s + ".export'");
                    }


                    foreach (var l in lines)
                    {
                        //ideally this should be replaced with regex @"(\d)* *(\w)+"
                        //hard coding this stuff isn't the best idea.
                        var split = l.Split(' ');

                        if (unresolvedReferences.ContainsKey(split[split.Length - 1]))
                        {
                            var func = new CodeInformation.FunctionInformation
                            {
                                FunctionName = split[split.Length - 1],
                                Ordinal      = int.Parse(split[0]),
                                Replacements = new List <int>()
                            };
                            unresolvedReferences[split[split.Length - 1]] = func;
                            si.Functions.Add(func);
                        }
                    }

                    if (si.Functions.Count > 0)
                    {
                        ci.SymbolInfo.Add(si);
                    }
                }
            }
            catch (FileNotFoundException)
            {
                throw;
            }
            catch (Exception ex)
            {
                //should never happen if installed correctly
                throw new Exception(FormatError("Unable to read import files: " + ex.Message));
            }


            bool found_main = false;

            //first calculate byte offsets for everything
            offset = 0;
            foreach (UnprocessedInstruction instruction in unprocessed_code)
            {
                if (instruction.isLabel)
                {
                    if (instruction.ident.Equals("main"))
                    {
                        ci.EntryPoint = (uint)offset;
                        found_main    = true;
                    }

                    labels.Add(instruction.ident, offset);
                }
                else
                {
                    foreach (Instruction instruct in x86InstructionSet.x86Instructions)
                    {
                        if (instruction.ident.Equals(instruct.mnemonic))
                        {
                            instruction.instruction = instruct;
                            break;
                        }
                    }

                    if (instruction.instruction == null)
                    {
                        throw new Exception(FormatError("Invalid opcode.", instruction.main_token.lineNum,
                                                        instruction.main_token.linePos));
                    }

                    if (!isValidArgument(instruction.arg0, instruction.instruction.arg1) ||
                        !isValidArgument(instruction.arg1, instruction.instruction.arg2) ||
                        !isValidArgument(instruction.arg2, instruction.instruction.arg3))
                    {
                        throw new Exception(FormatError("Invalid operand", instruction.main_token.lineNum,
                                                        instruction.main_token.linePos));
                    }

                    //I swear officer, this hack isn't mine. Please don't arrest me.
                    //need to replace for external calls
                    if (instruction.ident.Equals("call"))
                    {
                        if (instruction.arg0.ident != null)
                        {
                            if (unresolvedReferences[instruction.arg0.ident] != null)
                            {
                                //external code
                                instruction.arg0.offsetValue = 1;

                                unresolvedReferences[instruction.arg0.ident].Replacements.Add(offset + 2);
                            }
                        }
                    }
                    else if (instruction.ident.Equals("mov"))
                    {
                        if (instruction.arg1.ident != null)
                        {
                            //can be either a string, label, or external function
                            if (unresolvedReferences[instruction.arg1.ident] != null)
                            {
                                instruction.arg1.offsetValue = 1;
                                //external function
                                unresolvedReferences[instruction.arg1.ident].Replacements.Add(offset + 2);
                            }
                            else if (stringTable.ContainsKey(instruction.arg1.ident))
                            {
                                instruction.arg1.offsetValue = 1;
                                //string table
                                stringTable[instruction.arg1.ident].Item2.Add(offset + 2);
                            }
                            //labels handled elsewhere
                        }
                    }
                    //replace string table calls
                    else if (instruction.ident.Equals("push"))
                    {
                        if (instruction.arg0.ident != null)
                        {
                            if (stringTable.ContainsKey(instruction.arg0.ident))
                            {
                                //string table
                                instruction.arg0.offsetValue = 1;

                                stringTable[instruction.arg0.ident].Item2.Add(offset + 1);
                            }
                        }
                    }

                    instruction.offset = offset;
                    offset            += instruction.instruction.numberOfBytes(instruction.arg0,
                                                                               instruction.arg1, instruction.arg2);
                }
            }

            if (!found_main)
            {
                throw new Exception(FormatError("Could not find entrypoint. Expected 'main' label."));
            }


            //remove all resolved external references/string references/label references
            foreach (var key in unresolvedReferences.Keys.ToArray())
            {
                if (unresolvedReferences[key] != null)
                {
                    unresolvedReferences.Remove(key);
                }
                else if (stringTable.ContainsKey(key))
                {
                    unresolvedReferences.Remove(key);
                }
                else if (labels.ContainsKey(key))
                {
                    unresolvedReferences.Remove(key);
                }
            }
            if (unresolvedReferences.Count > 0)
            {
                foreach (var v in unresolvedReferences)
                {
                    warnings.Add(FormatWarning("Unresolved reference to '" + v.Key + "'"));
                }
                throw new Exception(FormatError("Cannot continue compilation."));
            }


            //"The magnitude of this hack compares favorably with that of the national debt." - A Microsoft Programmer

            //resolve references for internal calls and jumps
            foreach (var unpr in unprocessed_code)
            {
                if (unpr.ident.Equals("push") && unpr.arg0.type == InstructionArg.LABEL)
                {
                    if (unpr.arg0.offsetValue != 1)
                    {
                        if (labels.ContainsKey(unpr.arg0.ident))
                        {
                            unpr.arg0.value = labels[unpr.arg0.ident] -
                                              (unpr.offset +
                                               unpr.instruction.numberOfBytes(unpr.arg0, unpr.arg1, unpr.arg2));
                            unpr.arg0.type = InstructionArg.IMM32;
                        }
                        else
                        {
                            throw new Exception(FormatError("Unresolved reference '" + unpr.arg0.ident + "'",
                                                            unpr.main_token.lineNum, unpr.main_token.linePos));
                        }
                    }
                }
                else if (unpr.ident.Equals("mov"))
                {
                    //if not external
                    if (unpr.arg1.ident != null && unpr.arg1.offsetValue != 1)
                    {
                        if (labels.ContainsKey(unpr.arg1.ident))
                        {
                            unpr.arg1.value = labels[unpr.arg1.ident] -
                                              (unpr.offset +
                                               unpr.instruction.numberOfBytes(unpr.arg0, unpr.arg1, unpr.arg2));
                        }
                        else
                        {
                            throw new Exception(FormatError("Unresolved reference '" + unpr.arg1.ident + "'",
                                                            unpr.main_token.lineNum, unpr.main_token.linePos));
                        }
                    }
                }
                else if (unpr.ident.Equals("call") || unpr.ident.Equals("jmp") || unpr.ident.Equals("jg") ||
                         unpr.ident.Equals("je") || unpr.ident.Equals("jge") || unpr.ident.Equals("jl") ||
                         unpr.ident.Equals("jle") || unpr.ident.Equals("jne") || unpr.ident.Equals("loop") ||
                         unpr.ident.Equals("loope") || unpr.ident.Equals("loopne"))
                {
                    //if not external
                    if (unpr.arg0.offsetValue != 1)
                    {
                        if (labels.ContainsKey(unpr.arg0.ident))
                        {
                            unpr.arg0.value = labels[unpr.arg0.ident] -
                                              (unpr.offset +
                                               unpr.instruction.numberOfBytes(unpr.arg0, unpr.arg1, unpr.arg2));
                        }
                        else
                        {
                            throw new Exception(FormatError("Unresolved reference '" + unpr.arg0.ident + "'",
                                                            unpr.main_token.lineNum, unpr.main_token.linePos));
                        }
                    }
                }
            }

            UnprocessedInstruction last_inst = null;

            try
            {
                //assemble everything
                foreach (var unpr in unprocessed_code)
                {
                    last_inst = unpr;
                    if (!unpr.isLabel)
                    {
                        code.AddRange(unpr.instruction.assemble(unpr.arg0, unpr.arg1, unpr.arg2));
                    }
                }
            }
            catch (Exception ex)
            {
                throw new Exception(
                          FormatError(ex.Message, last_inst.main_token.lineNum, last_inst.main_token.linePos), ex);
            }
        }
Exemplo n.º 2
0
        private void ParseCode()
        {
            //Expect { instruction } [string] (arg1 (, arg2 (, arg3 )))
            //Expect { label }       [string]:

            for (; index + 1 < tokens.Count && !tokens[index + 1].Equals(".");)
            {
                Expect(typeof(string), "Expected a label or instruction");
                if (index + 1 < tokens.Count && tokens[index + 1].Equals(":"))
                {
                    unprocessed_code.Add(new UnprocessedInstruction
                    {
                        ident      = tokens[index],
                        isLabel    = true,
                        main_token = tokens[index]
                    });

                    index += 2;
                    //a label does not need to be on its own line
                }
                UnprocessedInstruction inst = new UnprocessedInstruction
                {
                    ident      = tokens[index],
                    isLabel    = false,
                    main_token = tokens[index]
                };


                if (index < tokens.Count && !nextTokenIsNextLine())
                {
                    index++;
                    inst.arg0 = ParseArg();

                    if (index < tokens.Count && !nextTokenIsNextLine())
                    {
                        index++;
                        if (!tokens[index].Equals(","))
                        {
                            throw new Exception(FormatError("Expected a delimiter between arguments.",
                                                            tokens[index].lineNum, tokens[index].linePos));
                        }

                        index++;
                        inst.arg1 = ParseArg();
                        if (index < tokens.Count && !nextTokenIsNextLine())
                        {
                            index++;
                            if (!tokens[index].Equals(","))
                            {
                                throw new Exception(FormatError("Expected a delimiter between arguments.",
                                                                tokens[index].lineNum, tokens[index].linePos));
                            }

                            index++;
                            inst.arg2 = ParseArg();
                            if (!nextTokenIsNextLine())
                            {
                                throw new Exception(
                                          FormatError("Unexpected arg count. No instruction has more than 3 arguments.",
                                                      tokens[index].lineNum, tokens[index].linePos));
                            }
                        }
                    }
                }

                unprocessed_code.Add(inst);
            }
        }