Use libhac for loading NSO and KIP (#1047)
* Use libhac for loading NSOs and KIPs * Fix formatting * Refactor KIP and NSO executables for libhac * Fix up formatting * Remove Ryujinx.HLE.Loaders.Compression * Remove reference to Ryujinx.HLE.Loaders.Compression in NxStaticObject.cs * Remove reference to Ryujinx.HLE.Loaders.Compression in KernelInitialProcess.cs * Rename classes in Ryujinx.HLE.Loaders.Executables * Fix space alignment * Fix up formatting
This commit is contained in:
@ -1,147 +0,0 @@
|
||||
using Ryujinx.HLE.Loaders.Compression;
|
||||
using System.IO;
|
||||
|
||||
namespace Ryujinx.HLE.Loaders.Executables
|
||||
{
|
||||
class KernelInitialProcess : IExecutable
|
||||
{
|
||||
public string Name { get; private set; }
|
||||
|
||||
public ulong TitleId { get; private set; }
|
||||
|
||||
public int ProcessCategory { get; private set; }
|
||||
|
||||
public byte MainThreadPriority { get; private set; }
|
||||
public byte DefaultProcessorId { get; private set; }
|
||||
|
||||
public bool Is64Bits { get; private set; }
|
||||
public bool Addr39Bits { get; private set; }
|
||||
public bool IsService { get; private set; }
|
||||
|
||||
public byte[] Text { get; private set; }
|
||||
public byte[] Ro { get; private set; }
|
||||
public byte[] Data { get; private set; }
|
||||
|
||||
public int TextOffset { get; private set; }
|
||||
public int RoOffset { get; private set; }
|
||||
public int DataOffset { get; private set; }
|
||||
public int BssOffset { get; private set; }
|
||||
public int BssSize { get; private set; }
|
||||
|
||||
public int MainThreadStackSize { get; private set; }
|
||||
|
||||
public int[] Capabilities { get; private set; }
|
||||
|
||||
private struct SegmentHeader
|
||||
{
|
||||
public int Offset { get; private set; }
|
||||
public int DecompressedSize { get; private set; }
|
||||
public int CompressedSize { get; private set; }
|
||||
public int Attribute { get; private set; }
|
||||
|
||||
public SegmentHeader(
|
||||
int offset,
|
||||
int decompressedSize,
|
||||
int compressedSize,
|
||||
int attribute)
|
||||
{
|
||||
Offset = offset;
|
||||
DecompressedSize = decompressedSize;
|
||||
CompressedSize = compressedSize;
|
||||
Attribute = attribute;
|
||||
}
|
||||
}
|
||||
|
||||
public KernelInitialProcess(Stream input)
|
||||
{
|
||||
BinaryReader reader = new BinaryReader(input);
|
||||
|
||||
string magic = ReadString(reader, 4);
|
||||
|
||||
if (magic != "KIP1")
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Name = ReadString(reader, 12);
|
||||
|
||||
TitleId = reader.ReadUInt64();
|
||||
|
||||
ProcessCategory = reader.ReadInt32();
|
||||
|
||||
MainThreadPriority = reader.ReadByte();
|
||||
DefaultProcessorId = reader.ReadByte();
|
||||
|
||||
byte reserved = reader.ReadByte();
|
||||
byte flags = reader.ReadByte();
|
||||
|
||||
Is64Bits = (flags & 0x08) != 0;
|
||||
Addr39Bits = (flags & 0x10) != 0;
|
||||
IsService = (flags & 0x20) != 0;
|
||||
|
||||
SegmentHeader[] segments = new SegmentHeader[6];
|
||||
|
||||
for (int index = 0; index < segments.Length; index++)
|
||||
{
|
||||
segments[index] = new SegmentHeader(
|
||||
reader.ReadInt32(),
|
||||
reader.ReadInt32(),
|
||||
reader.ReadInt32(),
|
||||
reader.ReadInt32());
|
||||
}
|
||||
|
||||
TextOffset = segments[0].Offset;
|
||||
RoOffset = segments[1].Offset;
|
||||
DataOffset = segments[2].Offset;
|
||||
BssOffset = segments[3].Offset;
|
||||
BssSize = segments[3].DecompressedSize;
|
||||
|
||||
MainThreadStackSize = segments[1].Attribute;
|
||||
|
||||
Capabilities = new int[32];
|
||||
|
||||
for (int index = 0; index < Capabilities.Length; index++)
|
||||
{
|
||||
Capabilities[index] = reader.ReadInt32();
|
||||
}
|
||||
|
||||
input.Seek(0x100, SeekOrigin.Begin);
|
||||
|
||||
Text = ReadSegment(segments[0], input);
|
||||
Ro = ReadSegment(segments[1], input);
|
||||
Data = ReadSegment(segments[2], input);
|
||||
}
|
||||
|
||||
private byte[] ReadSegment(SegmentHeader header, Stream input)
|
||||
{
|
||||
byte[] data = new byte[header.DecompressedSize];
|
||||
|
||||
input.Read(data, 0, header.CompressedSize);
|
||||
|
||||
BackwardsLz.DecompressInPlace(data, header.CompressedSize);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
private static string ReadString(BinaryReader reader, int maxSize)
|
||||
{
|
||||
string value = string.Empty;
|
||||
|
||||
for (int index = 0; index < maxSize; index++)
|
||||
{
|
||||
char chr = (char)reader.ReadByte();
|
||||
|
||||
if (chr == '\0')
|
||||
{
|
||||
reader.BaseStream.Seek(maxSize - index - 1, SeekOrigin.Current);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
value += chr;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
35
Ryujinx.HLE/Loaders/Executables/KipExecutable.cs
Normal file
35
Ryujinx.HLE/Loaders/Executables/KipExecutable.cs
Normal file
@ -0,0 +1,35 @@
|
||||
using LibHac;
|
||||
using LibHac.Fs;
|
||||
using System.IO;
|
||||
|
||||
namespace Ryujinx.HLE.Loaders.Executables
|
||||
{
|
||||
class KipExecutable : Kip, IExecutable
|
||||
{
|
||||
public byte[] Text { get; }
|
||||
public byte[] Ro { get; }
|
||||
public byte[] Data { get; }
|
||||
|
||||
public int TextOffset => Header.Sections[0].OutOffset;
|
||||
public int RoOffset => Header.Sections[1].OutOffset;
|
||||
public int DataOffset => Header.Sections[2].OutOffset;
|
||||
public int BssOffset => Header.Sections[3].OutOffset;
|
||||
public int BssSize => Header.Sections[3].DecompressedSize;
|
||||
|
||||
public int[] Capabilities { get; }
|
||||
|
||||
public KipExecutable(IStorage inStorage) : base(inStorage)
|
||||
{
|
||||
Capabilities = new int[32];
|
||||
|
||||
for (int index = 0; index < Capabilities.Length; index++)
|
||||
{
|
||||
Capabilities[index] = System.BitConverter.ToInt32(Header.Capabilities, index * 4);
|
||||
}
|
||||
|
||||
Text = DecompressSection(0);
|
||||
Ro = DecompressSection(1);
|
||||
Data = DecompressSection(2);
|
||||
}
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@ using System.IO;
|
||||
|
||||
namespace Ryujinx.HLE.Loaders.Executables
|
||||
{
|
||||
class NxRelocatableObject : IExecutable
|
||||
class NroExecutable : IExecutable
|
||||
{
|
||||
public byte[] Text { get; private set; }
|
||||
public byte[] Ro { get; private set; }
|
||||
@ -20,7 +20,7 @@ namespace Ryujinx.HLE.Loaders.Executables
|
||||
public ulong SourceAddress { get; private set; }
|
||||
public ulong BssAddress { get; private set; }
|
||||
|
||||
public NxRelocatableObject(Stream input, ulong sourceAddress = 0, ulong bssAddress = 0)
|
||||
public NroExecutable(Stream input, ulong sourceAddress = 0, ulong bssAddress = 0)
|
||||
{
|
||||
SourceAddress = sourceAddress;
|
||||
BssAddress = bssAddress;
|
28
Ryujinx.HLE/Loaders/Executables/NsoExecutable.cs
Normal file
28
Ryujinx.HLE/Loaders/Executables/NsoExecutable.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using LibHac;
|
||||
using LibHac.Fs;
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Ryujinx.HLE.Loaders.Executables
|
||||
{
|
||||
class NsoExecutable : Nso, IExecutable
|
||||
{
|
||||
public byte[] Text { get; }
|
||||
public byte[] Ro { get; }
|
||||
public byte[] Data { get; }
|
||||
|
||||
public int TextOffset => (int)Sections[0].MemoryOffset;
|
||||
public int RoOffset => (int)Sections[1].MemoryOffset;
|
||||
public int DataOffset => (int)Sections[2].MemoryOffset;
|
||||
public int BssOffset => DataOffset + Data.Length;
|
||||
|
||||
public new int BssSize => (int)base.BssSize;
|
||||
|
||||
public NsoExecutable(IStorage inStorage) : base(inStorage)
|
||||
{
|
||||
Text = Sections[0].DecompressSection();
|
||||
Ro = Sections[1].DecompressSection();
|
||||
Data = Sections[2].DecompressSection();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,109 +0,0 @@
|
||||
using Ryujinx.HLE.Loaders.Compression;
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Ryujinx.HLE.Loaders.Executables
|
||||
{
|
||||
class NxStaticObject : IExecutable
|
||||
{
|
||||
public byte[] Text { get; private set; }
|
||||
public byte[] Ro { get; private set; }
|
||||
public byte[] Data { get; private set; }
|
||||
|
||||
public int TextOffset { get; private set; }
|
||||
public int RoOffset { get; private set; }
|
||||
public int DataOffset { get; private set; }
|
||||
public int BssSize { get; private set; }
|
||||
|
||||
public int BssOffset => DataOffset + Data.Length;
|
||||
|
||||
[Flags]
|
||||
private enum NsoFlags
|
||||
{
|
||||
IsTextCompressed = 1 << 0,
|
||||
IsRoCompressed = 1 << 1,
|
||||
IsDataCompressed = 1 << 2,
|
||||
HasTextHash = 1 << 3,
|
||||
HasRoHash = 1 << 4,
|
||||
HasDataHash = 1 << 5
|
||||
}
|
||||
|
||||
public NxStaticObject(Stream input)
|
||||
{
|
||||
BinaryReader reader = new BinaryReader(input);
|
||||
|
||||
input.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
int nsoMagic = reader.ReadInt32();
|
||||
int version = reader.ReadInt32();
|
||||
int reserved = reader.ReadInt32();
|
||||
int flagsMsk = reader.ReadInt32();
|
||||
int textOffset = reader.ReadInt32();
|
||||
int textMemOffset = reader.ReadInt32();
|
||||
int textDecSize = reader.ReadInt32();
|
||||
int modNameOffset = reader.ReadInt32();
|
||||
int roOffset = reader.ReadInt32();
|
||||
int roMemOffset = reader.ReadInt32();
|
||||
int roDecSize = reader.ReadInt32();
|
||||
int modNameSize = reader.ReadInt32();
|
||||
int dataOffset = reader.ReadInt32();
|
||||
int dataMemOffset = reader.ReadInt32();
|
||||
int dataDecSize = reader.ReadInt32();
|
||||
int bssSize = reader.ReadInt32();
|
||||
|
||||
byte[] buildId = reader.ReadBytes(0x20);
|
||||
|
||||
int textSize = reader.ReadInt32();
|
||||
int roSize = reader.ReadInt32();
|
||||
int dataSize = reader.ReadInt32();
|
||||
|
||||
input.Seek(0x24, SeekOrigin.Current);
|
||||
|
||||
int dynStrOffset = reader.ReadInt32();
|
||||
int dynStrSize = reader.ReadInt32();
|
||||
int dynSymOffset = reader.ReadInt32();
|
||||
int dynSymSize = reader.ReadInt32();
|
||||
|
||||
byte[] textHash = reader.ReadBytes(0x20);
|
||||
byte[] roHash = reader.ReadBytes(0x20);
|
||||
byte[] dataHash = reader.ReadBytes(0x20);
|
||||
|
||||
NsoFlags flags = (NsoFlags)flagsMsk;
|
||||
|
||||
TextOffset = textMemOffset;
|
||||
RoOffset = roMemOffset;
|
||||
DataOffset = dataMemOffset;
|
||||
BssSize = bssSize;
|
||||
|
||||
// Text segment
|
||||
input.Seek(textOffset, SeekOrigin.Begin);
|
||||
|
||||
Text = reader.ReadBytes(textSize);
|
||||
|
||||
if (flags.HasFlag(NsoFlags.IsTextCompressed) && textSize != 0)
|
||||
{
|
||||
Text = Lz4.Decompress(Text, textDecSize);
|
||||
}
|
||||
|
||||
// Read-only data segment
|
||||
input.Seek(roOffset, SeekOrigin.Begin);
|
||||
|
||||
Ro = reader.ReadBytes(roSize);
|
||||
|
||||
if (flags.HasFlag(NsoFlags.IsRoCompressed) && roSize != 0)
|
||||
{
|
||||
Ro = Lz4.Decompress(Ro, roDecSize);
|
||||
}
|
||||
|
||||
// Data segment
|
||||
input.Seek(dataOffset, SeekOrigin.Begin);
|
||||
|
||||
Data = reader.ReadBytes(dataSize);
|
||||
|
||||
if (flags.HasFlag(NsoFlags.IsDataCompressed) && dataSize != 0)
|
||||
{
|
||||
Data = Lz4.Decompress(Data, dataDecSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user