const std = @import("std"); // Total reserved size of the `_symbols` section. The section is // self-contained: symbol_area.S emits its entries followed by a // `.space` fill up to exactly this size, and the linker scripts just // `KEEP(*(_symbols))` with no separate reservation — so this constant // is the only knob. Bumped 65536 -> 98304 once the symbol count // (compiler-rt + the FS modules) pushed used_space past 64 KiB; bumped // 98304 -> 131072 when the USB gadget driver pushed past 96 KiB. const pre_allocated_size = 131072; const symbol_area_file = "src/symbol_area.S"; const entry_size = 64; const max_sym_name_len = entry_size - 8 - 1; pub fn main(init: std.process.Init) !void { const io = init.io; var stdout_buf: [1024]u8 = undefined; var stdout_obj = std.Io.File.stdout().writer(io, &stdout_buf); const stdout = &stdout_obj.interface; try stdout.writeAll("generating symbol area\n"); var file = try std.Io.Dir.cwd().createFile(io, symbol_area_file, .{}); defer file.close(io); var file_buf: [4096]u8 = undefined; var writer_obj = file.writer(io, &file_buf); const writer = &writer_obj.interface; try writer.writeAll(".section \"_symbols\", \"a\"\n"); var count: usize = 0; var stdin_buf: [4096]u8 = undefined; var stdin_obj = std.Io.File.stdin().reader(io, &stdin_buf); const stdin = &stdin_obj.interface; var input_buf: [1024 * 1024]u8 = undefined; const input_len = try stdin.readSliceShort(&input_buf); if (input_len == input_buf.len) { std.debug.panic("symbol table input filled the {d} B buffer — likely truncated, grow input_buf!\n", .{input_buf.len}); } var line_it = std.mem.splitScalar(u8, input_buf[0..input_len], '\n'); while (line_it.next()) |line| { const trimmed = std.mem.trim(u8, line, " \r"); if (trimmed.len == 0) continue; var it = std.mem.tokenizeAny(u8, trimmed, " \t"); const addr = it.next() orelse continue; _ = it.next() orelse continue; // ignore the symbol type field const name = it.next() orelse continue; if (name.len > max_sym_name_len) { std.debug.panic("{s} is too long!\n", .{name}); } try writer.print(".quad 0x{s}\n", .{addr}); try writer.print(".string \"{s}\"\n", .{name}); try writer.print(".space {d}\n", .{max_sym_name_len - name.len}); count += 1; } // null entry sentinel that terminates the symbol table try writer.writeAll(".space 64\n"); count += 1; const used_space = entry_size * count; if (used_space > pre_allocated_size) { // Print actionable numbers: the bump must be at least the // shortfall, rounded to a comfortable size so the next few // growth rounds don't re-trip this. pre_allocated_size at the // top of this file is the only knob — the `_symbols` section // is self-sized (this script's trailing `.space` fill) and the // linker scripts just `KEEP(*(_symbols))`, so nothing else // needs touching in lockstep. std.debug.panic( "too many symbols! used_space={d} > pre_allocated_size={d} " ++ "(shortfall {d} bytes, {d} symbols at {d} bytes each). " ++ "Bump pre_allocated_size in scripts/generate_syms.zig.\n", .{ used_space, pre_allocated_size, used_space - pre_allocated_size, count, entry_size }, ); } try writer.print(".space {d}\n", .{pre_allocated_size - used_space}); // flush buffered output before exiting try writer.flush(); try stdout.print("symbol area: {d}\n", .{used_space}); try stdout.writeAll("please be sure the pre_allocated_size == the .space value in the first pass!\n"); try stdout.flush(); }