public void Link() { mUnits.Clear(); mInstructions.Clear(); mData.Clear(); mLit.Clear(); mBss = 0; mAllSymbols.Clear(); mSymbolUsages.Clear(); //Placeholder for calling main //mInstructions.Add(new Instruction(OpCode.NOOPERATION)); //mInstructions.Add(new Instruction(OpCode.HALT));//After main returns, HALT foreach (string file in mInputFiles) { CompilationUnit unit = new CompilationUnit(); bool success = unit.Open(file); if (success) { unit.InstructionOffset = mInstructions.Count; unit.DataOffset = mData.Count; unit.LitOffset = mLit.Count; foreach (var i in unit.Instructions) { mInstructions.Add(i); } foreach (var b in unit.Data) { mData.Add(b); } foreach (var b in unit.Lit) { mLit.Add(b); } mBss += (int)unit.Header.BssSize; mUnits.Add(unit); } } TotalInstructionCount = mInstructions.Count; TotalDataBytes = mData.Count; TotalLitBytes = mLit.Count; //Resolve internal symbols (after this, data and instructions will be modified in the unit) foreach (var unit in mUnits) { unit.ResolveSymbols(); } mInstructions.Clear(); mData.Clear(); mLit.Clear(); foreach (var unit in mUnits) { foreach (var i in unit.Instructions) { mInstructions.Add(i); } foreach (var b in unit.Data) { mData.Add(b); } foreach (var b in unit.Lit) { mLit.Add(b); } } foreach (var unit in mUnits) { foreach (var s in unit.Symbols) { if (s.Flag == Symbol.EnFlag.Export) { if (mAllSymbols.ContainsKey(s.Name)) { throw new Exception(string.Format("Symbol '{0}' in {1} is already defined in {2}", s.Name, unit.File, mAllSymbols[s.Name].Value.File)); } else { mAllSymbols.Add(s.Name, new KeyValuePair <Symbol, CompilationUnit>(s, unit)); } } } } ResolveExternals(); //save data and lit symbol usage addresses (including internals) here in order for machine to adjust addresses in runtime int symbolId = 0; foreach (var unit in mUnits) { foreach (SymbolUsage su in unit.SymbolUsages) { //At this stage, symbol name is not important int address = su.Address; switch (su.Section) { case EnSection.Code: address += unit.InstructionOffset; break; case EnSection.Data: address += unit.DataOffset; break; } SymbolUsage newSu = new SymbolUsage((++symbolId).ToString(), su.Section, address); mSymbolUsages.Add(newSu); } } /* * Symbol symbolMain = null; * foreach (var unit in mUnits) * { * symbolMain = unit.GetSymbol("main"); * if (null != symbolMain) * { * if (symbolMain.Section == EnSection.Code) * { * mInstructions[0].Operation = OpCode.CALL; * mInstructions[0].Modifier1 = (UInt16)(OpModifier.Immediate | OpModifier.Absolute); * mInstructions[0].Parameter1 = (symbolMain.Address + unit.InstructionOffset) * Instruction.InstructionSize; * } * else * { * throw new Exception("main function not found!"); * } * break; * } * } * if (null == symbolMain) * { * throw new Exception("main() could not be found!"); * }*/ }
//May have errors void ResolveExternals() { foreach (var unit in mUnits) { foreach (var symbolUsage in unit.UnresolvedSymbols) { if (mAllSymbols.ContainsKey(symbolUsage.Name)) { var symbolAndUnit = mAllSymbols[symbolUsage.Name]; Symbol symbol = symbolAndUnit.Key; CompilationUnit symbolOwnerUnit = symbolAndUnit.Value; switch (symbolUsage.Section) { case EnSection.Code: { int address = -1; switch (symbol.Section) { case EnSection.Code: address = (symbol.Address + symbolOwnerUnit.InstructionOffset) * Instruction.InstructionSize; break; case EnSection.Data: address = symbolOwnerUnit.DataOffset + symbol.Address + Instruction.InstructionSize * Linker.TotalInstructionCount; break; } if (address >= 0) { mInstructions[unit.InstructionOffset + symbolUsage.Address].Parameter1 = address; } else { throw new Exception(string.Format("Symbol location not found: {0}", symbol.Name)); } } break; case EnSection.Data: { int address = symbol.Address + symbolOwnerUnit.LitOffset + Linker.TotalDataBytes + Instruction.InstructionSize * Linker.TotalInstructionCount; byte[] bytes = BitConverter.GetBytes(address); mData[unit.DataOffset + symbolUsage.Address + 0] = bytes[0]; mData[unit.DataOffset + symbolUsage.Address + 1] = bytes[1]; mData[unit.DataOffset + symbolUsage.Address + 2] = bytes[2]; mData[unit.DataOffset + symbolUsage.Address + 3] = bytes[3]; } break; default: throw new Exception(string.Format("Symbol section not found: {0}", symbol.Name)); } } else { throw new Exception(string.Format("Unresolved symbol '{0}' used in {1}", symbolUsage.Name, unit.File)); } } } }