[nx|nstool] Encapsulated NsoHeader parsing into nx::NsoHeader

This commit is contained in:
jakcron 2018-06-01 21:35:36 +08:00
parent 3363d9152a
commit 915bd80f6f
5 changed files with 409 additions and 56 deletions

View file

@ -1,5 +1,5 @@
#pragma once
#include <nx/xci.h>
#include <nx/nso.h>
#include <fnd/MemoryBlob.h>
#include <fnd/List.h>
#include <fnd/ISerialiseableBinary.h>
@ -10,6 +10,81 @@ namespace nx
public fnd::ISerialiseableBinary
{
public:
struct sModuleId
{
byte_t data[nso::kModuleIdLen];
void operator=(const sModuleId& other)
{
memcpy(data, other.data, nso::kModuleIdLen);
}
bool operator==(const sModuleId& other) const
{
return memcmp(data, other.data, nso::kModuleIdLen) == 0;
}
bool operator!=(const sModuleId& other) const
{
return !(*this == other);
}
};
struct sLayout
{
uint32_t offset;
uint32_t size;
void operator=(const sLayout& other)
{
offset = other.offset;
size = other.size;
}
bool operator==(const sLayout& other) const
{
return (offset == other.offset) \
&& (size == other.size);
}
bool operator!=(const sLayout& other) const
{
return !(*this == other);
}
};
struct sCodeSegment
{
sLayout file_layout;
sLayout memory_layout;
bool is_compressed;
bool is_hashed;
crypto::sha::sSha256Hash hash;
void operator=(const sCodeSegment& other)
{
file_layout = other.file_layout;
memory_layout = other.memory_layout;
is_compressed = other.is_compressed;
is_hashed = other.is_hashed;
hash = other.hash;
}
bool operator==(const sCodeSegment& other) const
{
return (file_layout == other.file_layout) \
&& (memory_layout == other.memory_layout) \
&& (is_compressed == other.is_compressed) \
&& (is_hashed == other.is_hashed) \
&& (hash == other.hash);
}
bool operator!=(const sCodeSegment& other) const
{
return !(*this == other);
}
};
NsoHeader();
NsoHeader(const NsoHeader& other);
NsoHeader(const byte_t* bytes, size_t len);
@ -29,7 +104,32 @@ namespace nx
// variables
void clear();
const sModuleId& getModuleId() const;
void setModuleId(const sModuleId& id);
uint32_t getBssSize() const;
void setBssSize(uint32_t size);
const sCodeSegment& getTextSegmentInfo() const;
void setTextSegmentInfo(const sCodeSegment& info);
const sCodeSegment& getRoSegmentInfo() const;
void setRoSegmentInfo(const sCodeSegment& info);
const sCodeSegment& getDataSegmentInfo() const;
void setDataSegmentInfo(const sCodeSegment& info);
const sLayout& getModuleNameInfo() const;
void setModuleNameInfo(const sLayout& info);
const sLayout& getRoEmbeddedInfo() const;
void setRoEmbeddedInfo(const sLayout& info);
const sLayout& getRoDynStrInfo() const;
void setRoDynStrInfo(const sLayout& info);
const sLayout& getRoDynSymInfo() const;
void setRoDynSymInfo(const sLayout& info);
private:
const std::string kModuleName = "NSO_HEADER";
@ -37,6 +137,15 @@ namespace nx
fnd::MemoryBlob mBinaryBlob;
// data
sModuleId mModuleId;
uint32_t mBssSize;
sCodeSegment mTextSegmentInfo;
sCodeSegment mRoSegmentInfo;
sCodeSegment mDataSegmentInfo;
sLayout mModuleNameInfo;
sLayout mRoEmbeddedInfo;
sLayout mRoDynStrInfo;
sLayout mRoDynSymInfo;
// helpers
bool isEqual(const NsoHeader& other) const;

View file

@ -2,9 +2,7 @@
#include <string>
#include <fnd/types.h>
#include <fnd/List.h>
#include <crypto/aes.h>
#include <crypto/sha.h>
#include <crypto/rsa.h>
#include <fnd/ISerialiseableBinary.h>
namespace nx
@ -23,6 +21,7 @@ namespace nx
FLAG_DATA_HASH
};
static const uint32_t kDefaultFormatVersion = 0;
static const size_t kModuleIdLen = 32;
}
@ -43,7 +42,7 @@ namespace nx
struct sNsoHeader
{
char signature[4];
le_uint32_t version;
le_uint32_t format_version;
byte_t reserved_1[4];
le_uint32_t flags;
sNsoCodeSegment text;
@ -60,9 +59,9 @@ namespace nx
sNsoSection embedded;
sNsoSection dyn_str;
sNsoSection dyn_sym;
byte_t text_hash[crypto::sha::kSha256HashLen];
byte_t ro_hash[crypto::sha::kSha256HashLen];
byte_t data_hash[crypto::sha::kSha256HashLen];
crypto::sha::sSha256Hash text_hash;
crypto::sha::sSha256Hash ro_hash;
crypto::sha::sSha256Hash data_hash;
};
#pragma pack(pop)

View file

@ -42,24 +42,282 @@ size_t nx::NsoHeader::getSize() const
void nx::NsoHeader::exportBinary()
{
throw fnd::Exception(kModuleName, "exportBinary() not implemented");
mBinaryBlob.alloc(sizeof(sNsoHeader));
nx::sNsoHeader* hdr = (nx::sNsoHeader*)mBinaryBlob.getBytes();
// set header identifers
memcpy(hdr->signature, nso::kNsoSig.c_str(), 4);
hdr->format_version = nso::kDefaultFormatVersion;
// variable to store flags before commiting to header
uint32_t flags = 0;
// set moduleid
memcpy(hdr->module_id, mModuleId.data, nso::kModuleIdLen);
// set bss size
hdr->bss_size = mBssSize;
// set text segment
hdr->text.file_offset = mTextSegmentInfo.file_layout.offset;
hdr->text.memory_offset = mTextSegmentInfo.memory_layout.offset;
hdr->text.size = mTextSegmentInfo.memory_layout.size;
hdr->text_file_size = mTextSegmentInfo.file_layout.size;
if (mTextSegmentInfo.is_compressed)
{
flags |= _BIT(nso::FLAG_TEXT_COMPRESS);
}
if (mTextSegmentInfo.is_hashed)
{
flags |= _BIT(nso::FLAG_TEXT_HASH);
hdr->text_hash = mTextSegmentInfo.hash;
}
// set ro segment
hdr->ro.file_offset = mRoSegmentInfo.file_layout.offset;
hdr->ro.memory_offset = mRoSegmentInfo.memory_layout.offset;
hdr->ro.size = mRoSegmentInfo.memory_layout.size;
hdr->ro_file_size = mRoSegmentInfo.file_layout.size;
if (mRoSegmentInfo.is_compressed)
{
flags |= _BIT(nso::FLAG_RO_COMPRESS);
}
if (mRoSegmentInfo.is_hashed)
{
flags |= _BIT(nso::FLAG_RO_HASH);
hdr->ro_hash = mRoSegmentInfo.hash;
}
// set data segment
hdr->data.file_offset = mDataSegmentInfo.file_layout.offset;
hdr->data.memory_offset = mDataSegmentInfo.memory_layout.offset;
hdr->data.size = mDataSegmentInfo.memory_layout.size;
hdr->data_file_size = mDataSegmentInfo.file_layout.size;
if (mDataSegmentInfo.is_compressed)
{
flags |= _BIT(nso::FLAG_DATA_COMPRESS);
}
if (mDataSegmentInfo.is_hashed)
{
flags |= _BIT(nso::FLAG_DATA_HASH);
hdr->data_hash = mDataSegmentInfo.hash;
}
// set module name info
hdr->module_name_offset = mModuleNameInfo.offset;
hdr->module_name_size = mModuleNameInfo.size;
// set ro embedded info
hdr->embedded.offset = mRoEmbeddedInfo.offset;
hdr->embedded.size = mRoEmbeddedInfo.size;
// set ro dyn str info
hdr->dyn_str.offset = mRoDynStrInfo.offset;
hdr->dyn_str.size = mRoDynStrInfo.size;
// set ro dyn sym info
hdr->dyn_sym.offset = mRoDynSymInfo.offset;
hdr->dyn_sym.size = mRoDynSymInfo.size;
hdr->flags = flags;
}
void nx::NsoHeader::importBinary(const byte_t* bytes, size_t len)
{
throw fnd::Exception(kModuleName, "importBinary() not implemented");
// check input data size
if (len < sizeof(sNsoHeader))
{
throw fnd::Exception(kModuleName, "NSO header size is too small");
}
// clear internal members
clear();
// allocate internal local binary copy
mBinaryBlob.alloc(sizeof(sNsoHeader));
memcpy(mBinaryBlob.getBytes(), bytes, mBinaryBlob.getSize());
// get sNsoHeader ptr
const nx::sNsoHeader* hdr = (const nx::sNsoHeader*)mBinaryBlob.getBytes();
// check NSO signature
if (std::string(hdr->signature, 4) != nso::kNsoSig)
{
throw fnd::Exception(kModuleName, "NSO header corrupt (unrecognised header signature)");
}
// check NSO format version
if (hdr->format_version.get() != nso::kDefaultFormatVersion)
{
throw fnd::Exception(kModuleName, "NSO header corrupt (unsupported format version)");
}
memcpy(mModuleId.data, hdr->module_id, nso::kModuleIdLen);
mBssSize = hdr->bss_size.get();
mTextSegmentInfo.file_layout.offset = hdr->text.file_offset.get();
mTextSegmentInfo.file_layout.size = hdr->text_file_size.get();
mTextSegmentInfo.memory_layout.offset = hdr->text.memory_offset.get();
mTextSegmentInfo.memory_layout.size = hdr->text.size.get();
mTextSegmentInfo.is_compressed = _HAS_BIT(hdr->flags.get(), nso::FLAG_TEXT_COMPRESS);
mTextSegmentInfo.is_hashed = _HAS_BIT(hdr->flags.get(), nso::FLAG_TEXT_HASH);
mTextSegmentInfo.hash = hdr->text_hash;
mRoSegmentInfo.file_layout.offset = hdr->ro.file_offset.get();
mRoSegmentInfo.file_layout.size = hdr->ro_file_size.get();
mRoSegmentInfo.memory_layout.offset = hdr->ro.memory_offset.get();
mRoSegmentInfo.memory_layout.size = hdr->ro.size.get();
mRoSegmentInfo.is_compressed = _HAS_BIT(hdr->flags.get(), nso::FLAG_RO_COMPRESS);
mRoSegmentInfo.is_hashed = _HAS_BIT(hdr->flags.get(), nso::FLAG_RO_HASH);
mRoSegmentInfo.hash = hdr->ro_hash;
mDataSegmentInfo.file_layout.offset = hdr->data.file_offset.get();
mDataSegmentInfo.file_layout.size = hdr->data_file_size.get();
mDataSegmentInfo.memory_layout.offset = hdr->data.memory_offset.get();
mDataSegmentInfo.memory_layout.size = hdr->data.size.get();
mDataSegmentInfo.is_compressed = _HAS_BIT(hdr->flags.get(), nso::FLAG_RO_COMPRESS);
mDataSegmentInfo.is_hashed = _HAS_BIT(hdr->flags.get(), nso::FLAG_RO_HASH);
mDataSegmentInfo.hash = hdr->data_hash;
mModuleNameInfo.offset = hdr->module_name_offset.get();
mModuleNameInfo.size = hdr->module_name_size.get();
mRoEmbeddedInfo.offset = hdr->embedded.offset.get();
mRoEmbeddedInfo.size = hdr->embedded.size.get();
mRoDynStrInfo.offset = hdr->dyn_str.offset.get();
mRoDynStrInfo.size = hdr->dyn_str.size.get();
mRoDynSymInfo.offset = hdr->dyn_sym.offset.get();
mRoDynSymInfo.size = hdr->dyn_sym.size.get();
}
void nx::NsoHeader::clear()
{
mBinaryBlob.clear();
memset(&mModuleId, 0, sizeof(mModuleId));
mBssSize = 0;
memset(&mTextSegmentInfo, 0, sizeof(mTextSegmentInfo));
memset(&mRoSegmentInfo, 0, sizeof(mRoSegmentInfo));
memset(&mDataSegmentInfo, 0, sizeof(mDataSegmentInfo));
memset(&mModuleNameInfo, 0, sizeof(mModuleNameInfo));
memset(&mRoEmbeddedInfo, 0, sizeof(mRoEmbeddedInfo));
memset(&mRoDynStrInfo, 0, sizeof(mRoDynStrInfo));
memset(&mRoDynSymInfo, 0, sizeof(mRoDynSymInfo));
}
const nx::NsoHeader::sModuleId& nx::NsoHeader::getModuleId() const
{
return mModuleId;
}
void nx::NsoHeader::setModuleId(const sModuleId& id)
{
mModuleId = id;
}
uint32_t nx::NsoHeader::getBssSize() const
{
return mBssSize;
}
void nx::NsoHeader::setBssSize(uint32_t size)
{
mBssSize = size;
}
const nx::NsoHeader::sCodeSegment& nx::NsoHeader::getTextSegmentInfo() const
{
return mTextSegmentInfo;
}
void nx::NsoHeader::setTextSegmentInfo(const sCodeSegment& info)
{
mTextSegmentInfo = info;
}
const nx::NsoHeader::sCodeSegment& nx::NsoHeader::getRoSegmentInfo() const
{
return mRoSegmentInfo;
}
void nx::NsoHeader::setRoSegmentInfo(const sCodeSegment& info)
{
mRoSegmentInfo = info;
}
const nx::NsoHeader::sCodeSegment& nx::NsoHeader::getDataSegmentInfo() const
{
return mDataSegmentInfo;
}
void nx::NsoHeader::setDataSegmentInfo(const sCodeSegment& info)
{
mDataSegmentInfo = info;
}
const nx::NsoHeader::sLayout& nx::NsoHeader::getModuleNameInfo() const
{
return mModuleNameInfo;
}
void nx::NsoHeader::setModuleNameInfo(const sLayout& info)
{
mModuleNameInfo = info;
}
const nx::NsoHeader::sLayout& nx::NsoHeader::getRoEmbeddedInfo() const
{
return mRoEmbeddedInfo;
}
void nx::NsoHeader::setRoEmbeddedInfo(const sLayout& info)
{
mRoEmbeddedInfo = info;
}
const nx::NsoHeader::sLayout& nx::NsoHeader::getRoDynStrInfo() const
{
return mRoDynStrInfo;
}
void nx::NsoHeader::setRoDynStrInfo(const sLayout& info)
{
mRoDynStrInfo = info;
}
const nx::NsoHeader::sLayout& nx::NsoHeader::getRoDynSymInfo() const
{
return mRoDynSymInfo;
}
void nx::NsoHeader::setRoDynSymInfo(const sLayout& info)
{
mRoDynSymInfo = info;
}
bool nx::NsoHeader::isEqual(const NsoHeader& other) const
{
return false;
return (mModuleId == other.mModuleId) \
&& (mBssSize == other.mBssSize) \
&& (mTextSegmentInfo == other.mTextSegmentInfo) \
&& (mRoSegmentInfo == other.mRoSegmentInfo) \
&& (mDataSegmentInfo == other.mDataSegmentInfo) \
&& (mModuleNameInfo == other.mModuleNameInfo) \
&& (mRoEmbeddedInfo == other.mRoEmbeddedInfo) \
&& (mRoDynStrInfo == other.mRoDynStrInfo) \
&& (mRoDynSymInfo == other.mRoDynSymInfo);
}
void nx::NsoHeader::copyFrom(const NsoHeader& other)
{
mModuleId = other.mModuleId;
mBssSize = other.mBssSize;
mTextSegmentInfo = other.mTextSegmentInfo;
mRoSegmentInfo = other.mRoSegmentInfo;
mDataSegmentInfo = other.mDataSegmentInfo;
mModuleNameInfo = other.mModuleNameInfo;
mRoEmbeddedInfo = other.mRoEmbeddedInfo;
mRoDynStrInfo = other.mRoDynStrInfo;
mRoDynSymInfo = other.mRoDynSymInfo;
}

View file

@ -41,11 +41,7 @@ void NsoProcess::process()
scratch.alloc(sizeof(nx::sNsoHeader));
mReader->read(scratch.getBytes(), 0, scratch.getSize());
memcpy(&mNso, scratch.getBytes(), sizeof(nx::sNsoHeader));
if (std::string(mNso.signature, 4) != nx::nso::kNsoSig)
{
throw fnd::Exception(kModuleName, "Corrupt NSO header");
}
mHdr.importBinary(scratch.getBytes(), scratch.getSize());
if (mCliOutputType >= OUTPUT_NORMAL)
{
@ -73,70 +69,61 @@ void NsoProcess::displayHeader()
#define _HEXDUMP_L(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) printf("%02x", var[a__a__A]); } while(0)
printf("[NSO Header]\n");
printf(" Format Version: %" PRId32 "\n", mNso.version.get());
printf(" Flags: 0x%" PRIx32 "\n", mNso.flags.get());
printf(" ModuleId: ");
_HEXDUMP_L(mNso.module_id, 32);
_HEXDUMP_L(mHdr.getModuleId().data, nx::nso::kModuleIdLen);
printf("\n");
printf(" Program Segments:\n");
printf(" .module_id:\n");
printf(" FileOffset: 0x%" PRIx32 "\n", mNso.module_name_offset.get());
printf(" FileSize: 0x%" PRIx32 "\n", mNso.module_name_size.get());
printf(" FileOffset: 0x%" PRIx32 "\n", mHdr.getModuleNameInfo().offset);
printf(" FileSize: 0x%" PRIx32 "\n", mHdr.getModuleNameInfo().size);
printf(" .text:\n");
printf(" FileOffset: 0x%" PRIx32 "\n", mNso.text.file_offset.get());
printf(" FileSize: 0x%" PRIx32 "%s\n", mNso.text_file_size.get(), _HAS_BIT(mNso.flags.get(), nx::nso::FLAG_TEXT_COMPRESS)? " (COMPRESSED)" : "");
//printf(" Compressed: %s\n", getBoolStr(_HAS_BIT(mNso.flags.get(), nx::nso::FLAG_TEXT_COMPRESS)));
printf(" FileOffset: 0x%" PRIx32 "\n", mHdr.getTextSegmentInfo().file_layout.offset);
printf(" FileSize: 0x%" PRIx32 "%s\n", mHdr.getTextSegmentInfo().file_layout.size, mHdr.getTextSegmentInfo().is_compressed? " (COMPRESSED)" : "");
printf(" .ro:\n");
printf(" FileOffset: 0x%" PRIx32 "\n", mNso.ro.file_offset.get());
printf(" FileSize: 0x%" PRIx32 "%s\n", mNso.ro_file_size.get(), _HAS_BIT(mNso.flags.get(), nx::nso::FLAG_RO_COMPRESS)? " (COMPRESSED)" : "");
//printf(" Compressed: %s\n", getBoolStr(_HAS_BIT(mNso.flags.get(), nx::nso::FLAG_RO_COMPRESS)));
printf(" FileOffset: 0x%" PRIx32 "\n", mHdr.getRoSegmentInfo().file_layout.offset);
printf(" FileSize: 0x%" PRIx32 "%s\n", mHdr.getRoSegmentInfo().file_layout.size, mHdr.getRoSegmentInfo().is_compressed? " (COMPRESSED)" : "");
printf(" .data:\n");
printf(" FileOffset: 0x%" PRIx32 "\n", mNso.data.file_offset.get());
printf(" FileSize: 0x%" PRIx32 "%s\n", mNso.data_file_size.get(), _HAS_BIT(mNso.flags.get(), nx::nso::FLAG_DATA_COMPRESS)? " (COMPRESSED)" : "");
//printf(" Compressed: %s\n", getBoolStr(_HAS_BIT(mNso.flags.get(), nx::nso::FLAG_DATA_COMPRESS)));
printf(" FileOffset: 0x%" PRIx32 "\n", mHdr.getDataSegmentInfo().file_layout.offset);
printf(" FileSize: 0x%" PRIx32 "%s\n", mHdr.getDataSegmentInfo().file_layout.size, mHdr.getDataSegmentInfo().is_compressed? " (COMPRESSED)" : "");
printf(" Program Sections:\n");
printf(" .text:\n");
printf(" MemoryOffset: 0x%" PRIx32 "\n", mNso.text.memory_offset.get());
printf(" MemorySize: 0x%" PRIx32 "\n", mNso.text.size.get());
//printf(" Hashed: %s\n", getBoolStr(_HAS_BIT(mNso.flags.get(), nx::nso::FLAG_TEXT_HASH)));
if (_HAS_BIT(mNso.flags.get(), nx::nso::FLAG_TEXT_HASH))
printf(" MemoryOffset: 0x%" PRIx32 "\n", mHdr.getTextSegmentInfo().memory_layout.offset);
printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getTextSegmentInfo().memory_layout.size);
if (mHdr.getTextSegmentInfo().is_hashed)
{
printf(" Hash: ");
_HEXDUMP_L(mNso.text_hash, 32);
_HEXDUMP_L(mHdr.getTextSegmentInfo().hash.bytes, 32);
printf("\n");
}
printf(" .ro:\n");
printf(" MemoryOffset: 0x%" PRIx32 "\n", mNso.ro.memory_offset.get());
printf(" MemorySize: 0x%" PRIx32 "\n", mNso.ro.size.get());
//printf(" Hashed: %s\n", getBoolStr(_HAS_BIT(mNso.flags.get(), nx::nso::FLAG_RO_HASH)));
if (_HAS_BIT(mNso.flags.get(), nx::nso::FLAG_RO_HASH))
printf(" MemoryOffset: 0x%" PRIx32 "\n", mHdr.getRoSegmentInfo().memory_layout.offset);
printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getRoSegmentInfo().memory_layout.size);
if (mHdr.getRoSegmentInfo().is_hashed)
{
printf(" Hash: ");
_HEXDUMP_L(mNso.ro_hash, 32);
_HEXDUMP_L(mHdr.getRoSegmentInfo().hash.bytes, 32);
printf("\n");
}
printf(" .api_info:\n");
printf(" MemoryOffset: 0x%" PRIx32 "\n", mNso.ro.memory_offset.get() + mNso.embedded.offset.get());
printf(" MemorySize: 0x%" PRIx32 "\n", mNso.embedded.size.get());
printf(" MemoryOffset: 0x%" PRIx32 "\n", mHdr.getRoSegmentInfo().memory_layout.offset + mHdr.getRoEmbeddedInfo().offset);
printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getRoEmbeddedInfo().size);
printf(" .dynstr:\n");
printf(" MemoryOffset: 0x%" PRIx32 "\n", mNso.ro.memory_offset.get() + mNso.dyn_str.offset.get());
printf(" MemorySize: 0x%" PRIx32 "\n", mNso.dyn_str.size.get());
printf(" MemoryOffset: 0x%" PRIx32 "\n", mHdr.getRoSegmentInfo().memory_layout.offset + mHdr.getRoDynStrInfo().offset);
printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getRoDynStrInfo().size);
printf(" .dynsym:\n");
printf(" MemoryOffset: 0x%" PRIx32 "\n", mNso.ro.memory_offset.get() + mNso.dyn_sym.offset.get());
printf(" MemorySize: 0x%" PRIx32 "\n", mNso.dyn_sym.size.get());
printf(" MemoryOffset: 0x%" PRIx32 "\n", mHdr.getRoSegmentInfo().memory_layout.offset + mHdr.getRoDynSymInfo().offset);
printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getRoDynSymInfo().size);
printf(" .data:\n");
printf(" MemoryOffset: 0x%" PRIx32 "\n", mNso.data.memory_offset.get());
printf(" MemorySize: 0x%" PRIx32 "\n", mNso.data.size.get());
//printf(" Hashed: %s\n", getBoolStr(_HAS_BIT(mNso.flags.get(), nx::nso::FLAG_DATA_HASH)));
if (_HAS_BIT(mNso.flags.get(), nx::nso::FLAG_DATA_HASH))
printf(" MemoryOffset: 0x%" PRIx32 "\n", mHdr.getDataSegmentInfo().memory_layout.offset);
printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getDataSegmentInfo().memory_layout.size);
if (mHdr.getDataSegmentInfo().is_hashed)
{
printf(" Hash: ");
_HEXDUMP_L(mNso.data_hash, 32);
_HEXDUMP_L(mHdr.getDataSegmentInfo().hash.bytes, 32);
printf("\n");
}
printf(" .bss:\n");
printf(" MemorySize: 0x%" PRIx32 "\n", mNso.bss_size.get());
printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getBssSize());
#undef _HEXDUMP_L
}
}

View file

@ -2,7 +2,7 @@
#include <string>
#include <fnd/types.h>
#include <fnd/IFile.h>
#include <nx/nso.h>
#include <nx/NsoHeader.h>
#include "nstool.h"
@ -26,7 +26,7 @@ private:
CliOutputType mCliOutputType;
bool mVerify;
nx::sNsoHeader mNso;
nx::NsoHeader mHdr;
void displayHeader();
};