NSO: Difference between revisions
| No edit summary | No edit summary | ||
| (33 intermediate revisions by 10 users not shown) | |||
| Line 1: | Line 1: | ||
| NSO is the main executable format. | NSO is the main executable format. | ||
| It starts with a  | It starts with the "NSO" header and mainly describes .text, .rodata, and .data segments (like a short-form of ELF program headers). If the segments are compressed, they are compressed using LZ4. | ||
| = NsoHeader = | |||
| {| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
| |- | |- | ||
| Line 10: | Line 12: | ||
| | 0x0 | | 0x0 | ||
| | 4 | | 4 | ||
| |  | | Signature ("NSO0") | ||
| |- | |- | ||
| | 0x4 | | 0x4 | ||
| | 4 | | 4 | ||
| |   | | Version | ||
| |- | |- | ||
| | 0x8 | | 0x8 | ||
| | 4 | | 4 | ||
| |   | | Reserved | ||
| |- | |- | ||
| | 0xC | | 0xC | ||
| | 4 | | 4 | ||
| |   | | [[#Flags|Flags]] | ||
| |- | |- | ||
| | 0x10 | | 0x10 | ||
| |  | | 0x4 | ||
| |   | | TextFileOffset | ||
| |- | |- | ||
| | 0x14 | | 0x14 | ||
| |  | | 0x4 | ||
| | | | TextMemoryOffset | ||
| |- | |- | ||
| | 0x18 | | 0x18 | ||
| |  | | 0x4 | ||
| |  | | TextSize | ||
| |- | |- | ||
| | 0x1C | | 0x1C | ||
| |  | | 0x4  | ||
| |  | | ModuleNameOffset (calculated by sizeof(header)) | ||
| |- | |- | ||
| | 0x20 | | 0x20 | ||
| |  | | 0x4 | ||
| |   | | RoFileOffset | ||
| |- | |- | ||
| | 0x24 | | 0x24 | ||
| |  | | 0x4 | ||
| |  | | RoMemoryOffset | ||
| |- | |- | ||
| | 0x28 | | 0x28 | ||
| |  | | 0x4 | ||
| |  | | RoSize | ||
| |- | |- | ||
| | 0x2C | | 0x2C | ||
| |  | | 0x4 | ||
| |  | | ModuleNameSize | ||
| |- | |- | ||
| | 0x30 | | 0x30 | ||
| |  | | 0x4 | ||
| |   | | DataFileOffset | ||
| |- | |- | ||
| | 0x34 | | 0x34 | ||
| |  | | 0x4 | ||
| |  | | DataMemoryOffset | ||
| |- | |- | ||
| | 0x38 | | 0x38 | ||
| |  | | 0x4 | ||
| | | | DataSize | ||
| |- | |||
| | 0x3C | |||
| | 0x4 | |||
| | BssSize | |||
| |- | |||
| | 0x40 | |||
| | 0x20 | |||
| | [[#ModuleId|ModuleId]] | |||
| |- | |||
| | 0x60 | |||
| | 0x4 | |||
| | TextFileSize (.text compressed size) | |||
| |- | |||
| | 0x64 | |||
| | 0x4 | |||
| | RoFileSize (.rodata compressed size) | |||
| |- | |||
| | 0x68 | |||
| | 0x4 | |||
| | DataFileSize (.data compressed size) | |||
| |- | |||
| | 0x6C | |||
| | 0x1C | |||
| | Reserved | |||
| |- | |||
| | 0x88 | |||
| | 0x4 | |||
| | EmbeddedOffset (relative to the .rodata section) | |||
| |- | |||
| | 0x8C | |||
| | 0x4 | |||
| | EmbeddedSize | |||
| |- | |||
| | 0x90 | |||
| | 0x4 | |||
| | DynStrOffset (relative to the .rodata section) | |||
| |- | |||
| | 0x94 | |||
| | 0x4 | |||
| | DynStrSize | |||
| |- | |||
| | 0x98 | |||
| | 0x4 | |||
| | DynSymOffset (relative to the .rodata section) | |||
| |- | |||
| | 0x9C | |||
| | 0x4 | |||
| | DynSymSize | |||
| |- | |- | ||
| | 0xA0 | | 0xA0 | ||
| |  | | 0x20 | ||
| |  | | TextHash (SHA-256 hash over the decompressed .text section using the above size) | ||
| |- | |||
| | 0xC0 | |||
| | 0x20 | |||
| | RoHash (SHA-256 hash over the decompressed .rodata section using the above size) | |||
| |- | |||
| | 0xE0 | |||
| | 0x20 | |||
| | DataHash (SHA-256 hash over the decompressed .data section using the above size) | |||
| |- | |- | ||
| | 0x100 | | 0x100 | ||
| | | | Variable | ||
| | Compressed sections | | Compressed sections | ||
| |} | |} | ||
| == Flags == | |||
| {| class="wikitable" border="1" | |||
| |- | |||
| ! Bits | |||
| ! Description | |||
| |- | |||
| | 0 | |||
| | TextCompress (.text section is compressed) | |||
| |- | |||
| | 1 | |||
| | RoCompress (.rodata section is compressed) | |||
| |- | |||
| | 2 | |||
| | DataCompress (.data section is compressed) | |||
| |- | |||
| | 3 | |||
| | TextHash (.text hash must be checked when loading) | |||
| |- | |||
| | 4 | |||
| | RoHash (.rodata hash must be checked when loading) | |||
| |- | |||
| | 5 | |||
| | DataHash (.data hash must be checked when loading) | |||
| |} | |||
| == ModuleId == | |||
| This is "nn::ro::detail::ModuleId". | |||
| Value of "build id" from ELF's GNU .note section. Contains variable sized digest, up to 32bytes. | |||
| = Arguments = | |||
| [[Loader_services|Loader]] maps memory and writes the [[Loader_services#SetProgramArgument|arguments]] to {end of rwdata section}. Official processes use argdata_addr = {page-aligned _end}. svcQueryMemory is used by official sw to verify that argdata_addr is mapped RW, since this memory is only mapped when arguments are specified via that command. Afterwards, official sw aligns the argdata_addr to 4-bytes. | |||
| The structure located at argdata_addr is as follows: | |||
| {| class="wikitable" border="1" | |||
| |- | |||
| ! Offset | |||
| ! Size | |||
| ! Description | |||
| |- | |||
| | 0x0 || 0x4 || This is the total allocated space relative to argdata_addr, used for calculating the max size of the argv ptr array. Normally 0x9000? | |||
| |- | |||
| | 0x4 || 0x4 || This is the total_bytesize of the actual argdata string. | |||
| |- | |||
| | 0x8 || 0x18 || Unused by official sw. | |||
| |- | |||
| | 0x20 || See above || Actual argdata string. | |||
| |} | |||
| * The copy of the args used with the argv array is written by official processes to actual_argdata_string+actual_argdata_size. | |||
| * argv_ptrarray written by official processes is at (args_copy+actual_argdata_size) + 0x9 & ~0x7. | |||
Revision as of 22:29, 25 September 2024
NSO is the main executable format.
It starts with the "NSO" header and mainly describes .text, .rodata, and .data segments (like a short-form of ELF program headers). If the segments are compressed, they are compressed using LZ4.
NsoHeader
| Offset | Size | Description | 
|---|---|---|
| 0x0 | 4 | Signature ("NSO0") | 
| 0x4 | 4 | Version | 
| 0x8 | 4 | Reserved | 
| 0xC | 4 | Flags | 
| 0x10 | 0x4 | TextFileOffset | 
| 0x14 | 0x4 | TextMemoryOffset | 
| 0x18 | 0x4 | TextSize | 
| 0x1C | 0x4 | ModuleNameOffset (calculated by sizeof(header)) | 
| 0x20 | 0x4 | RoFileOffset | 
| 0x24 | 0x4 | RoMemoryOffset | 
| 0x28 | 0x4 | RoSize | 
| 0x2C | 0x4 | ModuleNameSize | 
| 0x30 | 0x4 | DataFileOffset | 
| 0x34 | 0x4 | DataMemoryOffset | 
| 0x38 | 0x4 | DataSize | 
| 0x3C | 0x4 | BssSize | 
| 0x40 | 0x20 | ModuleId | 
| 0x60 | 0x4 | TextFileSize (.text compressed size) | 
| 0x64 | 0x4 | RoFileSize (.rodata compressed size) | 
| 0x68 | 0x4 | DataFileSize (.data compressed size) | 
| 0x6C | 0x1C | Reserved | 
| 0x88 | 0x4 | EmbeddedOffset (relative to the .rodata section) | 
| 0x8C | 0x4 | EmbeddedSize | 
| 0x90 | 0x4 | DynStrOffset (relative to the .rodata section) | 
| 0x94 | 0x4 | DynStrSize | 
| 0x98 | 0x4 | DynSymOffset (relative to the .rodata section) | 
| 0x9C | 0x4 | DynSymSize | 
| 0xA0 | 0x20 | TextHash (SHA-256 hash over the decompressed .text section using the above size) | 
| 0xC0 | 0x20 | RoHash (SHA-256 hash over the decompressed .rodata section using the above size) | 
| 0xE0 | 0x20 | DataHash (SHA-256 hash over the decompressed .data section using the above size) | 
| 0x100 | Variable | Compressed sections | 
Flags
| Bits | Description | 
|---|---|
| 0 | TextCompress (.text section is compressed) | 
| 1 | RoCompress (.rodata section is compressed) | 
| 2 | DataCompress (.data section is compressed) | 
| 3 | TextHash (.text hash must be checked when loading) | 
| 4 | RoHash (.rodata hash must be checked when loading) | 
| 5 | DataHash (.data hash must be checked when loading) | 
ModuleId
This is "nn::ro::detail::ModuleId".
Value of "build id" from ELF's GNU .note section. Contains variable sized digest, up to 32bytes.
Arguments
Loader maps memory and writes the arguments to {end of rwdata section}. Official processes use argdata_addr = {page-aligned _end}. svcQueryMemory is used by official sw to verify that argdata_addr is mapped RW, since this memory is only mapped when arguments are specified via that command. Afterwards, official sw aligns the argdata_addr to 4-bytes.
The structure located at argdata_addr is as follows:
| Offset | Size | Description | 
|---|---|---|
| 0x0 | 0x4 | This is the total allocated space relative to argdata_addr, used for calculating the max size of the argv ptr array. Normally 0x9000? | 
| 0x4 | 0x4 | This is the total_bytesize of the actual argdata string. | 
| 0x8 | 0x18 | Unused by official sw. | 
| 0x20 | See above | Actual argdata string. | 
- The copy of the args used with the argv array is written by official processes to actual_argdata_string+actual_argdata_size.
- argv_ptrarray written by official processes is at (args_copy+actual_argdata_size) + 0x9 & ~0x7.