Ryujinx/Ryujinx.HLE/Loaders/Executable.cs
Thomas Guillemard c2c765b30f hbabi: Implement argv (#272)
This commit implements the argv config key in Ryujinx (by creating a temporary copy of the homebrew executable in the sdmc VFS) to make it possible
to load libnx's "romfs" files.

This commit also call Os.Dispose in Ns.OnFinish to dispose all resources when exiting
2018-07-17 16:14:27 -03:00

177 lines
5.6 KiB
C#

using ChocolArm64.Memory;
using Ryujinx.HLE.Loaders.Executables;
using Ryujinx.HLE.OsHle;
using System.Collections.Generic;
using System.IO;
namespace Ryujinx.HLE.Loaders
{
class Executable
{
private List<ElfDyn> Dynamic;
private Dictionary<long, string> m_SymbolTable;
public IReadOnlyDictionary<long, string> SymbolTable => m_SymbolTable;
public string Name { get; private set; }
public string FilePath { get; private set; }
private AMemory Memory;
public long ImageBase { get; private set; }
public long ImageEnd { get; private set; }
public Executable(IExecutable Exe, AMemory Memory, long ImageBase)
{
Dynamic = new List<ElfDyn>();
m_SymbolTable = new Dictionary<long, string>();
FilePath = Exe.FilePath;
Name = Path.GetFileNameWithoutExtension(FilePath.Replace(Homebrew.TemporaryNroSuffix, ""));
this.Memory = Memory;
this.ImageBase = ImageBase;
this.ImageEnd = ImageBase;
WriteData(ImageBase + Exe.TextOffset, Exe.Text, MemoryType.CodeStatic, AMemoryPerm.RX);
WriteData(ImageBase + Exe.ROOffset, Exe.RO, MemoryType.CodeMutable, AMemoryPerm.Read);
WriteData(ImageBase + Exe.DataOffset, Exe.Data, MemoryType.CodeMutable, AMemoryPerm.RW);
if (Exe.Mod0Offset == 0)
{
int BssOffset = Exe.DataOffset + Exe.Data.Length;
int BssSize = Exe.BssSize;
MapBss(ImageBase + BssOffset, BssSize);
ImageEnd = ImageBase + BssOffset + BssSize;
return;
}
long Mod0Offset = ImageBase + Exe.Mod0Offset;
int Mod0Magic = Memory.ReadInt32(Mod0Offset + 0x0);
long DynamicOffset = Memory.ReadInt32(Mod0Offset + 0x4) + Mod0Offset;
long BssStartOffset = Memory.ReadInt32(Mod0Offset + 0x8) + Mod0Offset;
long BssEndOffset = Memory.ReadInt32(Mod0Offset + 0xc) + Mod0Offset;
long EhHdrStartOffset = Memory.ReadInt32(Mod0Offset + 0x10) + Mod0Offset;
long EhHdrEndOffset = Memory.ReadInt32(Mod0Offset + 0x14) + Mod0Offset;
long ModObjOffset = Memory.ReadInt32(Mod0Offset + 0x18) + Mod0Offset;
MapBss(BssStartOffset, BssEndOffset - BssStartOffset);
ImageEnd = BssEndOffset;
while (true)
{
long TagVal = Memory.ReadInt64(DynamicOffset + 0);
long Value = Memory.ReadInt64(DynamicOffset + 8);
DynamicOffset += 0x10;
ElfDynTag Tag = (ElfDynTag)TagVal;
if (Tag == ElfDynTag.DT_NULL)
{
break;
}
Dynamic.Add(new ElfDyn(Tag, Value));
}
long StrTblAddr = ImageBase + GetFirstValue(ElfDynTag.DT_STRTAB);
long SymTblAddr = ImageBase + GetFirstValue(ElfDynTag.DT_SYMTAB);
long SymEntSize = GetFirstValue(ElfDynTag.DT_SYMENT);
while ((ulong)SymTblAddr < (ulong)StrTblAddr)
{
ElfSym Sym = GetSymbol(SymTblAddr, StrTblAddr);
m_SymbolTable.TryAdd(Sym.Value, Sym.Name);
SymTblAddr += SymEntSize;
}
}
private void WriteData(
long Position,
byte[] Data,
MemoryType Type,
AMemoryPerm Perm)
{
Memory.Manager.Map(Position, Data.Length, (int)Type, AMemoryPerm.Write);
Memory.WriteBytes(Position, Data);
Memory.Manager.Reprotect(Position, Data.Length, Perm);
}
private void MapBss(long Position, long Size)
{
Memory.Manager.Map(Position, Size, (int)MemoryType.Normal, AMemoryPerm.RW);
}
private ElfRel GetRelocation(long Position)
{
long Offset = Memory.ReadInt64(Position + 0);
long Info = Memory.ReadInt64(Position + 8);
long Addend = Memory.ReadInt64(Position + 16);
int RelType = (int)(Info >> 0);
int SymIdx = (int)(Info >> 32);
ElfSym Symbol = GetSymbol(SymIdx);
return new ElfRel(Offset, Addend, Symbol, (ElfRelType)RelType);
}
private ElfSym GetSymbol(int Index)
{
long StrTblAddr = ImageBase + GetFirstValue(ElfDynTag.DT_STRTAB);
long SymTblAddr = ImageBase + GetFirstValue(ElfDynTag.DT_SYMTAB);
long SymEntSize = GetFirstValue(ElfDynTag.DT_SYMENT);
long Position = SymTblAddr + Index * SymEntSize;
return GetSymbol(Position, StrTblAddr);
}
private ElfSym GetSymbol(long Position, long StrTblAddr)
{
int NameIndex = Memory.ReadInt32(Position + 0);
int Info = Memory.ReadByte(Position + 4);
int Other = Memory.ReadByte(Position + 5);
int SHIdx = Memory.ReadInt16(Position + 6);
long Value = Memory.ReadInt64(Position + 8);
long Size = Memory.ReadInt64(Position + 16);
string Name = string.Empty;
for (int Chr; (Chr = Memory.ReadByte(StrTblAddr + NameIndex++)) != 0;)
{
Name += (char)Chr;
}
return new ElfSym(Name, Info, Other, SHIdx, Value, Size);
}
private long GetFirstValue(ElfDynTag Tag)
{
foreach (ElfDyn Entry in Dynamic)
{
if (Entry.Tag == Tag)
{
return Entry.Value;
}
}
return 0;
}
}
}