/// <summary> /// Copies the references from the object <paramref name="files"/>. /// </summary> /// <param name="files">The object files to copy references from.</param> /// <param name="combined">The object file that owns the copied references.</param> private static void CopyReferences(IEnumerable <ObjectFile> files, ObjectFile combined) { foreach (var file in files) { foreach (var procedure in file.OfType <Procedure>().Where(p => p.IsDefined)) { foreach (var reference in procedure.References) { var proc = combined.OfType <Procedure>().First(p => p.Name == procedure.Name); var referenced = combined.First(a => a.Name == reference.Atom.Name); var r = new Reference(referenced); r.Address = reference.Address; r.IsAddressInLittleEndian = reference.IsAddressInLittleEndian; r.SizeOfAddress = reference.SizeOfAddress; if (!referenced.IsGlobal) { var a = GetDefiningObjectFile(referenced.Name, files); var b = GetDefiningObjectFile(proc.Name, files); if (a != null && b != null && a != b) { throw new InvalidObjectFileException("'" + proc.Name + "' is referencing '" + referenced.Name + "' which is local to another object file."); } } proc.References.Add(r); } } } }
/// <summary> /// Combines object files into a single one. /// </summary> /// <param name="files">The object files to combine.</param> /// <returns>The combined object file.</returns> /// <exception cref="ArgumentNullException"> /// <paramref name="files"/> is null. /// </exception> /// <exception cref="InvalidObjectFileException"> /// The combined object file is invalid. /// </exception> public ObjectFile Link(IEnumerable <ObjectFile> files) { if (files == null) { throw new ArgumentNullException(nameof(files)); } var combined = new ObjectFile(); foreach (var file in files) { if (combined.Origin != file.Origin) { if (combined.IsOriginSet) { throw new InvalidObjectFileException("Inconsistent origin."); } combined.IsOriginSet = true; combined.Origin = file.Origin; } foreach (var atom in file) { var procedure = atom as Procedure; if (procedure != null) { if (combined.OfType <Procedure>().Any(p => p.IsMain) && procedure.IsMain) { throw new InvalidObjectFileException("Multiple main procedures."); } } var duplicate = combined.FirstOrDefault(a => a.Name == atom.Name); if (duplicate != null) { if (duplicate.IsDefined && atom.IsDefined) { throw new InvalidObjectFileException("There are multiple atoms with called '" + atom.Name + "'."); } if (duplicate.GetType() != atom.GetType()) { throw new InvalidObjectFileException("'" + duplicate.Name + "' and '" + atom.Name + "' is not of the same type."); } if (!duplicate.IsDefined && !atom.IsDefined) { continue; } if (duplicate.IsDefined && !atom.IsDefined) { continue; } combined.Atoms.Remove(duplicate); } combined.Atoms.Add(Copy(atom)); } } CopyReferences(files, combined); return(combined); }