diff --git a/Ryujinx.HLE/HOS/Kernel/KMemoryManager.cs b/Ryujinx.HLE/HOS/Kernel/KMemoryManager.cs
index 3afdb57022..8871cbe7d6 100644
--- a/Ryujinx.HLE/HOS/Kernel/KMemoryManager.cs
+++ b/Ryujinx.HLE/HOS/Kernel/KMemoryManager.cs
@@ -148,6 +148,92 @@ namespace Ryujinx.HLE.HOS.Kernel
             }
         }
 
+        public long MapProcessCodeMemory(long Dst, long Src, long Size)
+        {
+            lock (Blocks)
+            {
+                long PagesCount = Size / PageSize;
+
+                bool Success = IsUnmapped(Dst, Size);
+
+                Success &= CheckRange(
+                            Src,
+                            Size,
+                            MemoryState.Mask,
+                            MemoryState.Heap,
+                            MemoryPermission.Mask,
+                            MemoryPermission.ReadAndWrite,
+                            MemoryAttribute.Mask,
+                            MemoryAttribute.None,
+                            MemoryAttribute.IpcAndDeviceMapped,
+                            out _,
+                            out _,
+                            out _);
+
+                if (Success)
+                {
+                    long PA = CpuMemory.GetPhysicalAddress(Src);
+
+                    InsertBlock(Dst, PagesCount, MemoryState.CodeStatic, MemoryPermission.ReadAndExecute);
+                    InsertBlock(Src, PagesCount, MemoryState.Heap, MemoryPermission.None);
+
+                    CpuMemory.Map(Dst, PA, Size);
+
+                    return 0;
+                }
+            }
+
+            return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
+        }
+
+        public long UnmapProcessCodeMemory(long Dst, long Src, long Size)
+        {
+            lock (Blocks)
+            {
+                long PagesCount = Size / PageSize;
+
+                bool Success = CheckRange(
+                            Dst,
+                            Size,
+                            MemoryState.Mask,
+                            MemoryState.CodeStatic,
+                            MemoryPermission.None,
+                            MemoryPermission.None,
+                            MemoryAttribute.Mask,
+                            MemoryAttribute.None,
+                            MemoryAttribute.IpcAndDeviceMapped,
+                            out _,
+                            out _,
+                            out _);
+
+                Success &= CheckRange(
+                            Src,
+                            Size,
+                            MemoryState.Mask,
+                            MemoryState.Heap,
+                            MemoryPermission.Mask,
+                            MemoryPermission.None,
+                            MemoryAttribute.Mask,
+                            MemoryAttribute.None,
+                            MemoryAttribute.IpcAndDeviceMapped,
+                            out _,
+                            out _,
+                            out _);
+
+                if (Success)
+                {
+                    InsertBlock(Dst, PagesCount, MemoryState.Unmapped);
+                    InsertBlock(Src, PagesCount, MemoryState.Heap, MemoryPermission.ReadAndWrite);
+
+                    CpuMemory.Unmap(Dst, Size);
+
+                    return 0;
+                }
+            }
+
+            return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
+        }
+
         public void HleMapCustom(long Position, long Size, MemoryState State, MemoryPermission Permission)
         {
             long PagesCount = Size / PageSize;
@@ -755,6 +841,18 @@ namespace Ryujinx.HLE.HOS.Kernel
             }
         }
 
+        public bool HleIsUnmapped(long Position, long Size)
+        {
+            bool Result = false;
+
+            lock (Blocks)
+            {
+                Result = IsUnmapped(Position, Size);
+            }
+
+            return Result;
+        }
+
         private bool IsUnmapped(long Position, long Size)
         {
             return CheckRange(
diff --git a/Ryujinx.HLE/HOS/Process.cs b/Ryujinx.HLE/HOS/Process.cs
index 3817f56195..ab0ab18ba1 100644
--- a/Ryujinx.HLE/HOS/Process.cs
+++ b/Ryujinx.HLE/HOS/Process.cs
@@ -106,13 +106,37 @@ namespace Ryujinx.HLE.HOS
                 throw new ObjectDisposedException(nameof(Process));
             }
 
-            Device.Log.PrintInfo(LogClass.Loader, $"Image base at 0x{ImageBase:x16}.");
+            long ImageEnd = LoadProgram(Program, ImageBase);
 
-            Executable Executable = new Executable(Program, MemoryManager, Memory, ImageBase);
+            ImageBase = IntUtils.AlignUp(ImageEnd, KMemoryManager.PageSize);
+        }
+
+        public long LoadProgram(IExecutable Program, long ExecutableBase)
+        {
+            if (Disposed)
+            {
+                throw new ObjectDisposedException(nameof(Process));
+            }
+
+            Device.Log.PrintInfo(LogClass.Loader, $"Image base at 0x{ExecutableBase:x16}.");
+
+            Executable Executable = new Executable(Program, MemoryManager, Memory, ExecutableBase);
 
             Executables.Add(Executable);
 
-            ImageBase = IntUtils.AlignUp(Executable.ImageEnd, KMemoryManager.PageSize);
+            return Executable.ImageEnd;
+        }
+
+        public void RemoveProgram(long ExecutableBase)
+        {
+            foreach (Executable Executable in Executables)
+            {
+                if (Executable.ImageBase == ExecutableBase)
+                {
+                    Executables.Remove(Executable);
+                    break;
+                }
+            }
         }
 
         public void SetEmptyArgs()
diff --git a/Ryujinx.HLE/HOS/Services/Ldr/IRoInterface.cs b/Ryujinx.HLE/HOS/Services/Ldr/IRoInterface.cs
new file mode 100644
index 0000000000..4d595fde27
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Ldr/IRoInterface.cs
@@ -0,0 +1,457 @@
+using Ryujinx.HLE.HOS.Ipc;
+using Ryujinx.HLE.Loaders.Executables;
+using Ryujinx.HLE.Utilities;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+
+using static Ryujinx.HLE.HOS.ErrorCode;
+
+namespace Ryujinx.HLE.HOS.Services.Ldr
+{
+    [StructLayout(LayoutKind.Explicit, Size = 0x350)]
+    unsafe struct NrrHeader
+    {
+        [FieldOffset(0)]
+        public uint  Magic;
+
+        [FieldOffset(0x10)]
+        public ulong TitleIdMask;
+
+        [FieldOffset(0x18)]
+        public ulong TitleIdPattern;
+
+        [FieldOffset(0x30)]
+        public fixed byte Modulus[0x100];
+
+        [FieldOffset(0x130)]
+        public fixed byte FixedKeySignature[0x100];
+
+        [FieldOffset(0x230)]
+        public fixed byte NrrSignature[0x100];
+
+        [FieldOffset(0x330)]
+        public ulong TitleIdMin;
+
+        [FieldOffset(0x338)]
+        public uint  NrrSize;
+
+        [FieldOffset(0x340)]
+        public uint HashOffset;
+
+        [FieldOffset(0x344)]
+        public uint HashCount;
+    }
+
+    class NrrInfo
+    {
+        public NrrHeader    Header     { get; private set; }
+        public List<byte[]> Hashes     { get; private set; }
+        public long         NrrAddress { get; private set; }
+
+        public NrrInfo(long NrrAddress, NrrHeader Header, List<byte[]> Hashes)
+        {
+            this.NrrAddress = NrrAddress;
+            this.Header     = Header;
+            this.Hashes     = Hashes;
+        }
+    }
+
+    class NroInfo
+    {
+        public Nro    Executable       { get; private set; }
+        public byte[] Hash             { get; private set; }
+        public long   NroAddress       { get; private set; }
+        public long   TotalSize        { get; private set; }
+        public long   NroMappedAddress { get; set; }
+
+        public NroInfo(Nro Executable, byte[] Hash, long TotalSize)
+        {
+            this.Executable = Executable;
+            this.Hash       = Hash;
+            this.TotalSize = TotalSize;
+        }
+    }
+
+    class IRoInterface : IpcService
+    {
+        private Dictionary<int, ServiceProcessRequest> m_Commands;
+
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+
+        private const int MaxNrr = 0x40;
+        private const int MaxNro = 0x40;
+
+        private const uint NrrMagic = 0x3052524E;
+        private const uint NroMagic = 0x304F524E;
+
+        private List<NrrInfo> NrrInfos;
+        private List<NroInfo> NroInfos;
+
+        private bool IsInitialized;
+
+        public IRoInterface()
+        {
+            m_Commands = new Dictionary<int, ServiceProcessRequest>()
+            {
+                { 0, LoadNro    },
+                { 1, UnloadNro  },
+                { 2, LoadNrr    },
+                { 3, UnloadNrr  },
+                { 4, Initialize },
+            };
+
+            NrrInfos = new List<NrrInfo>(MaxNrr);
+            NroInfos = new List<NroInfo>(MaxNro);
+        }
+
+        private long ParseNrr(out NrrInfo NrrInfo, ServiceCtx Context, long NrrAddress, long NrrSize)
+        {
+            NrrInfo = null;
+
+            if (NrrSize == 0 || NrrAddress + NrrSize <= NrrAddress || (NrrSize & 0xFFF) != 0)
+            {
+                return MakeError(ErrorModule.Loader, LoaderErr.BadSize);
+            }
+            else if ((NrrAddress & 0xFFF) != 0)
+            {
+                return MakeError(ErrorModule.Loader, LoaderErr.UnalignedAddress);
+            }
+
+            StructReader Reader = new StructReader(Context.Memory, NrrAddress);
+            NrrHeader    Header = Reader.Read<NrrHeader>();
+
+            if (Header.Magic != NrrMagic)
+            {
+                return MakeError(ErrorModule.Loader, LoaderErr.InvalidNrr);
+            }
+            else if (Header.NrrSize != NrrSize)
+            {
+                return MakeError(ErrorModule.Loader, LoaderErr.BadSize);
+            }
+
+            List<byte[]> Hashes = new List<byte[]>();
+
+            for (int i = 0; i < Header.HashCount; i++)
+            {
+                Hashes.Add(Context.Memory.ReadBytes(NrrAddress + Header.HashOffset + (i * 0x20), 0x20));
+            }
+
+            NrrInfo = new NrrInfo(NrrAddress, Header, Hashes);
+
+            return 0;
+        }
+
+        public bool IsNroHashPresent(byte[] NroHash)
+        {
+            foreach (NrrInfo Info in NrrInfos)
+            {
+                foreach (byte[] Hash in Info.Hashes)
+                {
+                    if (Hash.SequenceEqual(NroHash))
+                    {
+                        return true;
+                    }
+                }
+            }
+
+            return false;
+        }
+
+        public bool IsNroLoaded(byte[] NroHash)
+        {
+            foreach (NroInfo Info in NroInfos)
+            {
+                if (Info.Hash.SequenceEqual(NroHash))
+                {
+                    return true;
+                }
+            }
+
+            return false;
+        }
+
+        public long ParseNro(out NroInfo Res, ServiceCtx Context, long NroHeapAddress, long NroSize, long BssHeapAddress, long BssSize)
+        {
+            Res = null;
+
+            if (NroInfos.Count >= MaxNro)
+            {
+                return MakeError(ErrorModule.Loader, LoaderErr.MaxNro);
+            }
+            else if (NroSize == 0 || NroHeapAddress + NroSize <= NroHeapAddress || (NroSize & 0xFFF) != 0)
+            {
+                return MakeError(ErrorModule.Loader, LoaderErr.BadSize);
+            }
+            else if (BssSize != 0 && (BssHeapAddress + BssSize) <= BssHeapAddress)
+            {
+                return MakeError(ErrorModule.Loader, LoaderErr.BadSize);
+            }
+            else if ((NroHeapAddress & 0xFFF) != 0)
+            {
+                return MakeError(ErrorModule.Loader, LoaderErr.UnalignedAddress);
+            }
+
+            uint Magic       = Context.Memory.ReadUInt32(NroHeapAddress + 0x10);
+            uint NroFileSize = Context.Memory.ReadUInt32(NroHeapAddress + 0x18);
+
+            if (Magic != NroMagic || NroSize != NroFileSize)
+            {
+                return MakeError(ErrorModule.Loader, LoaderErr.InvalidNro);
+            }
+
+            byte[] NroData = Context.Memory.ReadBytes(NroHeapAddress, NroSize);
+            byte[] NroHash = null;
+
+            MemoryStream Stream = new MemoryStream(NroData);
+
+            using (SHA256 Hasher = SHA256.Create())
+            {
+                NroHash = Hasher.ComputeHash(Stream);
+            }
+
+            if (!IsNroHashPresent(NroHash))
+            {
+                return MakeError(ErrorModule.Loader, LoaderErr.NroHashNotPresent);
+            }
+
+            if (IsNroLoaded(NroHash))
+            {
+                return MakeError(ErrorModule.Loader, LoaderErr.NroAlreadyLoaded);
+            }
+
+            Stream.Position = 0;
+
+            Nro Executable = new Nro(Stream, "memory", NroHeapAddress, BssHeapAddress);
+
+            // check if everything is page align.
+            if ((Executable.Text.Length & 0xFFF) != 0 || (Executable.RO.Length & 0xFFF) != 0
+                || (Executable.Data.Length & 0xFFF) != 0 || (Executable.BssSize & 0xFFF) !=  0)
+            {
+                return MakeError(ErrorModule.Loader, LoaderErr.InvalidNro);
+            }
+
+            // check if everything is contiguous.
+            if (Executable.ROOffset != Executable.TextOffset + Executable.Text.Length
+                || Executable.DataOffset != Executable.ROOffset + Executable.RO.Length
+                || NroFileSize != Executable.DataOffset + Executable.Data.Length)
+            {
+                return MakeError(ErrorModule.Loader, LoaderErr.InvalidNro);
+            }
+
+            // finally check the bss size match.
+            if (Executable.BssSize != BssSize)
+            {
+                return MakeError(ErrorModule.Loader, LoaderErr.InvalidNro);
+            }
+
+            Res = new NroInfo(Executable, NroHash, Executable.Text.Length + Executable.RO.Length + Executable.Data.Length + Executable.BssSize);
+
+            return 0;
+        }
+
+        private long MapNro(ServiceCtx Context, NroInfo Info, out long NroMappedAddress)
+        {
+            NroMappedAddress = 0;
+            long TargetAddress = Context.Process.MemoryManager.AddrSpaceStart;
+
+            long HeapRegionStart = Context.Process.MemoryManager.HeapRegionStart;
+            long HeapRegionEnd   = Context.Process.MemoryManager.HeapRegionEnd;
+
+            long MapRegionStart = Context.Process.MemoryManager.MapRegionStart;
+            long MapRegionEnd   = Context.Process.MemoryManager.MapRegionEnd;
+
+            while (true)
+            {
+                if (TargetAddress + Info.TotalSize >= Context.Process.MemoryManager.AddrSpaceEnd)
+                {
+                    return MakeError(ErrorModule.Loader, LoaderErr.InvalidMemoryState);
+                }
+
+                bool IsValidAddress = !(HeapRegionStart > 0 && HeapRegionStart <= TargetAddress + Info.TotalSize - 1
+                    && TargetAddress <= HeapRegionEnd - 1)
+                    && !(MapRegionStart > 0
+                    && MapRegionStart <= TargetAddress + Info.TotalSize - 1
+                    && TargetAddress <= MapRegionEnd - 1);
+
+                if (IsValidAddress && Context.Process.MemoryManager.HleIsUnmapped(TargetAddress, Info.TotalSize))
+                {
+                    break;
+                }
+
+                TargetAddress += 0x1000;
+            }
+
+            Context.Process.LoadProgram(Info.Executable, TargetAddress);
+
+            Info.NroMappedAddress = TargetAddress;
+            NroMappedAddress      = TargetAddress;
+
+            return 0;
+        }
+
+        private long RemoveNrrInfo(long NrrAddress)
+        {
+            foreach (NrrInfo Info in NrrInfos)
+            {
+                if (Info.NrrAddress == NrrAddress)
+                {
+                    NrrInfos.Remove(Info);
+
+                    return 0;
+                }
+            }
+
+            return MakeError(ErrorModule.Loader, LoaderErr.BadNrrAddress);
+        }
+
+        private long RemoveNroInfo(ServiceCtx Context, long NroMappedAddress, long NroHeapAddress)
+        {
+            foreach (NroInfo Info in NroInfos)
+            {
+                if (Info.NroMappedAddress == NroMappedAddress && Info.Executable.SourceAddress == NroHeapAddress)
+                {
+                    NroInfos.Remove(Info);
+
+                    Context.Process.RemoveProgram(Info.NroMappedAddress);
+
+                    long Result = Context.Process.MemoryManager.UnmapProcessCodeMemory(Info.NroMappedAddress, Info.Executable.SourceAddress, Info.TotalSize - Info.Executable.BssSize);
+
+                    if (Result == 0 && Info.Executable.BssSize != 0)
+                    {
+                        Result = Context.Process.MemoryManager.UnmapProcessCodeMemory(Info.NroMappedAddress + Info.TotalSize - Info.Executable.BssSize, Info.Executable.BssAddress, Info.Executable.BssSize);
+                    }
+
+                    return Result;
+                }
+            }
+
+            return MakeError(ErrorModule.Loader, LoaderErr.BadNroAddress);
+        }
+
+        // LoadNro(u64, u64, u64, u64, u64, pid) -> u64
+        public long LoadNro(ServiceCtx Context)
+        {
+            long Result = MakeError(ErrorModule.Loader, LoaderErr.BadInitialization);
+
+            // Zero
+            Context.RequestData.ReadUInt64();
+
+            long NroHeapAddress = Context.RequestData.ReadInt64();
+            long NroSize        = Context.RequestData.ReadInt64();
+            long BssHeapAddress = Context.RequestData.ReadInt64();
+            long BssSize        = Context.RequestData.ReadInt64();
+
+            long NroMappedAddress = 0;
+
+            if (IsInitialized)
+            {
+                NroInfo Info;
+
+                Result = ParseNro(out Info, Context, NroHeapAddress, NroSize, BssHeapAddress, BssSize);
+
+                if (Result == 0)
+                {
+                    Result = MapNro(Context, Info, out NroMappedAddress);
+
+                    if (Result == 0)
+                    {
+                        NroInfos.Add(Info);
+                    }
+                }
+            }
+
+            Context.ResponseData.Write(NroMappedAddress);
+
+            return Result;
+        }
+
+        // UnloadNro(u64, u64, pid)
+        public long UnloadNro(ServiceCtx Context)
+        {
+            long Result = MakeError(ErrorModule.Loader, LoaderErr.BadInitialization);
+
+            long NroMappedAddress = Context.RequestData.ReadInt64();
+            long NroHeapAddress   = Context.RequestData.ReadInt64();
+
+            if (IsInitialized)
+            {
+                if ((NroMappedAddress & 0xFFF) != 0 || (NroHeapAddress & 0xFFF) != 0)
+                {
+                    return MakeError(ErrorModule.Loader, LoaderErr.UnalignedAddress);
+                }
+
+                Result = RemoveNroInfo(Context, NroMappedAddress, NroHeapAddress);
+            }
+
+            return Result;
+        }
+
+        // LoadNrr(u64, u64, u64, pid)
+        public long LoadNrr(ServiceCtx Context)
+        {
+            long Result = MakeError(ErrorModule.Loader, LoaderErr.BadInitialization);
+
+            // Zero
+            Context.RequestData.ReadUInt64();
+
+            long NrrAddress = Context.RequestData.ReadInt64();
+            long NrrSize    = Context.RequestData.ReadInt64();
+
+            if (IsInitialized)
+            {
+                NrrInfo Info;
+                Result = ParseNrr(out Info, Context, NrrAddress, NrrSize);
+
+                if(Result == 0)
+                {
+                    if (NrrInfos.Count >= MaxNrr)
+                    {
+                        Result = MakeError(ErrorModule.Loader, LoaderErr.MaxNrr);
+                    }
+                    else
+                    {
+                        NrrInfos.Add(Info);
+                    }
+                }
+            }
+
+            return Result;
+        }
+
+        // UnloadNrr(u64, u64, pid)
+        public long UnloadNrr(ServiceCtx Context)
+        {
+            long Result = MakeError(ErrorModule.Loader, LoaderErr.BadInitialization);
+
+            // Zero
+            Context.RequestData.ReadUInt64();
+
+            long NrrHeapAddress = Context.RequestData.ReadInt64();
+
+            if (IsInitialized)
+            {
+                if ((NrrHeapAddress & 0xFFF) != 0)
+                {
+                    return MakeError(ErrorModule.Loader, LoaderErr.UnalignedAddress);
+                }
+
+                Result = RemoveNrrInfo(NrrHeapAddress);
+            }
+
+            return Result;
+        }
+
+        // Initialize(u64, pid, KObject)
+        public long Initialize(ServiceCtx Context)
+        {
+            // TODO: we actually ignore the pid and process handle receive, we will need to use them when we will have multi process support.
+            IsInitialized = true;
+
+            return 0;
+        }
+    }
+}
diff --git a/Ryujinx.HLE/HOS/Services/Ldr/LoaderErr.cs b/Ryujinx.HLE/HOS/Services/Ldr/LoaderErr.cs
new file mode 100644
index 0000000000..ba77a5cc13
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Ldr/LoaderErr.cs
@@ -0,0 +1,18 @@
+namespace Ryujinx.HLE.HOS.Services.Ldr
+{
+    static class LoaderErr
+    {
+        public const int InvalidMemoryState = 51;
+        public const int InvalidNro         = 52;
+        public const int InvalidNrr         = 53;
+        public const int MaxNro             = 55;
+        public const int MaxNrr             = 56;
+        public const int NroAlreadyLoaded   = 57;
+        public const int NroHashNotPresent  = 54;
+        public const int UnalignedAddress   = 81;
+        public const int BadSize            = 82;
+        public const int BadNroAddress      = 84;
+        public const int BadNrrAddress      = 85;
+        public const int BadInitialization  = 87;
+    }
+}
diff --git a/Ryujinx.HLE/HOS/Services/ServiceFactory.cs b/Ryujinx.HLE/HOS/Services/ServiceFactory.cs
index fd5a06e6d9..f701dd0537 100644
--- a/Ryujinx.HLE/HOS/Services/ServiceFactory.cs
+++ b/Ryujinx.HLE/HOS/Services/ServiceFactory.cs
@@ -7,6 +7,7 @@ using Ryujinx.HLE.HOS.Services.Caps;
 using Ryujinx.HLE.HOS.Services.FspSrv;
 using Ryujinx.HLE.HOS.Services.Hid;
 using Ryujinx.HLE.HOS.Services.Irs;
+using Ryujinx.HLE.HOS.Services.Ldr;
 using Ryujinx.HLE.HOS.Services.Lm;
 using Ryujinx.HLE.HOS.Services.Mm;
 using Ryujinx.HLE.HOS.Services.Nfp;
@@ -100,6 +101,9 @@ namespace Ryujinx.HLE.HOS.Services
                 case "irs":
                     return new IIrSensorServer();
 
+                case "ldr:ro":
+                    return new IRoInterface();
+
                 case "lm":
                     return new ILogService();
 
diff --git a/Ryujinx.HLE/Loaders/Executable.cs b/Ryujinx.HLE/Loaders/Executable.cs
index a9850e4af9..3c63af141b 100644
--- a/Ryujinx.HLE/Loaders/Executable.cs
+++ b/Ryujinx.HLE/Loaders/Executable.cs
@@ -49,21 +49,49 @@ namespace Ryujinx.HLE.Loaders
             long DataPosition = ImageBase + (uint)Exe.DataOffset;
 
             long TextSize = (uint)IntUtils.AlignUp(Exe.Text.Length, KMemoryManager.PageSize);
-            long ROSize   = (uint)IntUtils.AlignUp(Exe.RO.Length,   KMemoryManager.PageSize);
+            long ROSize   = (uint)IntUtils.AlignUp(Exe.RO.Length, KMemoryManager.PageSize);
             long DataSize = (uint)IntUtils.AlignUp(Exe.Data.Length, KMemoryManager.PageSize);
+            long BssSize  = (uint)IntUtils.AlignUp(Exe.BssSize, KMemoryManager.PageSize);
 
-            long DataAndBssSize = (uint)IntUtils.AlignUp(Exe.BssSize, KMemoryManager.PageSize) + DataSize;
+            long DataAndBssSize = BssSize + DataSize;
 
             ImageEnd = DataPosition + DataAndBssSize;
 
-            MemoryManager.HleMapProcessCode(TextPosition, TextSize + ROSize + DataAndBssSize);
+            if (Exe.SourceAddress == 0)
+            {
+                MemoryManager.HleMapProcessCode(TextPosition, TextSize + ROSize + DataAndBssSize);
 
-            MemoryManager.SetProcessMemoryPermission(ROPosition,   ROSize,         MemoryPermission.Read);
-            MemoryManager.SetProcessMemoryPermission(DataPosition, DataAndBssSize, MemoryPermission.ReadAndWrite);
+                MemoryManager.SetProcessMemoryPermission(ROPosition, ROSize, MemoryPermission.Read);
+                MemoryManager.SetProcessMemoryPermission(DataPosition, DataAndBssSize, MemoryPermission.ReadAndWrite);
 
-            Memory.WriteBytes(TextPosition, Exe.Text);
-            Memory.WriteBytes(ROPosition,   Exe.RO);
-            Memory.WriteBytes(DataPosition, Exe.Data);
+                Memory.WriteBytes(TextPosition, Exe.Text);
+                Memory.WriteBytes(ROPosition, Exe.RO);
+                Memory.WriteBytes(DataPosition, Exe.Data);
+            }
+            else
+            {
+                long Result = MemoryManager.MapProcessCodeMemory(TextPosition, Exe.SourceAddress, TextSize + ROSize + DataSize);
+
+                if (Result != 0)
+                {
+                    throw new InvalidOperationException();
+                }
+
+                MemoryManager.SetProcessMemoryPermission(ROPosition, ROSize, MemoryPermission.Read);
+                MemoryManager.SetProcessMemoryPermission(DataPosition, DataSize, MemoryPermission.ReadAndWrite);
+
+                if (Exe.BssAddress != 0 && Exe.BssSize != 0)
+                {
+                    Result = MemoryManager.MapProcessCodeMemory(DataPosition + DataSize, Exe.BssAddress, BssSize);
+
+                    if (Result != 0)
+                    {
+                        throw new InvalidOperationException();
+                    }
+
+                    MemoryManager.SetProcessMemoryPermission(DataPosition + DataSize, BssSize, MemoryPermission.ReadAndWrite);
+                }
+            }
 
             if (Exe.Mod0Offset == 0)
             {
diff --git a/Ryujinx.HLE/Loaders/Executables/IExecutable.cs b/Ryujinx.HLE/Loaders/Executables/IExecutable.cs
index 44bad61497..6f0952abdb 100644
--- a/Ryujinx.HLE/Loaders/Executables/IExecutable.cs
+++ b/Ryujinx.HLE/Loaders/Executables/IExecutable.cs
@@ -8,6 +8,9 @@ namespace Ryujinx.HLE.Loaders.Executables
         byte[] RO   { get; }
         byte[] Data { get; }
 
+        long SourceAddress { get; }
+        long BssAddress    { get; }
+
         int Mod0Offset { get; }
         int TextOffset { get; }
         int ROOffset   { get; }
diff --git a/Ryujinx.HLE/Loaders/Executables/Nro.cs b/Ryujinx.HLE/Loaders/Executables/Nro.cs
index 0b5068d7b9..6015da2132 100644
--- a/Ryujinx.HLE/Loaders/Executables/Nro.cs
+++ b/Ryujinx.HLE/Loaders/Executables/Nro.cs
@@ -16,9 +16,14 @@ namespace Ryujinx.HLE.Loaders.Executables
         public int DataOffset { get; private set; }
         public int BssSize    { get; private set; }
 
-        public Nro(Stream Input, string FilePath)
+        public long SourceAddress { get; private set; }
+        public long BssAddress    { get; private set; }
+
+        public Nro(Stream Input, string FilePath, long SourceAddress = 0, long BssAddress = 0)
         {
-            this.FilePath = FilePath;
+            this.FilePath      = FilePath;
+            this.SourceAddress = SourceAddress;
+            this.BssAddress    = BssAddress;
 
             BinaryReader Reader = new BinaryReader(Input);
 
diff --git a/Ryujinx.HLE/Loaders/Executables/Nso.cs b/Ryujinx.HLE/Loaders/Executables/Nso.cs
index fef9c4b853..c7b48a5f35 100644
--- a/Ryujinx.HLE/Loaders/Executables/Nso.cs
+++ b/Ryujinx.HLE/Loaders/Executables/Nso.cs
@@ -18,6 +18,9 @@ namespace Ryujinx.HLE.Loaders.Executables
         public int DataOffset { get; private set; }
         public int BssSize    { get; private set; }
 
+        public long SourceAddress { get; private set; }
+        public long BssAddress    { get; private set; }
+
         [Flags]
         private enum NsoFlags
         {
@@ -33,6 +36,9 @@ namespace Ryujinx.HLE.Loaders.Executables
         {
             this.FilePath = FilePath;
 
+            SourceAddress = 0;
+            BssAddress    = 0;
+
             BinaryReader Reader = new BinaryReader(Input);
 
             Input.Seek(0, SeekOrigin.Begin);
diff --git a/Ryujinx.HLE/Logging/LogClass.cs b/Ryujinx.HLE/Logging/LogClass.cs
index 4905013411..0458c75f8a 100644
--- a/Ryujinx.HLE/Logging/LogClass.cs
+++ b/Ryujinx.HLE/Logging/LogClass.cs
@@ -23,6 +23,7 @@ namespace Ryujinx.HLE.Logging
         ServiceFs,
         ServiceHid,
         ServiceIrs,
+        ServiceLdr,
         ServiceLm,
         ServiceMm,
         ServiceNfp,