aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Core/Loaders
diff options
context:
space:
mode:
authoremmauss <emmausssss@gmail.com>2018-02-20 22:09:23 +0200
committergdkchan <gab.dark.100@gmail.com>2018-02-20 17:09:23 -0300
commit62b827f474f0aa2152dd339fcc7cf31084e16a0b (patch)
tree0e5c55b341aee4db0ccb841a084f253ec5e05657 /Ryujinx.Core/Loaders
parentcb665bb715834526d73c9469d16114b287faaecd (diff)
Split main project into core,graphics and chocolarm4 subproject (#29)
Diffstat (limited to 'Ryujinx.Core/Loaders')
-rw-r--r--Ryujinx.Core/Loaders/Compression/Lz4.cs78
-rw-r--r--Ryujinx.Core/Loaders/ElfDyn.cs15
-rw-r--r--Ryujinx.Core/Loaders/ElfDynTag.cs72
-rw-r--r--Ryujinx.Core/Loaders/ElfRel.cs19
-rw-r--r--Ryujinx.Core/Loaders/ElfRelType.cs128
-rw-r--r--Ryujinx.Core/Loaders/ElfSym.cs43
-rw-r--r--Ryujinx.Core/Loaders/ElfSymBinding.cs9
-rw-r--r--Ryujinx.Core/Loaders/ElfSymType.cs13
-rw-r--r--Ryujinx.Core/Loaders/ElfSymVisibility.cs10
-rw-r--r--Ryujinx.Core/Loaders/Executable.cs149
-rw-r--r--Ryujinx.Core/Loaders/Executables/IExecutable.cs17
-rw-r--r--Ryujinx.Core/Loaders/Executables/Nro.cs62
-rw-r--r--Ryujinx.Core/Loaders/Executables/Nso.cs122
13 files changed, 737 insertions, 0 deletions
diff --git a/Ryujinx.Core/Loaders/Compression/Lz4.cs b/Ryujinx.Core/Loaders/Compression/Lz4.cs
new file mode 100644
index 00000000..eb1602a0
--- /dev/null
+++ b/Ryujinx.Core/Loaders/Compression/Lz4.cs
@@ -0,0 +1,78 @@
+using System;
+
+namespace Ryujinx.Core.Loaders.Compression
+{
+ static class Lz4
+ {
+ public static byte[] Decompress(byte[] Cmp, int DecLength)
+ {
+ byte[] Dec = new byte[DecLength];
+
+ int CmpPos = 0;
+ int DecPos = 0;
+
+ int GetLength(int Length)
+ {
+ byte Sum;
+
+ if (Length == 0xf)
+ {
+ do
+ {
+ Length += (Sum = Cmp[CmpPos++]);
+ }
+ while (Sum == 0xff);
+ }
+
+ return Length;
+ }
+
+ do
+ {
+ byte Token = Cmp[CmpPos++];
+
+ int EncCount = (Token >> 0) & 0xf;
+ int LitCount = (Token >> 4) & 0xf;
+
+ //Copy literal chunck
+ LitCount = GetLength(LitCount);
+
+ Buffer.BlockCopy(Cmp, CmpPos, Dec, DecPos, LitCount);
+
+ CmpPos += LitCount;
+ DecPos += LitCount;
+
+ if (CmpPos >= Cmp.Length)
+ {
+ break;
+ }
+
+ //Copy compressed chunck
+ int Back = Cmp[CmpPos++] << 0 |
+ Cmp[CmpPos++] << 8;
+
+ EncCount = GetLength(EncCount) + 4;
+
+ int EncPos = DecPos - Back;
+
+ if (EncCount <= Back)
+ {
+ Buffer.BlockCopy(Dec, EncPos, Dec, DecPos, EncCount);
+
+ DecPos += EncCount;
+ }
+ else
+ {
+ while (EncCount-- > 0)
+ {
+ Dec[DecPos++] = Dec[EncPos++];
+ }
+ }
+ }
+ while (CmpPos < Cmp.Length &&
+ DecPos < Dec.Length);
+
+ return Dec;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/Loaders/ElfDyn.cs b/Ryujinx.Core/Loaders/ElfDyn.cs
new file mode 100644
index 00000000..2ed50b3e
--- /dev/null
+++ b/Ryujinx.Core/Loaders/ElfDyn.cs
@@ -0,0 +1,15 @@
+namespace Ryujinx.Core.Loaders
+{
+ struct ElfDyn
+ {
+ public ElfDynTag Tag { get; private set; }
+
+ public long Value { get; private set; }
+
+ public ElfDyn(ElfDynTag Tag, long Value)
+ {
+ this.Tag = Tag;
+ this.Value = Value;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/Loaders/ElfDynTag.cs b/Ryujinx.Core/Loaders/ElfDynTag.cs
new file mode 100644
index 00000000..1616c223
--- /dev/null
+++ b/Ryujinx.Core/Loaders/ElfDynTag.cs
@@ -0,0 +1,72 @@
+namespace Ryujinx.Core.Loaders
+{
+ enum ElfDynTag
+ {
+ DT_NULL = 0,
+ DT_NEEDED = 1,
+ DT_PLTRELSZ = 2,
+ DT_PLTGOT = 3,
+ DT_HASH = 4,
+ DT_STRTAB = 5,
+ DT_SYMTAB = 6,
+ DT_RELA = 7,
+ DT_RELASZ = 8,
+ DT_RELAENT = 9,
+ DT_STRSZ = 10,
+ DT_SYMENT = 11,
+ DT_INIT = 12,
+ DT_FINI = 13,
+ DT_SONAME = 14,
+ DT_RPATH = 15,
+ DT_SYMBOLIC = 16,
+ DT_REL = 17,
+ DT_RELSZ = 18,
+ DT_RELENT = 19,
+ DT_PLTREL = 20,
+ DT_DEBUG = 21,
+ DT_TEXTREL = 22,
+ DT_JMPREL = 23,
+ DT_BIND_NOW = 24,
+ DT_INIT_ARRAY = 25,
+ DT_FINI_ARRAY = 26,
+ DT_INIT_ARRAYSZ = 27,
+ DT_FINI_ARRAYSZ = 28,
+ DT_RUNPATH = 29,
+ DT_FLAGS = 30,
+ DT_ENCODING = 32,
+ DT_PREINIT_ARRAY = 32,
+ DT_PREINIT_ARRAYSZ = 33,
+ DT_GNU_PRELINKED = 0x6ffffdf5,
+ DT_GNU_CONFLICTSZ = 0x6ffffdf6,
+ DT_GNU_LIBLISTSZ = 0x6ffffdf7,
+ DT_CHECKSUM = 0x6ffffdf8,
+ DT_PLTPADSZ = 0x6ffffdf9,
+ DT_MOVEENT = 0x6ffffdfa,
+ DT_MOVESZ = 0x6ffffdfb,
+ DT_FEATURE_1 = 0x6ffffdfc,
+ DT_POSFLAG_1 = 0x6ffffdfd,
+ DT_SYMINSZ = 0x6ffffdfe,
+ DT_SYMINENT = 0x6ffffdff,
+ DT_GNU_HASH = 0x6ffffef5,
+ DT_TLSDESC_PLT = 0x6ffffef6,
+ DT_TLSDESC_GOT = 0x6ffffef7,
+ DT_GNU_CONFLICT = 0x6ffffef8,
+ DT_GNU_LIBLIST = 0x6ffffef9,
+ DT_CONFIG = 0x6ffffefa,
+ DT_DEPAUDIT = 0x6ffffefb,
+ DT_AUDIT = 0x6ffffefc,
+ DT_PLTPAD = 0x6ffffefd,
+ DT_MOVETAB = 0x6ffffefe,
+ DT_SYMINFO = 0x6ffffeff,
+ DT_VERSYM = 0x6ffffff0,
+ DT_RELACOUNT = 0x6ffffff9,
+ DT_RELCOUNT = 0x6ffffffa,
+ DT_FLAGS_1 = 0x6ffffffb,
+ DT_VERDEF = 0x6ffffffc,
+ DT_VERDEFNUM = 0x6ffffffd,
+ DT_VERNEED = 0x6ffffffe,
+ DT_VERNEEDNUM = 0x6fffffff,
+ DT_AUXILIARY = 0x7ffffffd,
+ DT_FILTER = 0x7fffffff
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/Loaders/ElfRel.cs b/Ryujinx.Core/Loaders/ElfRel.cs
new file mode 100644
index 00000000..8db27452
--- /dev/null
+++ b/Ryujinx.Core/Loaders/ElfRel.cs
@@ -0,0 +1,19 @@
+namespace Ryujinx.Core.Loaders
+{
+ struct ElfRel
+ {
+ public long Offset { get; private set; }
+ public long Addend { get; private set; }
+
+ public ElfSym Symbol { get; private set; }
+ public ElfRelType Type { get; private set; }
+
+ public ElfRel(long Offset, long Addend, ElfSym Symbol, ElfRelType Type)
+ {
+ this.Offset = Offset;
+ this.Addend = Addend;
+ this.Symbol = Symbol;
+ this.Type = Type;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/Loaders/ElfRelType.cs b/Ryujinx.Core/Loaders/ElfRelType.cs
new file mode 100644
index 00000000..a0533138
--- /dev/null
+++ b/Ryujinx.Core/Loaders/ElfRelType.cs
@@ -0,0 +1,128 @@
+namespace Ryujinx.Core.Loaders
+{
+ enum ElfRelType
+ {
+ R_AARCH64_NONE = 0,
+ R_AARCH64_ABS64 = 257,
+ R_AARCH64_ABS32 = 258,
+ R_AARCH64_ABS16 = 259,
+ R_AARCH64_PREL64 = 260,
+ R_AARCH64_PREL32 = 261,
+ R_AARCH64_PREL16 = 262,
+ R_AARCH64_MOVW_UABS_G0 = 263,
+ R_AARCH64_MOVW_UABS_G0_NC = 264,
+ R_AARCH64_MOVW_UABS_G1 = 265,
+ R_AARCH64_MOVW_UABS_G1_NC = 266,
+ R_AARCH64_MOVW_UABS_G2 = 267,
+ R_AARCH64_MOVW_UABS_G2_NC = 268,
+ R_AARCH64_MOVW_UABS_G3 = 269,
+ R_AARCH64_MOVW_SABS_G0 = 270,
+ R_AARCH64_MOVW_SABS_G1 = 271,
+ R_AARCH64_MOVW_SABS_G2 = 272,
+ R_AARCH64_LD_PREL_LO19 = 273,
+ R_AARCH64_ADR_PREL_LO21 = 274,
+ R_AARCH64_ADR_PREL_PG_HI21 = 275,
+ R_AARCH64_ADR_PREL_PG_HI21_NC = 276,
+ R_AARCH64_ADD_ABS_LO12_NC = 277,
+ R_AARCH64_LDST8_ABS_LO12_NC = 278,
+ R_AARCH64_TSTBR14 = 279,
+ R_AARCH64_CONDBR19 = 280,
+ R_AARCH64_JUMP26 = 282,
+ R_AARCH64_CALL26 = 283,
+ R_AARCH64_LDST16_ABS_LO12_NC = 284,
+ R_AARCH64_LDST32_ABS_LO12_NC = 285,
+ R_AARCH64_LDST64_ABS_LO12_NC = 286,
+ R_AARCH64_MOVW_PREL_G0 = 287,
+ R_AARCH64_MOVW_PREL_G0_NC = 288,
+ R_AARCH64_MOVW_PREL_G1 = 289,
+ R_AARCH64_MOVW_PREL_G1_NC = 290,
+ R_AARCH64_MOVW_PREL_G2 = 291,
+ R_AARCH64_MOVW_PREL_G2_NC = 292,
+ R_AARCH64_MOVW_PREL_G3 = 293,
+ R_AARCH64_LDST128_ABS_LO12_NC = 299,
+ R_AARCH64_MOVW_GOTOFF_G0 = 300,
+ R_AARCH64_MOVW_GOTOFF_G0_NC = 301,
+ R_AARCH64_MOVW_GOTOFF_G1 = 302,
+ R_AARCH64_MOVW_GOTOFF_G1_NC = 303,
+ R_AARCH64_MOVW_GOTOFF_G2 = 304,
+ R_AARCH64_MOVW_GOTOFF_G2_NC = 305,
+ R_AARCH64_MOVW_GOTOFF_G3 = 306,
+ R_AARCH64_GOTREL64 = 307,
+ R_AARCH64_GOTREL32 = 308,
+ R_AARCH64_GOT_LD_PREL19 = 309,
+ R_AARCH64_LD64_GOTOFF_LO15 = 310,
+ R_AARCH64_ADR_GOT_PAGE = 311,
+ R_AARCH64_LD64_GOT_LO12_NC = 312,
+ R_AARCH64_LD64_GOTPAGE_LO15 = 313,
+ R_AARCH64_TLSGD_ADR_PREL21 = 512,
+ R_AARCH64_TLSGD_ADR_PAGE21 = 513,
+ R_AARCH64_TLSGD_ADD_LO12_NC = 514,
+ R_AARCH64_TLSGD_MOVW_G1 = 515,
+ R_AARCH64_TLSGD_MOVW_G0_NC = 516,
+ R_AARCH64_TLSLD_ADR_PREL21 = 517,
+ R_AARCH64_TLSLD_ADR_PAGE21 = 518,
+ R_AARCH64_TLSLD_ADD_LO12_NC = 519,
+ R_AARCH64_TLSLD_MOVW_G1 = 520,
+ R_AARCH64_TLSLD_MOVW_G0_NC = 521,
+ R_AARCH64_TLSLD_LD_PREL19 = 522,
+ R_AARCH64_TLSLD_MOVW_DTPREL_G2 = 523,
+ R_AARCH64_TLSLD_MOVW_DTPREL_G1 = 524,
+ R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC = 525,
+ R_AARCH64_TLSLD_MOVW_DTPREL_G0 = 526,
+ R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC = 527,
+ R_AARCH64_TLSLD_ADD_DTPREL_HI12 = 528,
+ R_AARCH64_TLSLD_ADD_DTPREL_LO12 = 529,
+ R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC = 530,
+ R_AARCH64_TLSLD_LDST8_DTPREL_LO12 = 531,
+ R_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC = 532,
+ R_AARCH64_TLSLD_LDST16_DTPREL_LO12 = 533,
+ R_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC = 534,
+ R_AARCH64_TLSLD_LDST32_DTPREL_LO12 = 535,
+ R_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC = 536,
+ R_AARCH64_TLSLD_LDST64_DTPREL_LO12 = 537,
+ R_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC = 538,
+ R_AARCH64_TLSIE_MOVW_GOTTPREL_G1 = 539,
+ R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC = 540,
+ R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 = 541,
+ R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC = 542,
+ R_AARCH64_TLSIE_LD_GOTTPREL_PREL19 = 543,
+ R_AARCH64_TLSLE_MOVW_TPREL_G2 = 544,
+ R_AARCH64_TLSLE_MOVW_TPREL_G1 = 545,
+ R_AARCH64_TLSLE_MOVW_TPREL_G1_NC = 546,
+ R_AARCH64_TLSLE_MOVW_TPREL_G0 = 547,
+ R_AARCH64_TLSLE_MOVW_TPREL_G0_NC = 548,
+ R_AARCH64_TLSLE_ADD_TPREL_HI12 = 549,
+ R_AARCH64_TLSLE_ADD_TPREL_LO12 = 550,
+ R_AARCH64_TLSLE_ADD_TPREL_LO12_NC = 551,
+ R_AARCH64_TLSLE_LDST8_TPREL_LO12 = 552,
+ R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC = 553,
+ R_AARCH64_TLSLE_LDST16_TPREL_LO12 = 554,
+ R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC = 555,
+ R_AARCH64_TLSLE_LDST32_TPREL_LO12 = 556,
+ R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC = 557,
+ R_AARCH64_TLSLE_LDST64_TPREL_LO12 = 558,
+ R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC = 559,
+ R_AARCH64_TLSDESC_LD_PREL19 = 560,
+ R_AARCH64_TLSDESC_ADR_PREL21 = 561,
+ R_AARCH64_TLSDESC_ADR_PAGE21 = 562,
+ R_AARCH64_TLSDESC_LD64_LO12 = 563,
+ R_AARCH64_TLSDESC_ADD_LO12 = 564,
+ R_AARCH64_TLSDESC_OFF_G1 = 565,
+ R_AARCH64_TLSDESC_OFF_G0_NC = 566,
+ R_AARCH64_TLSDESC_LDR = 567,
+ R_AARCH64_TLSDESC_ADD = 568,
+ R_AARCH64_TLSDESC_CALL = 569,
+ R_AARCH64_TLSLE_LDST128_TPREL_LO12 = 570,
+ R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC = 571,
+ R_AARCH64_TLSLD_LDST128_DTPREL_LO12 = 572,
+ R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC = 573,
+ R_AARCH64_COPY = 1024,
+ R_AARCH64_GLOB_DAT = 1025,
+ R_AARCH64_JUMP_SLOT = 1026,
+ R_AARCH64_RELATIVE = 1027,
+ R_AARCH64_TLS_DTPMOD64 = 1028,
+ R_AARCH64_TLS_DTPREL64 = 1029,
+ R_AARCH64_TLS_TPREL64 = 1030,
+ R_AARCH64_TLSDESC = 1031
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/Loaders/ElfSym.cs b/Ryujinx.Core/Loaders/ElfSym.cs
new file mode 100644
index 00000000..35a45500
--- /dev/null
+++ b/Ryujinx.Core/Loaders/ElfSym.cs
@@ -0,0 +1,43 @@
+namespace Ryujinx.Core.Loaders
+{
+ struct ElfSym
+ {
+ public string Name { get; private set; }
+
+ public ElfSymType Type { get; private set; }
+ public ElfSymBinding Binding { get; private set; }
+ public ElfSymVisibility Visibility { get; private set; }
+
+ public bool IsFuncOrObject =>
+ Type == ElfSymType.STT_FUNC ||
+ Type == ElfSymType.STT_OBJECT;
+
+ public bool IsGlobalOrWeak =>
+ Binding == ElfSymBinding.STB_GLOBAL ||
+ Binding == ElfSymBinding.STB_WEAK;
+
+ public int SHIdx { get; private set; }
+ public long ValueAbs { get; private set; }
+ public long Value { get; private set; }
+ public long Size { get; private set; }
+
+ public ElfSym(
+ string Name,
+ int Info,
+ int Other,
+ int SHIdx,
+ long ImageBase,
+ long Value,
+ long Size)
+ {
+ this.Name = Name;
+ this.Type = (ElfSymType)(Info & 0xf);
+ this.Binding = (ElfSymBinding)(Info >> 4);
+ this.Visibility = (ElfSymVisibility)Other;
+ this.SHIdx = SHIdx;
+ this.ValueAbs = Value + ImageBase;
+ this.Value = Value;
+ this.Size = Size;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/Loaders/ElfSymBinding.cs b/Ryujinx.Core/Loaders/ElfSymBinding.cs
new file mode 100644
index 00000000..c8789496
--- /dev/null
+++ b/Ryujinx.Core/Loaders/ElfSymBinding.cs
@@ -0,0 +1,9 @@
+namespace Ryujinx.Core.Loaders
+{
+ enum ElfSymBinding
+ {
+ STB_LOCAL = 0,
+ STB_GLOBAL = 1,
+ STB_WEAK = 2
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/Loaders/ElfSymType.cs b/Ryujinx.Core/Loaders/ElfSymType.cs
new file mode 100644
index 00000000..786395e6
--- /dev/null
+++ b/Ryujinx.Core/Loaders/ElfSymType.cs
@@ -0,0 +1,13 @@
+namespace Ryujinx.Core.Loaders
+{
+ enum ElfSymType
+ {
+ STT_NOTYPE = 0,
+ STT_OBJECT = 1,
+ STT_FUNC = 2,
+ STT_SECTION = 3,
+ STT_FILE = 4,
+ STT_COMMON = 5,
+ STT_TLS = 6
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/Loaders/ElfSymVisibility.cs b/Ryujinx.Core/Loaders/ElfSymVisibility.cs
new file mode 100644
index 00000000..e72eb5b8
--- /dev/null
+++ b/Ryujinx.Core/Loaders/ElfSymVisibility.cs
@@ -0,0 +1,10 @@
+namespace Ryujinx.Core.Loaders
+{
+ enum ElfSymVisibility
+ {
+ STV_DEFAULT = 0,
+ STV_INTERNAL = 1,
+ STV_HIDDEN = 2,
+ STV_PROTECTED = 3
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/Loaders/Executable.cs b/Ryujinx.Core/Loaders/Executable.cs
new file mode 100644
index 00000000..6a6073ef
--- /dev/null
+++ b/Ryujinx.Core/Loaders/Executable.cs
@@ -0,0 +1,149 @@
+using ChocolArm64.Memory;
+using Ryujinx.Core.Loaders.Executables;
+using Ryujinx.Core.OsHle;
+using System.Collections.Generic;
+
+namespace Ryujinx.Core.Loaders
+{
+ class Executable
+ {
+ private AMemory Memory;
+
+ private ElfDyn[] Dynamic;
+
+ public long ImageBase { get; private set; }
+ public long ImageEnd { get; private set; }
+
+ public Executable(IExecutable Exe, AMemory Memory, long ImageBase)
+ {
+ 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.Normal, AMemoryPerm.Read);
+ WriteData(ImageBase + Exe.DataOffset, Exe.Data, MemoryType.Normal, AMemoryPerm.RW);
+
+ if (Exe.Mod0Offset == 0)
+ {
+ MapBss(ImageBase + Exe.DataOffset + Exe.Data.Count, Exe.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;
+
+ List<ElfDyn> Dynamic = new List<ElfDyn>();
+
+ 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));
+ }
+
+ this.Dynamic = Dynamic.ToArray();
+ }
+
+ private void WriteData(
+ long Position,
+ IList<byte> Data,
+ MemoryType Type,
+ AMemoryPerm Perm)
+ {
+ Memory.Manager.MapPhys(Position, Data.Count, (int)Type, AMemoryPerm.Write);
+
+ for (int Index = 0; Index < Data.Count; Index++)
+ {
+ Memory.WriteByte(Position + Index, Data[Index]);
+ }
+
+ Memory.Manager.Reprotect(Position, Data.Count, Perm);
+ }
+
+ private void MapBss(long Position, long Size)
+ {
+ Memory.Manager.MapPhys(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, ImageBase, Value, Size);
+ }
+
+ private long GetFirstValue(ElfDynTag Tag)
+ {
+ foreach (ElfDyn Entry in Dynamic)
+ {
+ if (Entry.Tag == Tag)
+ {
+ return Entry.Value;
+ }
+ }
+
+ return 0;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/Loaders/Executables/IExecutable.cs b/Ryujinx.Core/Loaders/Executables/IExecutable.cs
new file mode 100644
index 00000000..73787b1d
--- /dev/null
+++ b/Ryujinx.Core/Loaders/Executables/IExecutable.cs
@@ -0,0 +1,17 @@
+using System.Collections.ObjectModel;
+
+namespace Ryujinx.Core.Loaders.Executables
+{
+ public interface IExecutable
+ {
+ ReadOnlyCollection<byte> Text { get; }
+ ReadOnlyCollection<byte> RO { get; }
+ ReadOnlyCollection<byte> Data { get; }
+
+ int Mod0Offset { get; }
+ int TextOffset { get; }
+ int ROOffset { get; }
+ int DataOffset { get; }
+ int BssSize { get; }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/Loaders/Executables/Nro.cs b/Ryujinx.Core/Loaders/Executables/Nro.cs
new file mode 100644
index 00000000..3cbc4c5d
--- /dev/null
+++ b/Ryujinx.Core/Loaders/Executables/Nro.cs
@@ -0,0 +1,62 @@
+using System;
+using System.Collections.ObjectModel;
+using System.IO;
+
+namespace Ryujinx.Core.Loaders.Executables
+{
+ class Nro : IExecutable
+ {
+ private byte[] m_Text;
+ private byte[] m_RO;
+ private byte[] m_Data;
+
+ public ReadOnlyCollection<byte> Text => Array.AsReadOnly(m_Text);
+ public ReadOnlyCollection<byte> RO => Array.AsReadOnly(m_RO);
+ public ReadOnlyCollection<byte> Data => Array.AsReadOnly(m_Data);
+
+ public int Mod0Offset { 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 Nro(Stream Input)
+ {
+ BinaryReader Reader = new BinaryReader(Input);
+
+ Input.Seek(4, SeekOrigin.Begin);
+
+ int Mod0Offset = Reader.ReadInt32();
+ int Padding8 = Reader.ReadInt32();
+ int Paddingc = Reader.ReadInt32();
+ int NroMagic = Reader.ReadInt32();
+ int Unknown14 = Reader.ReadInt32();
+ int FileSize = Reader.ReadInt32();
+ int Unknown1c = Reader.ReadInt32();
+ int TextOffset = Reader.ReadInt32();
+ int TextSize = Reader.ReadInt32();
+ int ROOffset = Reader.ReadInt32();
+ int ROSize = Reader.ReadInt32();
+ int DataOffset = Reader.ReadInt32();
+ int DataSize = Reader.ReadInt32();
+ int BssSize = Reader.ReadInt32();
+
+ this.Mod0Offset = Mod0Offset;
+ this.TextOffset = TextOffset;
+ this.ROOffset = ROOffset;
+ this.DataOffset = DataOffset;
+ this.BssSize = BssSize;
+
+ byte[] Read(long Position, int Size)
+ {
+ Input.Seek(Position, SeekOrigin.Begin);
+
+ return Reader.ReadBytes(Size);
+ }
+
+ m_Text = Read(TextOffset, TextSize);
+ m_RO = Read(ROOffset, ROSize);
+ m_Data = Read(DataOffset, DataSize);
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Core/Loaders/Executables/Nso.cs b/Ryujinx.Core/Loaders/Executables/Nso.cs
new file mode 100644
index 00000000..7b8bf253
--- /dev/null
+++ b/Ryujinx.Core/Loaders/Executables/Nso.cs
@@ -0,0 +1,122 @@
+using Ryujinx.Core.Loaders.Compression;
+using System;
+using System.Collections.ObjectModel;
+using System.IO;
+
+namespace Ryujinx.Core.Loaders.Executables
+{
+ class Nso : IExecutable
+ {
+ private byte[] m_Text;
+ private byte[] m_RO;
+ private byte[] m_Data;
+
+ public ReadOnlyCollection<byte> Text => Array.AsReadOnly(m_Text);
+ public ReadOnlyCollection<byte> RO => Array.AsReadOnly(m_RO);
+ public ReadOnlyCollection<byte> Data => Array.AsReadOnly(m_Data);
+
+ public int Mod0Offset { 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; }
+
+ [Flags]
+ private enum NsoFlags
+ {
+ IsTextCompressed = 1 << 0,
+ IsROCompressed = 1 << 1,
+ IsDataCompressed = 1 << 2,
+ HasTextHash = 1 << 3,
+ HasROHash = 1 << 4,
+ HasDataHash = 1 << 5
+ }
+
+ public Nso(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;
+
+ this.TextOffset = TextMemOffset;
+ this.ROOffset = ROMemOffset;
+ this.DataOffset = DataMemOffset;
+ this.BssSize = BssSize;
+
+ //Text segment
+ Input.Seek(TextOffset, SeekOrigin.Begin);
+
+ m_Text = Reader.ReadBytes(TextSize);
+
+ if (Flags.HasFlag(NsoFlags.IsTextCompressed) || true)
+ {
+ m_Text = Lz4.Decompress(m_Text, TextDecSize);
+ }
+
+ //Read-only data segment
+ Input.Seek(ROOffset, SeekOrigin.Begin);
+
+ m_RO = Reader.ReadBytes(ROSize);
+
+ if (Flags.HasFlag(NsoFlags.IsROCompressed) || true)
+ {
+ m_RO = Lz4.Decompress(m_RO, RODecSize);
+ }
+
+ //Data segment
+ Input.Seek(DataOffset, SeekOrigin.Begin);
+
+ m_Data = Reader.ReadBytes(DataSize);
+
+ if (Flags.HasFlag(NsoFlags.IsDataCompressed) || true)
+ {
+ m_Data = Lz4.Decompress(m_Data, DataDecSize);
+ }
+
+ using (MemoryStream Text = new MemoryStream(m_Text))
+ {
+ BinaryReader TextReader = new BinaryReader(Text);
+
+ Text.Seek(4, SeekOrigin.Begin);
+
+ Mod0Offset = TextReader.ReadInt32();
+ }
+ }
+ }
+} \ No newline at end of file