nx_size.nx source
↩ module page · 142 lines · 4772 B
1// nx_size.nx -- sovereign `size` tool (binutils equivalent).
2//
3// Reports section sizes in the standard sysv format:
4//
5// text data bss dec hex filename
6// 1024 256 512 1792 0x700 my_program.elf
7//
8// 'text' = ALLOCATED + EXECUTABLE bytes (.text + .rodata)
9// 'data' = ALLOCATED + WRITABLE bytes (.data)
10// 'bss' = ALLOCATED + NOBITS bytes (.bss)
11// 'dec' = sum
12// 'hex' = same in hex
13//
14// Useful for tracking binary bloat over commits + verifying that
15// stripping or DCE actually shrank what we expected.
16//
17// Pairs with nx_objdump / nx_nm / nx_readelf as the size-focused
18// inspection tool.
19
20// nx_safety_envelope:
21// intended_use: AUTO_APPLIED -- primitive-specific tuning queued
22// sil_target: SIL1
23// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail]
24// verdict: NOT_YET_EVALUATED
25
26import "syscalls.nx"
27import "nx_elf_read.nx"
28import "nx_strfmt.nx"
29const NX_MAGIC_1024: i64 = 1024
30
31// SHF_* (matches nx_shtab constants).
32const NX_SIZE_SHF_WRITE: i64 = 0x1
33const NX_SIZE_SHF_ALLOC: i64 = 0x2
34const NX_SIZE_SHF_EXECINSTR: i64 = 0x4
35// SHT_*.
36const NX_SIZE_SHT_NOBITS: i64 = 8
37
38struct NxSizeReport {
39 text: i64,
40 data: i64,
41 bss: i64,
42}
43
44const NX_SIZE_REPORT_BYTES: i64 = 24
45
46func nx_size_report(buf: *u8, len: i64) -> *NxSizeReport {
47 let raw: *u8 = sys_mmap(NX_SIZE_REPORT_BYTES)
48 let r: *NxSizeReport = raw as *NxSizeReport
49 r.text = 0
50 r.data = 0
51 r.bss = 0
52
53 let h: *NxElfHeader = nx_elf_parse_header(buf, len)
54 if h.valid != 1 { return r }
55 if h.e_shnum == 0 { return r }
56
57 var i: i64 = 0
58 while i < h.e_shnum {
59 let s: *NxElfShdr = nx_elf_read_shdr(buf, h, i)
60 if (s.sh_flags & NX_SIZE_SHF_ALLOC) != 0 {
61 if s.sh_type == NX_SIZE_SHT_NOBITS {
62 r.bss = r.bss + s.sh_size
63 } else {
64 if (s.sh_flags & NX_SIZE_SHF_EXECINSTR) != 0 {
65 r.text = r.text + s.sh_size
66 } else {
67 if (s.sh_flags & NX_SIZE_SHF_WRITE) != 0 {
68 r.data = r.data + s.sh_size
69 } else {
70 // .rodata: counted as text.
71 r.text = r.text + s.sh_size
72 }
73 }
74 }
75 }
76 i = i + 1
77 }
78 return r
79}
80
81// Print sysv-format size to fd.
82func nx_size_print(buf: *u8, len: i64, fname: *u8, fd: i64) -> i64 {
83 let r: *NxSizeReport = nx_size_report(buf, len)
84 let total: i64 = r.text + r.data + r.bss
85
86 sys_write(fd, " text data bss dec hex filename\n" as *u8, 46)
87
88 let argv_raw: *u8 = sys_mmap(64)
89 let argv: *i64 = argv_raw as *i64
90 argv[0] = r.text
91 argv[1] = r.data
92 argv[2] = r.bss
93 argv[3] = total
94 argv[4] = total
95 argv[5] = fname as i64
96 nx_fmt_to_fd(fd, " %d %d %d %d 0x%X %s\n" as *u8, argv, 6)
97 return 0
98}
99
100// ---- self-test ---------------------------------------------------
101
102func main() -> i64 {
103 // Build a fake ELF with section headers describing 1 PROGBITS+
104 // EXEC + 1 PROGBITS+WRITE + 1 NOBITS section.
105 // Minimal layout: header + 4 section headers (NULL, .text, .data,
106 // .bss) at offset 0x100.
107 let elf: *u8 = sys_mmap(NX_MAGIC_1024)
108 var i: i64 = 0
109 while i < NX_MAGIC_1024 { elf[i] = 0; i = i + 1 }
110
111 // ELF header.
112 elf[0] = 0x7F; elf[1] = 0x45; elf[2] = 0x4C; elf[3] = 0x46
113 elf[4] = 2; elf[5] = 1; elf[6] = 1
114 elf[16] = 2; elf[18] = 0xF3
115 elf[40] = 0; elf[41] = 0x01 // e_shoff = 0x100
116 elf[52] = 64; elf[58] = 64; elf[60] = 4 // shentsize=64, shnum=4
117
118 // Section header table at offset 0x100.
119 // [0] NULL: all zero.
120 // [1] .text: PROGBITS, ALLOC|EXEC, size 256.
121 let off_text: i64 = 0x100 + 64
122 elf[off_text + 4] = 1 // SHT_PROGBITS
123 elf[off_text + 8] = 0x06 // ALLOC|EXEC
124 elf[off_text + 32] = 0; elf[off_text + 33] = 0x01 // size = 256
125 // [2] .data: PROGBITS, ALLOC|WRITE, size 128.
126 let off_data: i64 = 0x100 + 128
127 elf[off_data + 4] = 1
128 elf[off_data + 8] = 0x03 // ALLOC|WRITE
129 elf[off_data + 32] = 128
130 // [3] .bss: NOBITS, ALLOC|WRITE, size 512.
131 let off_bss: i64 = 0x100 + 192
132 elf[off_bss + 4] = 8 // SHT_NOBITS
133 elf[off_bss + 8] = 0x03 // ALLOC|WRITE
134 elf[off_bss + 32] = 0; elf[off_bss + 33] = 2 // size = 512
135
136 let r: *NxSizeReport = nx_size_report(elf, NX_MAGIC_1024)
137 if r.text != 256 { return __syscall(93, 10, 0, 0, 0, 0, 0) }
138 if r.data != 128 { return __syscall(93, 11, 0, 0, 0, 0, 0) }
139 if r.bss != 512 { return __syscall(93, 12, 0, 0, 0, 0, 0) }
140
141 return 0
142}