public static bool TryConvertToOverlay(string elfpath, string ovlpath, N64Ptr rpoint) { Ovl odata = new Ovl { start = rpoint, BindingSymbolName = { { "init", "initVars" } } }; bool result = false; MemoryStream ms = new MemoryStream(); using (FileStream elfFile = new FileStream(elfpath, FileMode.Open)) { elfFile.CopyTo(ms); ms.Position = 0; } result = TryConvertToOverlay(new BinaryReader(ms), odata, out byte[] ovlByte); using (FileStream fs = new FileStream(ovlpath, FileMode.Create)) { fs.Write(ovlByte, 0, ovlByte.Length); } return(result); }
private static void BindRelocatedSymbols(Ovl odata, List <SectionHeader> sections, Dictionary <int, List <Elf32_Sym> > symtabs) { var list = symtabs.Values.SelectMany(x => x); foreach (var kv in odata.BindingSymbolName) { var symbol = list.Where(x => x.Name == kv.Value).SingleOrDefault(); if (symbol != null && (symbol.st_shndx > 0 && symbol.st_shndx < sections.Count)) { var section = sections[symbol.st_shndx]; if (section.NS != null) { odata.BindingValue[kv.Key] = symbol.st_value + section.NS.Addr; continue; } } Console.WriteLine($"Binding {kv.Key}<-{kv.Value} failed"); } }
private static bool TryConvertToOverlay(BinaryReader elf, Ovl odata, out byte[] ovlByte) { ovlByte = new byte[0]; FileHeader header = new FileHeader(elf); if (!header.VerifyMagic()) { Console.WriteLine("Not an elf, or not a supported elf format"); return(false); } //Extract section headers List <SectionHeader> sections = GetSections(elf, header); //build memory map int relocations = GetRelocations(sections); Dictionary <string, SectionHeader> map = new Dictionary <string, SectionHeader>(); Dictionary <string, (N64Ptr addr, int size)> newMap = new Dictionary <string, (N64Ptr addr, int size)>(); N64Ptr cur = odata.start; for (int i = 0; i < ovlSectionsStr.Length; i++) { var secName = ovlSectionsStr[i]; if (secName == ".bss") { odata.header = cur - odata.start; cur += 0x14 + (relocations * 4) + 4; //header size, reloction size, header offset cur = Align.To16(cur); odata.pEnd = cur; } N64Ptr localStart = cur; foreach (var item in sections.Where(x => x.Name.StartsWith(secName))) { map[item.Name] = item; item.NS = new SectionHelper(item, cur, cur - odata.start, i + 1, cur - localStart); cur = Align.To16(cur + item.sh_size); } if (secName == ".bss") { odata.vEnd = cur; } int size = cur - localStart; newMap[secName] = (localStart, size); } //get relocated symtables Dictionary <int, List <Elf32_Sym> > symtabs = GetSymbols(elf, sections); //create our file ovlByte = new byte[odata.pEnd - odata.start]; List <Overlay.RelocationWord> ovlRelocations = new List <Overlay.RelocationWord>(); using (BinaryWriter ovl = new BinaryWriter(new MemoryStream(ovlByte))) { //copy data into the overlay foreach (var kv in map.OrderBy(x => x.Value.NS.Addr)) { var(sec, ptr, fOff, newSecId, sOff) = kv.Value.NS; if (sec == null) { continue; } if (sec.sh_type == SectionHeader.SHT_.PROGBITS) { ovl.BaseStream.Position = fOff; elf.BaseStream.Position = sec.sh_offset; byte[] data = elf.ReadBytes(sec.sh_size); ovl.Write(data); } } //handle relocations foreach (var section in sections.Where(x => x.sh_type == SectionHeader.SHT_.REL)) { List <Elf32_Rel> rel = GetSectionRelocations(elf, section); var secInfo = sections[section.sh_info]; if (secInfo.Name == ".pdr") { continue; } var(sec, ptr, fOff, newSecId, sOff) = secInfo.NS; //Sets section that REL applies to var symtab = symtabs[section.sh_link]; for (int i = 0; i < rel.Count; i++) { var relCur = rel[i]; var symbol = symtab[relCur.R_Sym]; if (symbol.st_shndx == 0) { Console.WriteLine($"{symbol.Name}: Undefined Section"); continue; } N64Ptr relSecAddr = sections[symbol.st_shndx].NS.Addr; switch (relCur.R_Type) { case Reloc.R_MIPS32: { ovl.BaseStream.Position = fOff + relCur.r_offset; elf.BaseStream.Position = sec.sh_offset + relCur.r_offset; var data = elf.ReadBigInt32() + relSecAddr + symbol.st_value; ovl.WriteBig(data); ovlRelocations.Add(new Overlay.RelocationWord((Overlay.Section)newSecId, Reloc.R_MIPS32, sOff + relCur.r_offset)); break; } case Reloc.R_MIPS26: { ovl.BaseStream.Position = fOff + relCur.r_offset; elf.BaseStream.Position = sec.sh_offset + relCur.r_offset; var data = elf.ReadBigUInt32(); var newAddrDat = (uint)((relSecAddr + symbol.st_value >> 2) & 0x3FFFFFF); data += newAddrDat; ovl.WriteBig(data); ovlRelocations.Add(new Overlay.RelocationWord((Overlay.Section)newSecId, Reloc.R_MIPS26, sOff + relCur.r_offset)); break; } case Reloc.R_MIPS_HI16: { if (!(i + 1 < rel.Count)) { Console.WriteLine("R_MIPS_HI16 without a proper pair"); return(false); } i++; var relLo = rel[i]; //have hi and lo relocations elf.BaseStream.Position = sec.sh_offset + relCur.r_offset + 2; var hiData = elf.ReadBigUInt16(); elf.BaseStream.Position = sec.sh_offset + relLo.r_offset; var loData = elf.ReadBigUInt32(); N64Ptr hiAddr = hiData << 16; N64Ptr addr = hiAddr + (loData & 0xFFFF) + relSecAddr + symtab[relLo.R_Sym].st_value; var hi16 = (ushort)((addr >> 16)); var lo16 = (ushort)(addr & 0xFFFF); bool isOri = ((loData >> 26) & 0x3F) == 0x0D; if (lo16 > 0x8000 && !isOri) { hi16++; } ovl.BaseStream.Position = fOff + relCur.r_offset + 2; ovl.WriteBig(hi16); ovl.BaseStream.Position = fOff + relLo.r_offset + 2; ovl.WriteBig(lo16); ovlRelocations.Add(new Overlay.RelocationWord((Overlay.Section)newSecId, Reloc.R_MIPS_HI16, sOff + relCur.r_offset)); ovlRelocations.Add(new Overlay.RelocationWord((Overlay.Section)newSecId, Reloc.R_MIPS_LO16, sOff + relLo.r_offset)); //Write repeating R_MIPS_LO16s while (i + 1 < rel.Count) { i++; relLo = rel[i]; if (relLo.R_Type != Reloc.R_MIPS_LO16) { i--; break; } elf.BaseStream.Position = sec.sh_offset + relLo.r_offset + 2; loData = elf.ReadBigUInt16(); addr = hiAddr + (loData & 0xFFFF) + relSecAddr + symtab[relLo.R_Sym].st_value; lo16 = (ushort)(addr & 0xFFFF); ovl.BaseStream.Position = fOff + relLo.r_offset + 2; ovl.WriteBig(lo16); ovlRelocations.Add(new Overlay.RelocationWord((Overlay.Section)newSecId, Reloc.R_MIPS_LO16, sOff + relLo.r_offset)); } break; } case Reloc.R_MIPS_LO16: { Console.WriteLine($"R_MIPS_LO16 {fOff + relCur.r_offset:X6} without a proper pair"); return(false); } default: { Console.WriteLine("Incompatible R_MIPS type, cannot convert"); return(false); } } } } ovl.BaseStream.Position = odata.header; foreach (var name in ovlSectionsStr) { ovl.WriteBig(newMap[name].size); } ovl.WriteBig(relocations); foreach (var item in ovlRelocations) { ovl.WriteBig(item.Word); } ovl.BaseStream.Position = ovl.BaseStream.Length - 4; var seekback = (int)(ovl.BaseStream.Length - odata.header); ovl.WriteBig(seekback); } BindRelocatedSymbols(odata, sections, symtabs); return(true); }
private static void ProcessInjectScript(Script script) { if (!File.Exists(script.Rom.Path)) { Console.WriteLine($"Cannot find inject rom {script.Rom.Path}"); return; } if (!int.TryParse(script.Rom.ActorTable, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out int actorTable)) { Console.WriteLine($"Cannot parse Actor Table address {script.Rom.ActorTable}"); return; } Console.WriteLine($"Rom: {script.Rom.Path}"); Console.WriteLine($"Actor Table: {script.Rom.ActorTable:X8}"); using (FileStream rom = new FileStream(script.Rom.Path, FileMode.Open)) { foreach (var actor in script.Actor) { if (!File.Exists(actor.Path)) { Console.WriteLine($"Cannot find file {actor.Path}"); continue; } if (!int.TryParse(actor.Id, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out int id) || !uint.TryParse(actor.VRam, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out uint vram) || !uint.TryParse(actor.VRom, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out uint vrom)) { Console.WriteLine($"Invalid parameter for actor {actor.Path}"); continue; } if (!uint.TryParse(actor.DMA, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out uint dma)) { dma = 0; } if (!File.Exists(actor.Path)) { Console.WriteLine($"Cannot locate {actor.Path}"); continue; } Ovl odata = new Ovl { start = vram, BindingSymbolName = { { "init", actor.InitBinding } } }; byte[] data = new byte[0]; using (FileStream elf = new FileStream(actor.Path, FileMode.Open)) { BinaryReader br = new BinaryReader(elf); if (!TryConvertToOverlay(br, odata, out data)) { Console.WriteLine($"Conversion of {actor.Path} failed!"); continue; } } odata.UpdateActorOverlay(new BinaryWriter(rom), actorTable, id, vrom, dma); rom.Position = vrom; rom.Write(data, 0, data.Length); } CRC.Write(rom); } }