Difference between revisions of "NSO"
(19 intermediate revisions by 7 users not shown) | |||
Line 1: | Line 1: | ||
NSO is the main executable format. | 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) | + | 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 12: | Line 12: | ||
| 0x0 | | 0x0 | ||
| 4 | | 4 | ||
− | | | + | | Signature ("NSO0") |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
|- | |- | ||
| 0x4 | | 0x4 | ||
Line 36: | Line 20: | ||
| 0x8 | | 0x8 | ||
| 4 | | 4 | ||
− | | | + | | Reserved |
|- | |- | ||
| 0xC | | 0xC | ||
| 4 | | 4 | ||
− | | Flags | + | | [[#Flags|Flags]] |
|- | |- | ||
| 0x10 | | 0x10 | ||
− | | | + | | 0x4 |
| TextFileOffset | | TextFileOffset | ||
|- | |- | ||
| 0x14 | | 0x14 | ||
− | | | + | | 0x4 |
| TextMemoryOffset | | TextMemoryOffset | ||
|- | |- | ||
| 0x18 | | 0x18 | ||
− | | | + | | 0x4 |
| TextSize | | TextSize | ||
|- | |- | ||
| 0x1C | | 0x1C | ||
− | | | + | | 0x4 |
− | | ModuleNameOffset | + | | ModuleNameOffset (calculated by sizeof(header)) |
|- | |- | ||
| 0x20 | | 0x20 | ||
− | | | + | | 0x4 |
| RoFileOffset | | RoFileOffset | ||
|- | |- | ||
| 0x24 | | 0x24 | ||
− | | | + | | 0x4 |
| RoMemoryOffset | | RoMemoryOffset | ||
|- | |- | ||
| 0x28 | | 0x28 | ||
− | | | + | | 0x4 |
| RoSize | | RoSize | ||
|- | |- | ||
| 0x2C | | 0x2C | ||
− | | | + | | 0x4 |
| ModuleNameSize | | ModuleNameSize | ||
|- | |- | ||
| 0x30 | | 0x30 | ||
− | | | + | | 0x4 |
| DataFileOffset | | DataFileOffset | ||
|- | |- | ||
| 0x34 | | 0x34 | ||
− | | | + | | 0x4 |
| DataMemoryOffset | | DataMemoryOffset | ||
|- | |- | ||
| 0x38 | | 0x38 | ||
− | | | + | | 0x4 |
| DataSize | | DataSize | ||
|- | |- | ||
| 0x3C | | 0x3C | ||
− | | | + | | 0x4 |
| BssSize | | BssSize | ||
|- | |- | ||
| 0x40 | | 0x40 | ||
| 0x20 | | 0x20 | ||
− | | | + | | [[#ModuleId|ModuleId]] |
|- | |- | ||
| 0x60 | | 0x60 | ||
| 0x4 | | 0x4 | ||
− | | TextFileSize | + | | TextFileSize (.text compressed size) |
|- | |- | ||
| 0x64 | | 0x64 | ||
| 0x4 | | 0x4 | ||
− | | RoFileSize | + | | RoFileSize (.rodata compressed size) |
|- | |- | ||
| 0x68 | | 0x68 | ||
| 0x4 | | 0x4 | ||
− | | DataFileSize | + | | DataFileSize (.data compressed size) |
+ | |- | ||
+ | | 0x6C | ||
+ | | 0x1C | ||
+ | | Reserved | ||
|- | |- | ||
− | | | + | | 0x88 |
− | | | + | | 0x4 |
− | | | + | | EmbeddedOffset (relative to the .rodata section) |
+ | |- | ||
+ | | 0x8C | ||
+ | | 0x4 | ||
+ | | EmbeddedSize | ||
|- | |- | ||
| 0x90 | | 0x90 | ||
− | | | + | | 0x4 |
− | | .rodata- | + | | DynStrOffset (relative to the .rodata section) |
+ | |- | ||
+ | | 0x94 | ||
+ | | 0x4 | ||
+ | | DynStrSize | ||
|- | |- | ||
| 0x98 | | 0x98 | ||
− | | | + | | 0x4 |
− | | .rodata- | + | | DynSymOffset (relative to the .rodata section) |
+ | |- | ||
+ | | 0x9C | ||
+ | | 0x4 | ||
+ | | DynSymSize | ||
|- | |- | ||
| 0xA0 | | 0xA0 | ||
− | | 0x20 | + | | 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" | {| class="wikitable" border="1" | ||
|- | |- | ||
− | ! | + | ! Bits |
− | |||
! Description | ! 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 | | 4 | ||
− | | | + | | RoHash (.rodata hash must be checked when loading) |
|- | |- | ||
− | | | + | | 5 |
− | | 4 | + | | 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 | + | | 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. |
Latest revision as of 21: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.