mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-27 15:35:29 +03:00
Implement NRO loader
This commit is contained in:
parent
428b4ce868
commit
1142e397c6
@ -6,5 +6,10 @@ set(source_DIR ${CMAKE_SOURCE_DIR}/src/main/cpp)
|
||||
|
||||
include_directories(${source_DIR}/include)
|
||||
|
||||
add_library(lightswitch SHARED ${source_DIR}/lightswitch.cpp ${source_DIR}/core/arm/cpu.cpp)
|
||||
add_library(lightswitch SHARED
|
||||
${source_DIR}/lightswitch.cpp
|
||||
${source_DIR}/core/arm/cpu.cpp
|
||||
|
||||
${source_DIR}/core/hos/loaders/nro.cpp
|
||||
)
|
||||
target_link_libraries(lightswitch ${source_DIR}/lib/${ANDROID_ABI}/libunicorn.a)
|
64
app/src/main/cpp/core/hos/loaders/nro.cpp
Normal file
64
app/src/main/cpp/core/hos/loaders/nro.cpp
Normal file
@ -0,0 +1,64 @@
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <syslog.h>
|
||||
#include <sys/mman.h>
|
||||
#include <vector>
|
||||
#include "nro.h"
|
||||
|
||||
// TODO: Move memory to it's own file
|
||||
#define MEM_BASE 0x80000000
|
||||
|
||||
void ReadDataFromFile(std::string file, char* output, uint32_t offset, size_t size)
|
||||
{
|
||||
std::ifstream f(file, std::ios::binary | std::ios::beg);
|
||||
|
||||
f.seekg(offset);
|
||||
f.read(output, size);
|
||||
|
||||
f.close();
|
||||
}
|
||||
|
||||
namespace loader {
|
||||
bool LoadNro(std::string file) {
|
||||
syslog(LOG_INFO, "Loading NRO file %s\n", file.c_str());
|
||||
|
||||
NroHeader h;
|
||||
ReadDataFromFile(file, reinterpret_cast<char *>(&h), 0x0, sizeof(NroHeader));
|
||||
if (h.magic != 0x304F524E) {
|
||||
syslog(LOG_ERR, "Invalid NRO magic 0x%x\n", h.magic);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<uint32_t> text, ro, data;
|
||||
text.resize(h.segments[0].size);
|
||||
ro.resize(h.segments[1].size);
|
||||
data.resize(h.segments[2].size);
|
||||
|
||||
ReadDataFromFile(file, reinterpret_cast<char *>(text.data()),
|
||||
h.segments[0].fileOffset, h.segments[0].size);
|
||||
ReadDataFromFile(file, reinterpret_cast<char *>(ro.data()),
|
||||
h.segments[1].fileOffset, h.segments[1].size);
|
||||
ReadDataFromFile(file, reinterpret_cast<char *>(data.data()),
|
||||
h.segments[2].fileOffset, h.segments[2].size);
|
||||
|
||||
|
||||
if(!mmap((void*)(MEM_BASE),
|
||||
h.segments[0].size, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, 0, 0) ||
|
||||
!mmap((void*)(MEM_BASE + h.segments[0].size),
|
||||
h.segments[1].size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, 0, 0) ||
|
||||
!mmap((void*)(MEM_BASE + h.segments[0].size + h.segments[1].size),
|
||||
h.segments[2].size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, 0, 0) ||
|
||||
!mmap((void*)(MEM_BASE + h.segments[0].size + h.segments[1].size + h.segments[2].size),
|
||||
h.bssSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, 0, 0)) {
|
||||
|
||||
syslog(LOG_ERR, "Failed mapping regions for executable");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::memcpy((void*)(MEM_BASE), text.data(), text.size());
|
||||
std::memcpy((void*)(MEM_BASE + h.segments[0].size), ro.data(), ro.size());
|
||||
std::memcpy((void*)(MEM_BASE + h.segments[0].size + h.segments[1].size), data.data(), data.size());
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
31
app/src/main/cpp/core/hos/loaders/nro.h
Normal file
31
app/src/main/cpp/core/hos/loaders/nro.h
Normal file
@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
namespace loader {
|
||||
struct NroSegmentHeader {
|
||||
uint32_t fileOffset;
|
||||
uint32_t size;
|
||||
};
|
||||
|
||||
struct NroHeader {
|
||||
uint32_t unused;
|
||||
uint32_t modOffset;
|
||||
uint64_t padding;
|
||||
|
||||
uint32_t magic;
|
||||
uint32_t version;
|
||||
uint32_t size;
|
||||
uint32_t flags;
|
||||
|
||||
NroSegmentHeader segments[3];
|
||||
|
||||
uint32_t bssSize;
|
||||
uint32_t reserved0;
|
||||
uint64_t buildId[4];
|
||||
uint64_t reserved1;
|
||||
|
||||
NroSegmentHeader extraSegments[3];
|
||||
};
|
||||
|
||||
bool LoadNro(std::string file);
|
||||
}
|
Loading…
Reference in New Issue
Block a user