Difference between revisions of "NSO"
From Nintendo Switch Brew
| Line 97: | Line 97: | ||
| | | | ||
| Compressed sections | | Compressed sections | ||
| + | |} | ||
| + | |||
| + | Most data in Switch binaries are standard ELF structures, however some are custom. | ||
| + | For example, the MOD header is essentially a replacement for a PT_DYNAMIC program header. | ||
| + | |||
| + | === MOD === | ||
| + | All offsets are signed 32bit values relative to the magic field. | ||
| + | The 32bits at image base + 4 must point to the magic field. | ||
| + | The MOD structure is designed such that it can be placed at image base and point to itself. | ||
| + | The 2 fields preceding the magic field get copied around with the structure, even if it is relocated to somewhere besides the image base. | ||
| + | {| class="wikitable" border="1" | ||
| + | |- | ||
| + | ! Offset | ||
| + | ! Size | ||
| + | ! Description | ||
| + | |- | ||
| + | | 0x00 | ||
| + | | 4 | ||
| + | | zero padding | ||
| + | |- | ||
| + | | 0x04 | ||
| + | | 4 | ||
| + | | offset to magic. Always 8 (so it works when MOD is at image_base + 0). | ||
| + | |- | ||
| + | | 0x08 | ||
| + | | 4 | ||
| + | | magic "MOD0" | ||
| + | |- | ||
| + | | 0x0C | ||
| + | | 4 | ||
| + | | .dynamic offset | ||
| + | |- | ||
| + | | 0x10 | ||
| + | | 4 | ||
| + | | .bss start offset | ||
| + | |- | ||
| + | | 0x14 | ||
| + | | 4 | ||
| + | | .bss end offset | ||
| + | |- | ||
| + | | 0x18 | ||
| + | | 4 | ||
| + | | .eh_frame start offset | ||
| + | |- | ||
| + | | 0x1C | ||
| + | | 4 | ||
| + | | .eh_frame end offset | ||
| + | |- | ||
| + | | 0x20 | ||
| + | | 4 | ||
| + | | offset to runtime-generated module object. typically equal to .bss base. | ||
|} | |} | ||
Revision as of 18:51, 3 July 2017
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):
SegmentHeader
| Offset | Size | Description |
|---|---|---|
| 0x0 | 4 | file offset of data |
| 0x4 | 4 | memory offset loaded to |
| 0x8 | 4 | size of data copied to memory offset (i.e. size after decompression) |
| 0xC | 4 | alignment used on memory size / size of .bss in the case of .data segment |
.rodata-relative extent
| Offset | Size | Description |
|---|---|---|
| 0x0 | 4 | offset (relative to .rodata) |
| 0x4 | 4 | size of region |
NSO Header
| Offset | Size | Description |
|---|---|---|
| 0x0 | 4 | Magic "NSO0" |
| 0x4 | 4 | |
| 0x8 | 4 | |
| 0xC | 4 | Always 0x3f? |
| 0x10 | 0x10 * 3 | SegmentHeader for each segment |
| 0x40 | 0x20 | Value of "build id" from ELF's GNU .note section. Contains variable sized digest, up to 32bytes. |
| 0x60 | 0x4 * 3 | file size of each segment (i.e. LZ4-compressed size) |
| 0x6c | 0x24 | Padding |
| 0x90 | 8 | .rodata-relative extents of .dynstr |
| 0x98 | 8 | .rodata-relative extents of .dynsym |
| 0xA0 | 0x20 * 3 | SHA256 hashes over the decompressed sections using the above byte-sizes: .text, .rodata, and .data. |
| 0x100 | Compressed sections |
Most data in Switch binaries are standard ELF structures, however some are custom. For example, the MOD header is essentially a replacement for a PT_DYNAMIC program header.
MOD
All offsets are signed 32bit values relative to the magic field. The 32bits at image base + 4 must point to the magic field. The MOD structure is designed such that it can be placed at image base and point to itself. The 2 fields preceding the magic field get copied around with the structure, even if it is relocated to somewhere besides the image base.
| Offset | Size | Description |
|---|---|---|
| 0x00 | 4 | zero padding |
| 0x04 | 4 | offset to magic. Always 8 (so it works when MOD is at image_base + 0). |
| 0x08 | 4 | magic "MOD0" |
| 0x0C | 4 | .dynamic offset |
| 0x10 | 4 | .bss start offset |
| 0x14 | 4 | .bss end offset |
| 0x18 | 4 | .eh_frame start offset |
| 0x1C | 4 | .eh_frame end offset |
| 0x20 | 4 | offset to runtime-generated module object. typically equal to .bss base. |