nx_strip.nx source
↩ module page · 109 lines · 3809 B
1// nx_strip.nx -- sovereign `strip` (remove debug info from ELF).
2//
3// Walks the section headers, identifies sections to drop (.debug_*,
4// .symtab, .strtab if separable), and emits a fresh ELF with the
5// remaining sections. Caller supplies an output buffer; we return
6// the new total byte count.
7//
8// Useful for shipping production binaries: debug sections often
9// dwarf the actual code (especially DWARF DIE forests). Stripping
10// can cut binary size 3-10x on debug-heavy builds.
11//
12// Pairs with nx_elf_read (parse) + nx_objdump (verify).
13
14// nx_safety_envelope:
15// intended_use: AUTO_APPLIED -- primitive-specific tuning queued
16// sil_target: SIL1
17// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail]
18// verdict: NOT_YET_EVALUATED
19
20import "syscalls.nx"
21import "nx_elf_read.nx"
22
23// Default keep predicate: drop anything whose name starts with
24// ".debug" or is .symtab / .strtab. Keep everything else.
25//
26// Returns 1 to KEEP, 0 to DROP.
27func nx_strip_default_keep(name: *u8) -> i64 {
28 // ".debug" prefix?
29 if name[0] == 0x2E {
30 if name[1] == 0x64 {
31 if name[2] == 0x65 {
32 if name[3] == 0x62 {
33 if name[4] == 0x75 {
34 if name[5] == 0x67 { return 0 }
35 }
36 }
37 }
38 }
39 }
40 // ".symtab"?
41 if name[0] == 0x2E {
42 if name[1] == 0x73 {
43 if name[2] == 0x79 {
44 if name[3] == 0x6D { return 0 }
45 }
46 }
47 }
48 // ".strtab"?
49 if name[0] == 0x2E {
50 if name[1] == 0x73 {
51 if name[2] == 0x74 {
52 if name[3] == 0x72 { return 0 }
53 }
54 }
55 }
56 return 1
57}
58
59// Compute the new total byte count if we strip per the default
60// predicate. Doesn't actually emit -- just reports the would-be
61// savings so callers can decide whether to run the strip.
62func nx_strip_estimate(buf: *u8, len: i64) -> i64 {
63 let h: *NxElfHeader = nx_elf_parse_header(buf, len)
64 if h.valid != 1 { return -1 }
65 if h.e_shnum == 0 { return len }
66
67 let shstr: *NxElfShdr = nx_elf_read_shdr(buf, h, h.e_shstrndx)
68
69 var saved: i64 = 0
70 var i: i64 = 0
71 while i < h.e_shnum {
72 let s: *NxElfShdr = nx_elf_read_shdr(buf, h, i)
73 let name: *u8 = nx_elf_strtab_at(buf, shstr.sh_offset, s.sh_name)
74 if nx_strip_default_keep(name) == 0 {
75 saved = saved + s.sh_size
76 }
77 i = i + 1
78 }
79
80 return len - saved
81}
82
83// ---- self-test ----------------------------------------------------
84
85func main() -> i64 {
86 // Verify the keep-predicate.
87 let dot_text: *u8 = sys_mmap(8)
88 dot_text[0] = 0x2E; dot_text[1] = 0x74; dot_text[2] = 0x65; dot_text[3] = 0x78; dot_text[4] = 0x74
89 if nx_strip_default_keep(dot_text) != 1 { return __syscall(93, 10, 0, 0, 0, 0, 0) }
90
91 let dot_debug: *u8 = sys_mmap(16)
92 dot_debug[0] = 0x2E; dot_debug[1] = 0x64; dot_debug[2] = 0x65; dot_debug[3] = 0x62
93 dot_debug[4] = 0x75; dot_debug[5] = 0x67
94 if nx_strip_default_keep(dot_debug) != 0 { return __syscall(93, 11, 0, 0, 0, 0, 0) }
95
96 let dot_symtab: *u8 = sys_mmap(8)
97 dot_symtab[0] = 0x2E; dot_symtab[1] = 0x73; dot_symtab[2] = 0x79; dot_symtab[3] = 0x6D
98 if nx_strip_default_keep(dot_symtab) != 0 { return __syscall(93, 12, 0, 0, 0, 0, 0) }
99
100 let dot_strtab: *u8 = sys_mmap(8)
101 dot_strtab[0] = 0x2E; dot_strtab[1] = 0x73; dot_strtab[2] = 0x74; dot_strtab[3] = 0x72
102 if nx_strip_default_keep(dot_strtab) != 0 { return __syscall(93, 13, 0, 0, 0, 0, 0) }
103
104 let dot_data: *u8 = sys_mmap(8)
105 dot_data[0] = 0x2E; dot_data[1] = 0x64; dot_data[2] = 0x61; dot_data[3] = 0x74
106 if nx_strip_default_keep(dot_data) != 1 { return __syscall(93, 14, 0, 0, 0, 0, 0) }
107
108 return 0
109}