public void TestAssemblyLine() { Assert.IsTrue( Float.GenerateAssemblyLine(0.200000002980232f) .Last().Equals( (".single", "0.2") ) ); var x = Float.GenerateAssemblyLine(0x402E000007800000UL).ToArray(); Assert.IsTrue( x.Last().Equals( (".quad", "0x402E000007800000") ) ); var y = Float.GenerateAssemblyLine(0.199999988079071f).ToArray(); Assert.IsTrue( y.Last().Equals( (".word", "0x3E4CCCCC") ) ); var z = Float.GenerateAssemblyLine(15.0).ToArray(); Assert.IsTrue( z.Last().Equals( (".double", "15") ) ); }
public IEnumerable <string> Disassemble(bool debugAddress = false) { var disassembler = new Disassembler(new DefaultDisassemblyFormatter(Symbols)); Func <string, string, string> formatPair = (left, right) => right == null ? $"\t{left}" : $"\t{left.PadRight(16)}{right}"; Func <UInt32, Instruction, DisassemblerOutput, string> formatDisasm = (pc, insn, output) => !debugAddress ? formatPair(output.Opcode, output.Operands) : formatPair(output.Opcode, (output.Operands ?? "").PadRight(32) + string.Format("# 0x{0:X8} 0x{2:X8} {1}", pc, Disassembler.DefaultWithoutPc.Disassemble(0, insn), insn.Word)); yield return("#include \"mips.h\""); yield return("#define s8 $fp"); yield return(""); var x = 0; yield return(formatPair("#", null)); foreach (var s in Sections) { yield return(formatPair($"# {s.Name}", string.Format("0x{0:X8} - 0x{1:X8} ({2,6:0.00} kb)", s.StartAddress, s.EndAddress, s.Size / 1024.0))); if (x++ == 2) { yield return(formatPair("# [relocs]", string.Format("0x{0:X8} - 0x{1:X8} ({2,6:0.00} kb)", Sections[2].EndAddress, Sections[2].EndAddress + HeaderOffset, HeaderOffset / 1024.0))); } } if (_oddities.Count > 0) { yield return(formatPair("#", null)); yield return(formatPair("# Oddities:", null)); foreach (var o in _oddities) { yield return(formatPair($"# - {o}", null)); } } yield return(formatPair("#", null)); yield return(""); yield return(formatPair(".set", "noreorder")); yield return(formatPair(".set", "noat")); yield return(""); for (var j = 0; j < Sections.Count; j++) { var section = Sections[j]; if (section.Size == 0) { continue; } UInt32 pc = section.StartAddress; if (section.Id >= 1) { yield return(""); yield return(""); } if (section.Id > 1) { yield return(formatPair(".section", $"{section.Name}")); } else { yield return(formatPair(section.Id == 1 ? ".data" : ".text", null)); } yield return(""); switch (section.Id) { case 0: foreach (var insn in section.Data.ToInstructions()) { var symbol = Symbols.Lookup(pc); if (symbol != null) { if (symbol.TypeHint.HasFlags(TypeHint.Function)) { yield return(""); yield return(formatPair(".global", symbol.Name)); yield return(formatPair(".type", $"{symbol.Name}, @function")); yield return(""); yield return(symbol.Name + ":"); } else { var pattern = @" \+ \d+$"; var name = symbol.Name; if (Regex.IsMatch(name, pattern)) { name = Regex.Replace(name, pattern, ""); } yield return(name + ":"); } } yield return(formatDisasm(pc, insn, disassembler.Disassemble(pc, insn))); pc += 4; } break; case 1: case 2: for (var i = 0; i < section.Data.Count; i++) { var symbol = Symbols.Lookup(pc + (UInt32)i); if (symbol != null) { var stuffs = new List <string> { "", formatPair(".type", $"{symbol.Name}, @object"), symbol.Name + ":" }; var reloc = Relocations.Lookup(pc + (UInt32)i); var doByte = false; Action <int> size = (s) => stuffs.Insert(2, formatPair(".size", $"{symbol.Name}, {s}")); bool checkNoSymbolsForNextNbytes(int length) => Enumerable.Range(1, length - 1) .Select(y => Symbols.Lookup(pc + (UInt32)(i + y))) .All(y => y == null); if (reloc != null && checkNoSymbolsForNextNbytes(4)) { size(4); stuffs.Add(formatPair(".word", Symbols.Lookup(reloc.Address).Name)); i += 3; } else if (symbol.TypeHint.HasFlags(TypeHint.HalfWord | TypeHint.HalfWordUnsigned) && checkNoSymbolsForNextNbytes(2)) { size(2); stuffs.Add(formatPair(".short", string.Format("0x{0:X4}", section.Data[i] << 8 | section.Data[i + 1]))); i++; } else if (symbol.TypeHint.HasFlags(TypeHint.Word | TypeHint.WordUnsigned) && checkNoSymbolsForNextNbytes(4)) { size(4); stuffs.Add(formatPair(".word", string.Format("0x{0:X8}", Utilities.ReadU32(section.Data, i)))); i += 3; } else if (symbol.TypeHint.HasFlags(TypeHint.DoubleWord) && checkNoSymbolsForNextNbytes(8)) { size(8); stuffs.Add(formatPair(".quad", string.Format("0x{0:X16}", Utilities.ReadU32(section.Data, i)))); i += 7; } else if (symbol.TypeHint.HasFlags(TypeHint.Single) && checkNoSymbolsForNextNbytes(4)) { size(4); var flt = BitConverter.ToSingle(BitConverter.GetBytes(Utilities.ReadU32(section.Data, i)), 0); stuffs.AddRange(Float.GenerateAssemblyLine(flt).Select(y => formatPair(y.left, y.right))); i += 3; } else if (symbol.TypeHint.HasFlags(TypeHint.Double) && checkNoSymbolsForNextNbytes(8)) { size(8); var flt = BitConverter.ToDouble(BitConverter.GetBytes(Utilities.ReadU64(section.Data, i)), 0); stuffs.AddRange(Float.GenerateAssemblyLine(flt).Select(y => formatPair(y.left, y.right))); i += 7; } else { doByte = true; } foreach (var q in stuffs) { yield return(q); } if (!doByte) { continue; } } else { var reloc = Relocations.Lookup(pc + (UInt32)i); if (reloc != null) { yield return(formatPair(".word", Symbols.Lookup(reloc.Address).Name)); i += 3; continue; } } yield return(formatPair(".byte", string.Format("0x{0:X2}", section.Data[i]))); } break; case 3: var bssSyms = Symbols .Where(s => s.Address >= section.StartAddress && s.Address < section.EndAddress) .OrderBy(s => s.Address) .ToArray(); var symIdx = 0; if (bssSyms.Length == 0) { yield return(formatPair(".space", $"{Sections[3].Size}")); break; } for (var ptr = 0; ptr < section.Size;) { long curAddr; var sym = bssSyms[symIdx]; if ((curAddr = section.StartAddress + ptr) < sym.Address) { var spaceSize = bssSyms[symIdx].Address - curAddr; yield return(formatPair(".space", $"{spaceSize}")); ptr += (int)spaceSize; } else { var size = (symIdx + 1 == bssSyms.Length ? section.EndAddress : bssSyms[symIdx + 1].Address) - sym.Address; var right = $"{sym.Name},{size},1"; if (debugAddress) { right = right.PadRight(24) + string.Format("# 0x{0:X8}", ptr + section.StartAddress); } yield return(formatPair(".local", sym.Name)); yield return(formatPair(".comm", right)); ptr += (int)size; symIdx++; } } break; } } }