Difference between revisions of "NSO"

From Nintendo Switch Brew
Jump to navigation Jump to search
 
(32 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 header:
+
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
| Magic "NSO0"
+
| Signature ("NSO0")
 
|-
 
|-
 
| 0x4
 
| 0x4
 
| 4
 
| 4
|  
+
| Version
 
|-
 
|-
 
| 0x8
 
| 0x8
 
| 4
 
| 4
|  
+
| Reserved
 
|-
 
|-
 
| 0xC
 
| 0xC
 
| 4
 
| 4
|  
+
| [[#Flags|Flags]]
 
|-
 
|-
 
| 0x10
 
| 0x10
| 4
+
| 0x4
|  
+
| TextFileOffset
 
|-
 
|-
 
| 0x14
 
| 0x14
| 4
+
| 0x4
| .text offset? (0)
+
| TextMemoryOffset
 
|-
 
|-
 
| 0x18
 
| 0x18
| 4
+
| 0x4
| .text size
+
| TextSize
 
|-
 
|-
 
| 0x1C
 
| 0x1C
| 4
+
| 0x4
| .text required align? (0x1000)
+
| ModuleNameOffset (calculated by sizeof(header))
 
|-
 
|-
 
| 0x20
 
| 0x20
| 4
+
| 0x4
| .text compressed size?
+
| RoFileOffset
 
|-
 
|-
 
| 0x24
 
| 0x24
| 4
+
| 0x4
| .rodata offset
+
| RoMemoryOffset
 
|-
 
|-
 
| 0x28
 
| 0x28
| 4
+
| 0x4
| .rodata size
+
| RoSize
 
|-
 
|-
 
| 0x2C
 
| 0x2C
| 4
+
| 0x4
| .rodata required align? (1)
+
| ModuleNameSize
 
|-
 
|-
 
| 0x30
 
| 0x30
| 4
+
| 0x4
| .rodata compressed size?
+
| DataFileOffset
 
|-
 
|-
 
| 0x34
 
| 0x34
| 4
+
| 0x4
| .data offset
+
| DataMemoryOffset
 
|-
 
|-
 
| 0x38
 
| 0x38
| 4
+
| 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
| 0x60
+
| 0x20
| 3 Hashes over the decompressed sections using the above byte-sizes: .text, .rodata, and .data.
+
| 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.

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.