mirror of
https://github.com/rdmsr/zag.git
synced 2026-10-27 13:58:20 +00:00
build: rewrite ksyms script in zig
This commit is contained in:
@@ -36,11 +36,19 @@ pub fn build(b: *std.Build) void {
|
|||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
});
|
});
|
||||||
|
|
||||||
// first pass
|
const ksyms_exe = b.addExecutable(.{
|
||||||
const empty_cmd = b.addSystemCommand(&.{ "python3", "build/ksyms.py", "--empty" });
|
.name = "ksyms",
|
||||||
empty_cmd.addArg("--output");
|
.root_module = b.createModule(.{
|
||||||
|
.root_source_file = b.path("build/ksyms.zig"),
|
||||||
|
.target = b.graph.host,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
const empty_cmd = b.addRunArtifact(ksyms_exe);
|
||||||
const empty_ksyms_s = empty_cmd.addOutputFileArg("ksyms_empty.s");
|
const empty_ksyms_s = empty_cmd.addOutputFileArg("ksyms_empty.s");
|
||||||
|
|
||||||
|
empty_cmd.stdio = .inherit;
|
||||||
|
|
||||||
const rtl_module = b.createModule(.{
|
const rtl_module = b.createModule(.{
|
||||||
.root_source_file = b.path("src/rtl/root.zig"),
|
.root_source_file = b.path("src/rtl/root.zig"),
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
@@ -69,12 +77,10 @@ pub fn build(b: *std.Build) void {
|
|||||||
b.step("kernel-nosym", "Build nosym kernel").dependOn(&kernel_nosym.step);
|
b.step("kernel-nosym", "Build nosym kernel").dependOn(&kernel_nosym.step);
|
||||||
|
|
||||||
// generate symbols
|
// generate symbols
|
||||||
const ksyms = b.addSystemCommand(&.{ "python3", "build/ksyms.py" });
|
const ksyms = b.addRunArtifact(ksyms_exe);
|
||||||
ksyms.addArg("--input");
|
|
||||||
ksyms.step.dependOn(&kernel_nosym.step);
|
ksyms.step.dependOn(&kernel_nosym.step);
|
||||||
ksyms.addFileArg(kernel_nosym.getEmittedBin());
|
|
||||||
ksyms.addArg("--output");
|
|
||||||
const ksyms_s = ksyms.addOutputFileArg("ksyms.s");
|
const ksyms_s = ksyms.addOutputFileArg("ksyms.s");
|
||||||
|
ksyms.addFileArg(kernel_nosym.getEmittedBin());
|
||||||
|
|
||||||
// second pass
|
// second pass
|
||||||
const kernel = addKernel(b, plat, optimize, config_module, ksyms_module, rtl_module, arch_module);
|
const kernel = addKernel(b, plat, optimize, config_module, ksyms_module, rtl_module, arch_module);
|
||||||
|
|||||||
@@ -1,89 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
# Simple kernel symbol dumper
|
|
||||||
# Usage: ksyms.py --input <kernel binary> --output <output file>
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
|
|
||||||
excluded_symbols = [
|
|
||||||
"text_start_addr",
|
|
||||||
"text_end_addr",
|
|
||||||
"rodata_start_addr",
|
|
||||||
"rodata_end_addr",
|
|
||||||
"data_start_addr",
|
|
||||||
"data_end_addr",
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def parse_nm_line(line: str):
|
|
||||||
parts = line.split()
|
|
||||||
if len(parts) < 3:
|
|
||||||
return None
|
|
||||||
|
|
||||||
addr_str, type, name = parts[0], parts[1], parts[2]
|
|
||||||
|
|
||||||
# Only get symbols in text
|
|
||||||
if type.lower() != "t":
|
|
||||||
return None
|
|
||||||
|
|
||||||
if name in excluded_symbols:
|
|
||||||
return None
|
|
||||||
|
|
||||||
addr = int(addr_str, 16)
|
|
||||||
return addr, name
|
|
||||||
|
|
||||||
|
|
||||||
def run_nm(binary: str):
|
|
||||||
result = subprocess.run(["nm", "-n", binary], capture_output=True, text=True)
|
|
||||||
if result.returncode != 0:
|
|
||||||
raise RuntimeError(f"nm failed: {result.stderr}")
|
|
||||||
return result.stdout.splitlines()
|
|
||||||
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(description="Generate kernel symbols from a binary")
|
|
||||||
parser.add_argument("--input", help="Input kernel binary")
|
|
||||||
parser.add_argument("--output", help="Output Assembly file (.s)")
|
|
||||||
parser.add_argument("--empty", action="store_true", help="Generate empty ksyms")
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
with open(args.output, "w") as f:
|
|
||||||
f.write("/* Auto-generated by build/ksyms.py - do not edit */\n")
|
|
||||||
f.write(".section .rodata\n")
|
|
||||||
|
|
||||||
if args.empty:
|
|
||||||
f.write(".global ksyms_array\n")
|
|
||||||
f.write(".global ksyms_count\n")
|
|
||||||
f.write(".align 8\n")
|
|
||||||
f.write("ksyms_array:\n")
|
|
||||||
f.write("ksyms_count:\n")
|
|
||||||
f.write(" .quad 0\n")
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
lines = run_nm(args.input)
|
|
||||||
symbols = []
|
|
||||||
for line in lines:
|
|
||||||
parsed = parse_nm_line(line)
|
|
||||||
if parsed:
|
|
||||||
symbols.append(parsed)
|
|
||||||
|
|
||||||
# Sort by address
|
|
||||||
symbols.sort(key=lambda x: x[0])
|
|
||||||
|
|
||||||
for i, (addr, name) in enumerate(symbols):
|
|
||||||
escaped = name.replace("\\", "\\\\").replace('"', '\\"')
|
|
||||||
f.write(f'.Lstr{i}: .asciz "{escaped}"\n')
|
|
||||||
|
|
||||||
f.write("\n.global ksyms_array\n")
|
|
||||||
f.write(".global ksyms_count\n")
|
|
||||||
f.write(".align 8\n")
|
|
||||||
f.write("ksyms_array:\n")
|
|
||||||
|
|
||||||
for i, (addr, name) in enumerate(symbols):
|
|
||||||
name_len = len(name.encode("utf-8"))
|
|
||||||
f.write(f" .quad 0x{addr:016x}\n")
|
|
||||||
f.write(f" .quad .Lstr{i}\n")
|
|
||||||
f.write(f" .quad {name_len}\n")
|
|
||||||
|
|
||||||
f.write("\nksyms_count:\n")
|
|
||||||
f.write(f" .quad {len(symbols)}\n")
|
|
||||||
+161
@@ -0,0 +1,161 @@
|
|||||||
|
//! Script to generate ksyms
|
||||||
|
//! Usage: ksyms.zig <output> <input>
|
||||||
|
const std = @import("std");
|
||||||
|
const builtin = @import("builtin");
|
||||||
|
const elf = std.elf;
|
||||||
|
const Io = std.Io;
|
||||||
|
const Allocator = std.mem.Allocator;
|
||||||
|
|
||||||
|
const Symbol = struct {
|
||||||
|
addr: usize,
|
||||||
|
name: []const u8,
|
||||||
|
};
|
||||||
|
|
||||||
|
const file_hdr =
|
||||||
|
\\/* Auto-generated by build/ksyms.zig - do not edit */
|
||||||
|
\\.section .rodata
|
||||||
|
\\.global ksyms_array
|
||||||
|
\\.global ksyms_count
|
||||||
|
\\.align 8
|
||||||
|
\\
|
||||||
|
;
|
||||||
|
|
||||||
|
const empty_str = file_hdr ++
|
||||||
|
\\ksyms_array:
|
||||||
|
\\ksyms_count:
|
||||||
|
\\.quad 0
|
||||||
|
;
|
||||||
|
|
||||||
|
fn getElfString(strtab: []const u8, offset: u32) []const u8 {
|
||||||
|
const remainder = strtab[offset..];
|
||||||
|
const str_ptr: [*:0]const u8 = @ptrCast(remainder.ptr);
|
||||||
|
const len = std.mem.len(str_ptr);
|
||||||
|
return remainder[0..len];
|
||||||
|
}
|
||||||
|
|
||||||
|
fn getSymbols(allocator: Allocator, bytes: []u8) !std.ArrayList(Symbol) {
|
||||||
|
var reader = Io.Reader.fixed(bytes);
|
||||||
|
|
||||||
|
const header = try std.elf.Header.read(&reader);
|
||||||
|
|
||||||
|
const shstrhdr_addr = header.shoff + (header.shentsize * header.shstrndx);
|
||||||
|
|
||||||
|
const shstrhdr = std.mem.bytesAsValue(elf.Shdr, bytes[shstrhdr_addr..]);
|
||||||
|
const section_names: []const u8 = bytes[shstrhdr.sh_offset..];
|
||||||
|
|
||||||
|
reader.seek = header.shoff;
|
||||||
|
|
||||||
|
var text_section_index: usize = undefined;
|
||||||
|
var symtab: elf.Shdr = undefined;
|
||||||
|
|
||||||
|
const shdrs = std.mem.bytesAsSlice(
|
||||||
|
elf.Shdr,
|
||||||
|
bytes[header.shoff..][0 .. header.shnum * header.shentsize],
|
||||||
|
);
|
||||||
|
|
||||||
|
for (0..header.shnum) |i| {
|
||||||
|
const name = getElfString(section_names, shdrs[i].sh_name);
|
||||||
|
|
||||||
|
if (std.mem.eql(u8, name, ".text")) {
|
||||||
|
text_section_index = i;
|
||||||
|
} else if (shdrs[i].sh_type == elf.SHT_SYMTAB) {
|
||||||
|
symtab = shdrs[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const sym_strtab_shdr_addr = header.shoff + (header.shentsize * symtab.sh_link);
|
||||||
|
const sym_strtab_shdr = std.mem.bytesAsValue(elf.Shdr, bytes[sym_strtab_shdr_addr..]);
|
||||||
|
const symbol_names: []const u8 = bytes[sym_strtab_shdr.sh_offset..];
|
||||||
|
|
||||||
|
const how_many = symtab.sh_size / symtab.sh_entsize;
|
||||||
|
const symbols: [*]elf.Sym = @ptrCast(@alignCast(bytes[symtab.sh_offset..].ptr));
|
||||||
|
|
||||||
|
var ret = try std.ArrayList(Symbol).initCapacity(allocator, how_many);
|
||||||
|
|
||||||
|
for (0..how_many) |i| {
|
||||||
|
const sym = symbols[i];
|
||||||
|
|
||||||
|
if (sym.st_shndx == elf.SHN_UNDEF)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (sym.st_name == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (sym.st_shndx != text_section_index) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const name = getElfString(symbol_names, sym.st_name);
|
||||||
|
|
||||||
|
try ret.append(allocator, .{
|
||||||
|
.addr = sym.st_value,
|
||||||
|
.name = name,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lessThan(_: void, a: Symbol, b: Symbol) bool {
|
||||||
|
return a.addr < b.addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generateSymbols(alloc: Allocator, file: []u8, writer: *Io.Writer) !void {
|
||||||
|
const symbols = try getSymbols(alloc, file);
|
||||||
|
|
||||||
|
std.mem.sort(Symbol, symbols.items, {}, lessThan);
|
||||||
|
|
||||||
|
_ = try writer.write(file_hdr);
|
||||||
|
_ = try writer.write("ksyms_array:\n");
|
||||||
|
|
||||||
|
for (symbols.items, 0..) |sym, i| {
|
||||||
|
try writer.print(".quad 0x{x}\n", .{sym.addr});
|
||||||
|
try writer.print(".quad .Lstr{}\n", .{i});
|
||||||
|
try writer.print(".quad {}\n", .{sym.name.len});
|
||||||
|
}
|
||||||
|
|
||||||
|
try writer.print("ksyms_count:\n .quad {}\n", .{symbols.items.len});
|
||||||
|
|
||||||
|
for (symbols.items, 0..) |sym, i| {
|
||||||
|
if (std.mem.indexOfScalar(u8, sym.name, '"') == null) {
|
||||||
|
try writer.print(".Lstr{}: .asciz \"{s}\"\n", .{ i, sym.name });
|
||||||
|
} else {
|
||||||
|
const size = std.mem.replacementSize(u8, sym.name, "\"", "\\\"");
|
||||||
|
const escaped = try alloc.alloc(u8, size);
|
||||||
|
|
||||||
|
_ = std.mem.replace(u8, sym.name, "\"", "\\\"", escaped);
|
||||||
|
try writer.print(".Lstr{}: .asciz \"{s}\" \n", .{ i, escaped });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main(init: std.process.Init) !void {
|
||||||
|
const arena = init.arena.allocator();
|
||||||
|
const io = init.io;
|
||||||
|
const args = init.minimal.args;
|
||||||
|
const args_slice = try args.toSlice(arena);
|
||||||
|
|
||||||
|
const outfile = try std.Io.Dir.cwd().createFile(io, args_slice[1], .{});
|
||||||
|
defer outfile.close(io);
|
||||||
|
|
||||||
|
const write_buffer = try arena.alloc(u8, 64 * 1024);
|
||||||
|
var writer = outfile.writer(io, write_buffer);
|
||||||
|
|
||||||
|
if (args_slice.len == 2) {
|
||||||
|
// Only output, generate an empty file.
|
||||||
|
try writer.interface.writeAll(empty_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args_slice.len == 3) {
|
||||||
|
// Got an input, parse the ELF.
|
||||||
|
const buf = try std.Io.Dir.cwd().readFileAlloc(
|
||||||
|
io,
|
||||||
|
args_slice[2],
|
||||||
|
arena,
|
||||||
|
.unlimited,
|
||||||
|
);
|
||||||
|
try generateSymbols(arena, buf, &writer.interface);
|
||||||
|
}
|
||||||
|
|
||||||
|
try writer.flush();
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user