Exemplo n.º 1
0
        /// <summary>
        ///
        /// </summary>
        /// <returns></returns>
        public static HSDAccessor GenerateFunctionDAT(LinkedELF lelf, LinkFile link, string[] functions, bool debug, bool quiet = false)
        {
            // Generate Function DAT
            var function = new HSDAccessor()
            {
                _s = new HSDStruct(0x20)
            };

            // Generate code section
            HSDStruct debug_symbol_table = null;
            int       debug_symbol_count = 0;
            Dictionary <SymbolData, long> dataToOffset = new Dictionary <SymbolData, long>();

            byte[] codedata;
            using (MemoryStream code = new MemoryStream())
            {
                // create debug symbol table
                if (debug)
                {
                    debug_symbol_table = new HSDStruct((lelf.AllSymbols.Count + 1) * 0xC);
                }

                // process all code
                foreach (var v in lelf.AllSymbols)
                {
                    // align
                    if (code.Length % 4 != 0)
                    {
                        code.Write(new byte[4 - (code.Length % 4)], 0, 4 - ((int)code.Length % 4));
                    }

                    int code_start = (int)code.Position;
                    // write code
                    if (v.Data.Length == 0 && link.TryGetSymbolAddress(CppSanatize(v.Symbol), out uint addr))
                    {
                        dataToOffset.Add(v, addr);
                    }
                    else
                    {
                        dataToOffset.Add(v, code.Length);
                        code.Write(v.Data, 0, v.Data.Length);
                    }
                    int code_end = (int)code.Position;

                    //Console.WriteLine($"{v.SectionName} {v.Symbol} Start: {code_start.ToString("X")} End: {code_end.ToString("X")} ");

                    if (debug && code_start != code_end)
                    {
                        debug_symbol_table.SetInt32(debug_symbol_count * 0xC, code_start);
                        debug_symbol_table.SetInt32(debug_symbol_count * 0xC + 4, code_end);
                        debug_symbol_table.SetString(debug_symbol_count * 0xC + 8, string.IsNullOrEmpty(v.Symbol) ? v.SectionName : v.Symbol, true);
                        debug_symbol_count++;
                    }
                }
                codedata = code.ToArray();

                // resize debug table
                if (debug)
                {
                    debug_symbol_table.Resize(debug_symbol_count * 0xC);
                }
            }

            // generate function table
            HSDStruct functionTable = new HSDStruct(8);
            var       funcCount     = 0;
            var       fl            = functions.ToList();

            foreach (var v in lelf.SymbolToData)
            {
                functionTable.Resize(8 * (funcCount + 1));
                functionTable.SetInt32(funcCount * 8, fl.IndexOf(v.Key));
                functionTable.SetInt32(funcCount * 8 + 4, (int)dataToOffset[v.Value]);
                funcCount++;
            }


            // set function table
            function._s.SetReferenceStruct(0x0C, functionTable);
            function._s.SetInt32(0x10, funcCount);


            // Generate Relocation Table
            HSDStruct relocationTable = new HSDStruct(0);
            var       relocCount      = 0;

            foreach (var v in lelf.AllSymbols)
            {
                // check data length
                if (v.Data.Length == 0)
                {
                    if (link.ContainsSymbol(CppSanatize(v.Symbol)))
                    {
                        continue;
                    }
                    else
                    {
                        throw new Exception($"Error: {v.Symbol} length is {v.Data.Length.ToString("X")}");
                    }
                }

                // print debug info
                if (!quiet)
                {
                    Console.WriteLine($"{v.Symbol,-30} {v.SectionName, -50} Offset: {dataToOffset[v].ToString("X8"), -16} Length: {v.Data.Length.ToString("X8")}");

                    if (v.Relocations.Count > 0)
                    {
                        Console.WriteLine($"\t {"Section:",-50} {"RelocType:",-20} {"FuncOffset:", -16} {"SectionOffset:"}");
                    }
                }

                // process and create relocation table
                foreach (var reloc in v.Relocations)
                {
                    if (!quiet)
                    {
                        Console.WriteLine($"\t {reloc.Symbol.SectionName, -50} {reloc.Type, -20} {reloc.Offset.ToString("X8"), -16} {reloc.AddEnd.ToString("X8")}");
                    }

                    // gather code positions
                    var codeOffset       = (int)(dataToOffset[v] + reloc.Offset);
                    var toFunctionOffset = (int)(dataToOffset[reloc.Symbol] + reloc.AddEnd);

                    // currently supported types check
                    switch (reloc.Type)
                    {
                    case RelocType.R_PPC_REL32:
                    case RelocType.R_PPC_REL24:
                    case RelocType.R_PPC_ADDR32:
                    case RelocType.R_PPC_ADDR16_LO:
                    case RelocType.R_PPC_ADDR16_HA:
                        break;

                    case (RelocType)0x6D:
                        break;

                    default:
                        // no exception, but not guarenteed to work
                        Console.WriteLine($"Warning: unsupported reloc type {toFunctionOffset.ToString("X")} " + reloc.Type.ToString("X") + $" in {v.Symbol} to {reloc.Symbol.Symbol} send this to Ploaj or UnclePunch");
                        break;
                    }

                    bool addEntry = true;

                    // only apply optimization if not external
                    if (!reloc.Symbol.External)
                    {
                        // calculate relative offset
                        var rel = toFunctionOffset - codeOffset;

                        // apply relocation automatically if possible
                        switch (reloc.Type)
                        {
                        case (RelocType)0x6D:
                        case RelocType.R_PPC_REL32:
                            codedata[codeOffset]     = (byte)((rel >> 24) & 0xFF);
                            codedata[codeOffset + 1] = (byte)((rel >> 16) & 0xFF);
                            codedata[codeOffset + 2] = (byte)((rel >> 8) & 0xFF);
                            codedata[codeOffset + 3] = (byte)((rel) & 0xFF);

                            addEntry = false;
                            break;

                        case RelocType.R_PPC_REL24:
                            var cur = ((codedata[codeOffset] & 0xFF) << 24) | ((codedata[codeOffset + 1] & 0xFF) << 16) | ((codedata[codeOffset + 2] & 0xFF) << 8) | ((codedata[codeOffset + 3] & 0xFF));
                            rel = cur | (rel & 0x03FFFFFC);

                            codedata[codeOffset]     = (byte)((rel >> 24) & 0xFF);
                            codedata[codeOffset + 1] = (byte)((rel >> 16) & 0xFF);
                            codedata[codeOffset + 2] = (byte)((rel >> 8) & 0xFF);
                            codedata[codeOffset + 3] = (byte)((rel) & 0xFF);

                            addEntry = false;
                            break;
                        }
                    }

                    // add relocation to table
                    if (addEntry)
                    {
                        relocationTable.Resize((relocCount + 1) * 0x08);
                        relocationTable.SetInt32(0x00 + relocCount * 8, codeOffset);
                        relocationTable.SetByte(0x00 + relocCount * 8, (byte)reloc.Type);
                        relocationTable.SetInt32(0x04 + relocCount * 8, toFunctionOffset);

                        relocCount++;
                    }
                }
            }

            function._s.SetReferenceStruct(0x00, new HSDStruct(codedata));
            function._s.SetReferenceStruct(0x04, relocationTable);
            function._s.SetInt32(0x08, relocCount);

            if (debug_symbol_table != null)
            {
                function._s.SetInt32(0x14, codedata.Length);
                function._s.SetInt32(0x18, debug_symbol_count);
                function._s.SetReferenceStruct(0x1C, debug_symbol_table);
            }

            return(function);
        }
Exemplo n.º 2
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="elfFiles"></param>
        /// <param name="linkFiles"></param>
        /// <param name="functions"></param>
        /// <param name="quiet"></param>
        public static LinkedELF LinkELFs(List <RelocELF> elfFiles, LinkFile linkFiles, string[] functions, bool quiet = false)
        {
            LinkedELF lelf = new LinkedELF();

            // Grab Symbol Table Info
            Queue <SymbolData> symbolQueue = new Queue <SymbolData>();

            // Gather the root symbols needed for function table
            if (functions == null)
            {
                if (!quiet)
                {
                    Console.WriteLine("No function table entered: defaulting to patching");
                }

                foreach (var elf in elfFiles)
                {
                    foreach (var sym in elf.SymbolSections)
                    {
                        var m = System.Text.RegularExpressions.Regex.Matches(sym.Symbol, @"0[xX][0-9a-fA-F]+");
                        if (m.Count > 0)
                        {
                            uint loc;
                            if (uint.TryParse(m[0].Value.ToLower().Replace("0x", ""), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out loc))
                            {
                                lelf.SymbolToData.Add(loc.ToString("X"), sym);
                                symbolQueue.Enqueue(sym);
                            }
                        }
                    }
                }
            }
            else
            {
                for (int i = 0; i < functions.Length; i++)
                {
                    foreach (var elf in elfFiles)
                    {
                        var sym = elf.SymbolSections.Find(e => CppSanatize(e.Symbol).Equals(functions[i], StringComparison.InvariantCultureIgnoreCase));

                        if (lelf.SymbolToData.ContainsKey(functions[i]))
                        {
                            Console.WriteLine($"Warning: found two table functions with the same symbol {functions[i]} defaulting to first found");
                        }
                        else
                        if (sym != null)
                        {
                            lelf.SymbolToData.Add(functions[i], sym);
                            symbolQueue.Enqueue(sym);
                        }
                    }
                }
            }

            // Resolve External and Duplicate Symbols
            Dictionary <SymbolData, SymbolData> SymbolRemapper = new Dictionary <SymbolData, SymbolData>();

            // Get All Symbols and Dependencies
            while (symbolQueue.Count > 0)
            {
                var orgsym = symbolQueue.Dequeue();
                var sym    = orgsym;

                // check if already remapped
                if (SymbolRemapper.ContainsKey(sym))
                {
                    continue;
                }

                // resolve external and remap
                if (sym.External)
                {
                    bool found = false;

                    foreach (var elf in elfFiles)
                    {
                        var externalSymbol = elf.SymbolSections.Where(e => e.Symbol.Equals(sym.Symbol) && !e.External).ToArray();

                        if (externalSymbol.Length > 0)
                        {
                            found = true;
                            SymbolRemapper.Add(sym, externalSymbol[0]);
                            sym = externalSymbol[0];
                            break;
                        }
                    }

                    if (linkFiles.ContainsSymbol(CppSanatize(sym.Symbol)))
                    {
                        found = true;
                    }

                    if (!found && sym.Symbol != "_GLOBAL_OFFSET_TABLE_")
                    {
                        throw new Exception("Could not resolve external symbol " + sym.Symbol + " - " + sym.SectionName + " " + sym.External);
                    }
                }

                // resolve duplicates
                if (!string.IsNullOrEmpty(sym.Symbol))
                {
                    bool duplicate = false;
                    // check if a symbol with this name is already used
                    foreach (var s in lelf.AllSymbols)
                    {
                        if (s.Symbol.Equals(sym.Symbol))
                        {
                            // remap this symbol and mark as duplicate
                            if (!SymbolRemapper.ContainsKey(sym))
                            {
                                SymbolRemapper.Add(sym, s);
                            }
                            duplicate = true;
                            break;
                        }
                    }
                    // if a duplicate is found, ignore this symbol
                    if (duplicate)
                    {
                        continue;
                    }
                }


                // hack to inject static variables from link file
                if (linkFiles.TryGetSymbolAddress(CppSanatize(sym.Symbol), out uint addr) &&
                    sym.Data.Length == 4 &&
                    sym.Data[0] == 0 && sym.Data[1] == 0 && sym.Data[2] == 0 && sym.Data[3] == 0)
                {
                    sym.Data = new byte[] { (byte)((addr >> 24) & 0xFF), (byte)((addr >> 16) & 0xFF), (byte)((addr >> 8) & 0xFF), (byte)(addr & 0xFF) };
                }

                // add symbols
                lelf.AllSymbols.Add(sym);


                // gather relocations from other symbols if necessary
                // transfer relocations??
                // if these are the same symbol and there is supposed to be a relocation, then port it?
                foreach (var el in elfFiles)
                {
                    var symcols = el.SymbolSections.Where(e =>
                                                          e != sym &&
                                                          e.SectionName == sym.SectionName &&
                                                          e.Data.SequenceEqual(sym.Data));

                    foreach (var s in symcols)
                    {
                        foreach (var sReloc in s.Relocations)
                        {
                            var exists = sym.Relocations.Exists(e => e.Equals(sReloc));

                            if (!exists)
                            {
                                sym.Relocations.Add(sReloc);
                            }
                        }
                    }
                }

                // add relocation sections to queue
                foreach (var v in sym.Relocations)
                {
                    if (!lelf.AllSymbols.Contains(v.Symbol) && !symbolQueue.Contains(v.Symbol))
                    {
                        symbolQueue.Enqueue(v.Symbol);
                    }
                }
            }


            // remap relocation table
            foreach (var v in lelf.AllSymbols)
            {
                System.Diagnostics.Debug.WriteLine(v.SectionName + " " + v.Relocations.Count);
                for (int i = 0; i < v.Relocations.Count; i++)
                {
                    if (SymbolRemapper.ContainsKey(v.Relocations[i].Symbol))
                    {
                        v.Relocations[i].Symbol = SymbolRemapper[v.Relocations[i].Symbol];
                    }

                    if (!lelf.AllSymbols.Contains(v.Relocations[i].Symbol) && !linkFiles.ContainsSymbol(CppSanatize(v.Relocations[i].Symbol.Symbol)))
                    {
                        throw new Exception("Missing Symbol " + v.Relocations[i].Symbol.Symbol + " " + v.Symbol);
                    }
                }
            }

            return(lelf);
        }