Exemplo n.º 1
0
        public static void CreateObjectCode(Stream toStream, IArchitecture architecture, List <IRInstruction> ir, Dictionary <string, StringConstant> stringConstants, Dictionary <string, Variable> globalVariables, Dictionary <string, Function> functions)
        {
            var header = new ObjectCodeHeader();

            header.RelocationAddresses = new List <int>();
            header.LabelAddresses      = new List <LabelAddressTableEntry>();

            var code = new List <byte>();

            //name => labelIndex
            header.ExportedSymbols = new Dictionary <string, int>();

            #region Functions

            if (functions != null)
            {
                foreach (var function in functions)
                {
                    if (function.Value.IsExported)
                    {
                        header.ExportedSymbols.Add(function.Key, function.Value.Address.Value);
                    }
                    else if (function.Value.IsExtern)
                    {
                        header.LabelAddresses.Add(
                            new LabelAddressTableEntry()
                        {
                            Index      = function.Value.Address.Value,
                            IsExtern   = true,
                            SymbolName = function.Key
                        }
                            );
                    }
                    else
                    {
                        if (function.Key.Equals("main", StringComparison.CurrentCultureIgnoreCase))
                        {
                            header.HasEntryPoint           = true;
                            header.EntryPointFunctionLabel = function.Value.Address.Value;
                        }
                    }
                }
            }

            #endregion

            int codeAddress = 0;

            foreach (var i in ir)
            {
                if (i is IRComment)
                {
                    continue;
                }

                if (i is IRLabel)
                {
                    header.LabelAddresses.Add(
                        new LabelAddressTableEntry()
                    {
                        Index   = ((IRLabel)i).Index,
                        Address = codeAddress
                    }
                        );
                }

                if (i is IRelocatableAddressValue && ((IRelocatableAddressValue)i).HasRelocatableAddressValue())
                {
                    int relocOffset = architecture.GetRelocationOffset(i);
                    header.RelocationAddresses.Add(codeAddress + relocOffset);
                }

                byte[] machineInstruction = i.GetImplementation(architecture);
                code.AddRange(machineInstruction.ToList());
                codeAddress += machineInstruction.Length;
            }

            int offset = codeAddress;
            int initializedDataSize = 0;

            #region String Constants

            if (stringConstants != null)
            {
                foreach (var str in stringConstants)
                {
                    header.LabelAddresses.Add(
                        new LabelAddressTableEntry()
                    {
                        Index   = str.Value.LabelAddress,
                        Address = offset + initializedDataSize
                    }
                        );

                    initializedDataSize += str.Value.Value.Length + 1;
                }
            }

            #endregion

            offset += initializedDataSize;
            int uninitializedDataSize = 0;

            #region Global Variables

            if (globalVariables != null)
            {
                foreach (var variable in globalVariables)
                {
                    if (variable.Value.IsExported)
                    {
                        header.ExportedSymbols.Add(variable.Key, variable.Value.Address.Value);
                    }

                    if (variable.Value.IsExtern)
                    {
                        header.LabelAddresses.Add(
                            new LabelAddressTableEntry()
                        {
                            Index      = variable.Value.Address.Value,
                            IsExtern   = true,
                            SymbolName = variable.Key
                        }
                            );
                    }
                    else
                    {
                        header.LabelAddresses.Add(
                            new LabelAddressTableEntry()
                        {
                            Index    = variable.Value.Address.Value,
                            IsExtern = false,
                            Address  = offset + uninitializedDataSize
                        }
                            );

                        uninitializedDataSize += variable.Value.Type.GetSize();
                    }
                }
            }

            #endregion

            offset += uninitializedDataSize;

            header.SizeOfDataAndCode = offset;

            using (var sw = new BinaryWriter(toStream))
            {
                ObjectCodeUtils.WriteObjectFileHeader(header, sw);

                //Code section
                foreach (byte b in code)
                {
                    sw.Write(b);
                }

                //Initialized data
                if (stringConstants != null)
                {
                    foreach (var str in stringConstants)
                    {
                        foreach (var ch in str.Value.Value.ToCharArray())
                        {
                            sw.Write((byte)ch);
                        }

                        sw.Write((byte)0); //0 terminated strings
                    }
                }

                //Uninitialized data
                for (int i = 0; i < uninitializedDataSize; i++)
                {
                    sw.Write((byte)0);
                }
            }
        }
Exemplo n.º 2
0
        public static void Link(Stream toStream, List <byte[]> objectFileCodes, bool createExecutable, int loadAddress = 0)
        {
            var headers        = new List <ObjectCodeHeader>();
            var objDataOffsets = new List <int>();

            int objDataOffset = 0;

            bool foundEntryPoint = false;

            for (int i = 0; i < objectFileCodes.Count; i++)
            {
                objDataOffsets.Add(objDataOffset + ((createExecutable && i == 0) ? 4 : 0));

                var header = ObjectCodeUtils.ReadObjectCodeHeader(objectFileCodes[i]);

                headers.Add(header);

                if (header.HasEntryPoint)
                {
                    if (foundEntryPoint)
                    {
                        throw new Exception("Multiple entry points detected in source object files");
                    }
                    else
                    {
                        foundEntryPoint = true;
                    }
                }

                objDataOffset += header.SizeOfDataAndCode;
            }

            if (createExecutable && !foundEntryPoint)
            {
                throw new Exception("No entry point found in any source object files");
            }

            using (var stream = new MemoryStream())
                using (var sw = new BinaryWriter(stream))
                    using (var sr = new BinaryReader(stream))
                    {
                        if (createExecutable)
                        {
                            loadAddress += 4;
                            sw.Write(0); //temporary until entry point address is resolved
                        }

                        for (int i = 0; i < objectFileCodes.Count; i++)
                        {
                            //Write data and code to output file
                            using (var objStream = new BinaryReader(new MemoryStream(objectFileCodes[i])))
                            {
                                objStream.BaseStream.Seek(headers[i].DataStart, SeekOrigin.Begin);

                                byte[] dataAndCode = new byte[objStream.BaseStream.Length - headers[i].DataStart];
                                objStream.Read(dataAndCode, 0, dataAndCode.Length);

                                sw.Seek(objDataOffsets[i], SeekOrigin.Begin);
                                sw.Write(dataAndCode);
                            }

                            //Perform relocations and symbol resolution
                            foreach (int address in headers[i].RelocationAddresses)
                            {
                                sr.BaseStream.Seek(address + objDataOffsets[i], SeekOrigin.Begin);

                                int labelIndex = BitConverter.ToInt32(BitConverter.GetBytes(sr.ReadInt32()).Reverse().ToArray(), 0);
                                var label      = headers[i].LabelAddresses[labelIndex];
                                int newAddress = -1;

                                if (label.IsExtern)
                                {
                                    bool resolved = false;

                                    //search all other header symbol tables
                                    for (int j = 0; j < objectFileCodes.Count; j++)
                                    {
                                        if (i == j)
                                        {
                                            continue;
                                        }

                                        if (headers[j].ExportedSymbols.ContainsKey(label.SymbolName))
                                        {
                                            resolved = true;
                                            int extLabelIndex = headers[j].ExportedSymbols[label.SymbolName];
                                            newAddress  = headers[j].LabelAddresses[extLabelIndex].Address;
                                            newAddress += objDataOffsets[j] + loadAddress;
                                        }
                                    }

                                    if (!resolved)
                                    {
                                        throw new UnresolvedExternalSymbolException(label.SymbolName);
                                    }
                                }
                                else
                                {
                                    //Write new address
                                    newAddress = label.Address + objDataOffsets[i] + loadAddress;

                                    if (createExecutable)
                                    {
                                        if (headers[i].HasEntryPoint && headers[i].EntryPointFunctionLabel == labelIndex)
                                        {
                                            //Write entry point address at position 0
                                            sw.Seek(0, SeekOrigin.Begin);
                                            sw.Write(BitConverter.GetBytes(newAddress).Reverse().ToArray());
                                        }
                                    }
                                }

                                sw.Seek(address + objDataOffsets[i], SeekOrigin.Begin);
                                sw.Write(BitConverter.GetBytes(newAddress).Reverse().ToArray());
                            }
                        }

                        stream.Seek(0, SeekOrigin.Begin);
                        stream.CopyTo(toStream);
                    }
        }