kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

commit 1237b5860034481d9e40836011e4e781f6a47ad4
parent 6405d2b7504c93c0c3b41a7ac8180c45691fc0f8
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Sun, 24 May 2026 05:19:07 -0700

slice: replace NUL-terminated strings with fat-pointer CfreeSlice

Eliminate NUL-terminated C strings across the first-party tree in favor of one
fat-pointer type carrying an explicit length, and type the whole public API in
terms of it. Strings retain a trailing NUL only where they cross an OS/format
boundary, and that NUL is never counted in the length.

Type & helpers
- CfreeSlice { union { const char* s; const uint8_t* data; }; size_t len; }
  (public) / Slice (internal), replacing CfreeBytes. Public CFREE_SLICE_LIT/
  _NULL/_ARG, cfree_slice_cstr/_eq/_eq_cstr; internal core/slice.{h,c} adds
  slice_from_cstr/slice_eq/slice_eq_cstr/slice_dup; strbuf gains put_slice/slice.

Interning & printing
- Interning is slice-valued: pool_slice/pool_intern_slice replace
  pool_str/pool_intern/pool_intern_cstr; public cfree_sym_str returns CfreeSlice
  and cfree_sym_intern takes one (cfree_sym_intern_len removed).
- Printing is length-explicit: every printf-family %s becomes %.*s + slice args;
  src/opt sprintf/snprintf moves to StrBuf.
- Comparisons: strcmp/strncmp on names/sections/registers/mnemonics/attributes
  become slice_eq/slice_eq_cstr (or Sym equality); arch mnemonic tables carry
  Slice. Ordering compares (stable sorts) are kept and annotated.

Public API typed on CfreeSlice
- disasm (CfreeInsn mnemonic/operands/annotation), object (sec/sym/reloc names,
  by_name lookups, group name), dwarf (names/files), jit (lookup/CfreeJitSym),
  arch (register name/index), link (script + session options: entry/soname/
  interp/rpaths/exports/patterns + CfreeExternResolver), compile (repl_entry_name,
  dep names), cg (file_scope_asm), archive (CfreeArMember.name + member symbols),
  source (add_memory/_builtin), preprocess (CfreeDefine/undefines), frontend
  extensions vtable, cfree_compiler_file_name.

Frontends & runtime
- lang/wasm interns names as CfreeSym instead of strdup; lang/c and lang/cpp call
  the public sym API directly (no local pool shims).

Boundaries kept as char*
- printf fmt, char[N] buffers, argv/envp, byte cursors in parsers/lexers, raw
  ELF/COFF readers, Mach-O fixed-name fields, static literal-table returns
  (op_name/register tables), host-callback vtable strings (metrics/diag), and
  file paths handed to CfreeFileIO/open()/host I/O. Driver/lang build with
  -Iinclude (driver also -Ilang) and never -Isrc.
- scripts/check_no_cstr.sh gates the tree: zero banned string functions and zero
  bare %s in src/lang/driver. The sole sanctioned NUL scan is slice_from_cstr in
  src/core/slice.c (plus the public inline cfree_slice_cstr at the argv boundary).

Build (lib/bin/rt) and gate clean; full suite green (isa, asm, parse, pp, toy,
opt, cg-api, link, elf, macho, dwarf, ar, debug, aa64-inline, wasm-front, coff,
x64 smoke; objdump rv64 8/8). Pre-existing, unrelated: test-parse-err
6_7_file_scope_register and the wine-dependent Windows/COFF smoke.

Diffstat:
MMakefile | 7+++++--
Mdriver/ar.c | 135++++++++++++++++++++++++++++++++++++++++++++++---------------------------------
Mdriver/as.c | 34+++++++++++++++++++++-------------
Mdriver/cc.c | 192++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------
Mdriver/cflags.c | 13+++++++------
Mdriver/cflags.h | 2+-
Mdriver/cpp.c | 34++++++++++++++++++++++------------
Mdriver/dbg.c | 295++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
Mdriver/driver.h | 6+++---
Mdriver/emu.c | 41++++++++++++++++++++++++-----------------
Mdriver/env.c | 78+++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------
Mdriver/hosted.c | 15++++++++-------
Mdriver/inputs.c | 49++++++++++++++++++++++++-------------------------
Mdriver/inputs.h | 12++++++------
Mdriver/ld.c | 110++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------
Mdriver/main.c | 11+++++++----
Mdriver/objcopy.c | 121+++++++++++++++++++++++++++++++++++++++++++++----------------------------------
Mdriver/objdump.c | 215+++++++++++++++++++++++++++++++++++++++++++++----------------------------------
Mdriver/ranlib.c | 41+++++++++++++++++++++++------------------
Mdriver/run.c | 55++++++++++++++++++++++++++++++++++---------------------
Mdriver/runtime.c | 54+++++++++++++++++++++++++++++++-----------------------
Mdriver/strip.c | 87+++++++++++++++++++++++++++++++++++++++++++------------------------------------
Mdriver/target.c | 9+++++----
Minclude/cfree/arch.h | 6+++---
Minclude/cfree/archive.h | 17++++++++++++-----
Minclude/cfree/cg.h | 3+--
Minclude/cfree/compile.h | 26++++++++++++++------------
Minclude/cfree/core.h | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------
Minclude/cfree/disasm.h | 8++++----
Minclude/cfree/dwarf.h | 28++++++++++++++--------------
Minclude/cfree/jit.h | 6+++---
Minclude/cfree/link.h | 47++++++++++++++++++++++++-----------------------
Minclude/cfree/object.h | 18+++++++++---------
Minclude/cfree/preprocess.h | 9+++++----
Minclude/cfree/source.h | 4++--
Mlang/c/abi/c_abi.c | 22+++++++++++-----------
Mlang/c/c.c | 15+++++++++------
Mlang/c/decl/decl_attrs.c | 16++++++++--------
Mlang/c/parse/cg_adapter.c | 6+++---
Mlang/c/parse/parse.c | 168++++++++++++++++++++++++++++++++++++++++---------------------------------------
Mlang/c/parse/parse_expr.c | 81+++++++++++++++++++++++++++++++++++++++++++++++--------------------------------
Mlang/c/parse/parse_init.c | 6+++---
Mlang/c/parse/parse_stmt.c | 16+++++++++-------
Mlang/c/parse/parse_type.c | 39++++++++++++++++++++++++---------------
Mlang/c/sem/sem.c | 13+++++--------
Mlang/cpp/cpp.c | 23++++++++++++++---------
Mlang/cpp/cpp_support.h | 17-----------------
Mlang/cpp/lex/lex.c | 15++++++++-------
Mlang/cpp/pp/pp.c | 73++++++++++++++++++++++++++++++++++++++-----------------------------------
Mlang/cpp/pp/pp_directive.c | 117++++++++++++++++++++++++++++++++++++++++++++++---------------------------------
Mlang/cpp/pp/pp_expand.c | 37++++++++++++++++++++++++++++---------
Mlang/toy/asm.c | 6+++---
Mlang/toy/builtins.c | 17+++++++++--------
Mlang/toy/compile.c | 13+++++++------
Mlang/toy/decls.c | 2+-
Mlang/toy/literals.c | 2+-
Mlang/toy/parser.c | 2+-
Mlang/toy/parser_core.c | 18+++++++++++-------
Mlang/toy/types.c | 4++--
Mlang/wasm/cg.c | 54+++++++++++++++++++++++++++---------------------------
Mlang/wasm/decode.c | 50++++++++++++++++++++------------------------------
Mlang/wasm/encode.c | 32++++++++++++++++----------------
Mlang/wasm/insn.c | 5+++--
Mlang/wasm/module.c | 45++++-----------------------------------------
Mlang/wasm/validate.c | 10+++++++---
Mlang/wasm/wasm.c | 20+++++++++++---------
Mlang/wasm/wasm.h | 2+-
Mlang/wasm/wasm_internal.h | 52++++++++++++++++++++++++++--------------------------
Mlang/wasm/wat.c | 178+++++++++++++++++++++++++++++--------------------------------------------------
Ascripts/check_no_cstr.sh | 37+++++++++++++++++++++++++++++++++++++
Msrc/api/arch.c | 17+++++++++++------
Msrc/api/archive.c | 95+++++++++++++++++++++++++++++++++----------------------------------------------
Msrc/api/compile.c | 61++++++++++++++++++++++++++++++++++---------------------------
Msrc/api/core.c | 36++++++++++++++++--------------------
Msrc/api/disasm.c | 62+++++++++++++++++++++++++++++++++-----------------------------
Msrc/api/link.c | 30++++++++++++++++++------------
Msrc/api/object_file.c | 49+++++++++++++++++++++++++++----------------------
Msrc/api/source.c | 4++--
Msrc/api/stubs.c | 4+++-
Msrc/arch/aa64/alloc.c | 11+++++------
Msrc/arch/aa64/arch.c | 24++++++++++++++----------
Msrc/arch/aa64/asm.c | 94+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
Msrc/arch/aa64/disasm.c | 8++++----
Msrc/arch/aa64/isa.c | 231++++++++++++++++++++++++++++++++++++++++---------------------------------------
Msrc/arch/aa64/isa.h | 3++-
Msrc/arch/aa64/ops.c | 15+++++++++------
Msrc/arch/aa64/regs.c | 9++++++---
Msrc/arch/c_target/emit.c | 38+++++++++++++++++++++-----------------
Msrc/arch/mc.c | 4++--
Msrc/arch/rv64/arch.c | 46+++++++++++++++++++++++++---------------------
Msrc/arch/rv64/asm.c | 98++++++++++++++++++++++++++++++++++++++++++-------------------------------------
Msrc/arch/rv64/disasm.c | 10+++++-----
Msrc/arch/rv64/emit.c | 4+++-
Msrc/arch/rv64/isa.c | 565++++++++++++++++++++++++++++++++++++++++---------------------------------------
Msrc/arch/rv64/isa.h | 5+++--
Msrc/arch/rv64/ops.c | 20++++++++++----------
Msrc/arch/rv64/regs.c | 8+++++---
Msrc/arch/x64/alloc.c | 19++++++++++---------
Msrc/arch/x64/arch.c | 24++++++++++++++----------
Msrc/arch/x64/asm.c | 97+++++++++++++++++++++++++++++++++++++++----------------------------------------
Msrc/arch/x64/disasm.c | 26+++++++++++++-------------
Msrc/arch/x64/emit.c | 3++-
Msrc/arch/x64/internal.h | 4+++-
Msrc/arch/x64/isa.c | 2+-
Msrc/arch/x64/isa.h | 3++-
Msrc/arch/x64/ops.c | 12+++++++-----
Msrc/arch/x64/regs.c | 17+++++++++++------
Msrc/asm/asm.c | 29+++++++++++++++++------------
Msrc/asm/asm_lex.c | 12++++++++----
Msrc/cg/arith.c | 3++-
Msrc/cg/asm.c | 14++++++--------
Msrc/cg/control.c | 12++++++++----
Msrc/cg/data.c | 20+++++++++++++-------
Msrc/cg/debug.c | 17++++++++++-------
Msrc/cg/internal.h | 5+++--
Msrc/cg/memory.c | 11++++++++---
Msrc/cg/session.c | 3++-
Msrc/cg/value.c | 31+++++++++++++++++++------------
Msrc/cg/wide.c | 3++-
Msrc/core/core.h | 4++--
Msrc/core/pool.c | 32+++++++++++---------------------
Msrc/core/pool.h | 11+++++++----
Asrc/core/slice.c | 28++++++++++++++++++++++++++++
Asrc/core/slice.h | 40++++++++++++++++++++++++++++++++++++++++
Msrc/core/source.c | 12+++++++-----
Msrc/core/strbuf.h | 13+++++++++++++
Msrc/dbg/step.c | 20+++++++++++---------
Msrc/debug/debug.c | 21++++++++++++---------
Msrc/debug/debug_emit.c | 23++++++++++++++---------
Msrc/debug/dwarf_line.c | 34++++++++++++++++++----------------
Msrc/debug/dwarf_open.c | 7++++---
Msrc/debug/dwarf_query.c | 37+++++++++++++++++++------------------
Msrc/debug/dwarf_type.c | 9+++++----
Msrc/emu/elf_load.c | 5+++--
Msrc/emu/emu.c | 3++-
Msrc/emu/emu.h | 2+-
Msrc/emu/runtime.c | 32++++++++++++--------------------
Msrc/link/link.c | 118++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
Msrc/link/link.h | 4++--
Msrc/link/link_coff.c | 59+++++++++++++++++++++++++++++++++--------------------------
Msrc/link/link_dyn.c | 43++++++++++++++++++++++++-------------------
Msrc/link/link_elf.c | 43++++++++++++++++++++++++++-----------------
Msrc/link/link_jit.c | 97+++++++++++++++++++++++++++++++++++++++++++------------------------------------
Msrc/link/link_layout.c | 44++++++++++++++++++++++++++------------------
Msrc/link/link_macho.c | 105++++++++++++++++++++++++++++++++++++++++++++++---------------------------------
Msrc/link/link_reloc_layout.c | 35+++++++++++++++++++++--------------
Msrc/link/link_relocatable.c | 6++++--
Msrc/link/link_resolve.c | 58+++++++++++++++++++++++++++++++---------------------------
Msrc/link/link_script.c | 49++++++++++++++++++++++++++++++-------------------
Msrc/obj/coff_emit.c | 7++++---
Msrc/obj/coff_read.c | 24++++++++++++++++--------
Msrc/obj/coff_read_dso.c | 5+++--
Msrc/obj/elf_emit.c | 7++++---
Msrc/obj/elf_read.c | 22++++++++++++----------
Msrc/obj/macho_emit.c | 19++++++++++++-------
Msrc/obj/macho_read.c | 11++++++-----
Msrc/obj/obj_secnames.c | 42++++++++++++++++++++++--------------------
Msrc/obj/obj_tls.c | 12+++++++-----
Msrc/obj/tbd_read.c | 6+++---
Msrc/opt/ir_print.c | 178+++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------
Msrc/opt/opt.c | 6++++--
Msrc/opt/pass_analysis.c | 23+++++++++++++++++++----
Msrc/opt/pass_emit.c | 8+++++---
Msrc/opt/pass_live.c | 68++++++++++++++++++++++++++++++++++++++++++++++++--------------------
Msrc/opt/pass_lower.c | 43++++++++++++++++++++++++++++++-------------
Msrc/opt/pass_machinize.c | 5++++-
Msrc/opt/pass_ssa.c | 76++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------
Mtest/api/abi_classify_test.c | 10+++++-----
Mtest/api/cg_switch_test.c | 4++--
Mtest/api/cg_type_test.c | 86++++++++++++++++++++++++++++++++++++++++----------------------------------------
Mtest/ar_test.c | 313++++++++++++++++++++++++++++++++++++++-----------------------------------------
Mtest/arch/aa64_inline_test.c | 4++--
Mtest/arch/aa64_isa_test.c | 18+++++++++---------
Mtest/arch/rv64_inline_test.c | 10+++++-----
Mtest/arch/x64_inline_test.c | 6+++---
Mtest/asm/harness/asm_runner.c | 59+++++++++++++++++++++++++++++++----------------------------
Mtest/coff/cfree-roundtrip-coff.c | 83+++++++++++++++++++++++++++++++++++++++----------------------------------------
Mtest/coff/pe-dso-forwarder.c | 4++--
Mtest/coff/pe-import-mingw.c | 8++++----
Mtest/coff/pe-import-smoke.c | 8++++----
Mtest/coff/pe-mixed-archive.c | 30+++++++++++++++---------------
Mtest/debug/cfi_unit.c | 10+++++-----
Mtest/debug/roundtrip_unit.c | 32+++++++++++++++++---------------
Mtest/dwarf/dwarf_test.c | 81++++++++++++++++++++++++++++++++++++++++++-------------------------------------
Mtest/elf/unit/align_4k.c | 9++++-----
Mtest/elf/unit/groupiter.c | 22+++++++++++-----------
Mtest/elf/unit/mutate.c | 32++++++++++++++++----------------
Mtest/elf/unit/smoke.c | 18++++++++----------
Mtest/elf/unit/x64_disasm_annotations.c | 31+++++++++++++++----------------
Mtest/libc/cases/11_strings.c | 16+++++++++-------
Mtest/libc/cases/13_malloc.c | 2+-
Mtest/link/harness/jit_runner.c | 42+++++++++++++++++++++++-------------------
Mtest/link/harness/link_exe_runner.c | 28++++++++++++++++------------
Mtest/link/rv64_jit_test.c | 8++++----
Mtest/opt/opt_test.c | 11++++++-----
Mtest/parse/harness/parse_runner.c | 32+++++++++++++++++---------------
Mtest/wasm/harness/wasm_tool.c | 3+--
197 files changed, 4234 insertions(+), 3331 deletions(-)

diff --git a/Makefile b/Makefile @@ -16,8 +16,11 @@ DEPFLAGS = -MMD -MP LIB_CFLAGS = $(CFLAGS_COMMON) -ffreestanding -Iinclude -Isrc # Driver: hosted CLI binary. Sees only the public include/ tree — that's -# what makes the driver the first consumer of libcfree. -DRIVER_CFLAGS = $(CFLAGS_COMMON) -Iinclude -I. +# what makes the driver the first consumer of libcfree. -Ilang lets `cc` reach +# the C frontend's public header ("c/c.h") for the JIT REPL; it deliberately +# does NOT get -Isrc, so internal headers ("core/...", "link/...") are +# unreachable from the driver. +DRIVER_CFLAGS = $(CFLAGS_COMMON) -Iinclude -Ilang include mk/config.mk diff --git a/driver/ar.c b/driver/ar.c @@ -47,14 +47,16 @@ #define AR_TOOL "ar" static void ar_usage(void) { - driver_errf(AR_TOOL, "%s", + driver_errf(AR_TOOL, "%.*s", + CFREE_SLICE_ARG(CFREE_SLICE_LIT( "usage: cfree ar {rc|r|c|t|x|p}[s] archive.a [members...]\n" - " cfree ar --help for full operation reference"); + " cfree ar --help for full operation reference"))); } void driver_help_ar(void) { driver_printf( - "%s", + "%.*s", + CFREE_SLICE_ARG(CFREE_SLICE_LIT( "cfree ar — POSIX `ar` archive front-end\n" "\n" "USAGE\n" @@ -109,7 +111,7 @@ void driver_help_ar(void) { "\n" "EXIT CODES\n" " 0 success 1 archive I/O error 2 bad " - "usage\n"); + "usage\n"))); } /* Parse SOURCE_DATE_EPOCH into a u64; 0 (or unset/invalid) means "no epoch". */ @@ -126,13 +128,13 @@ static uint64_t ar_epoch_from_env(void) { /* Return 1 iff `name` matches any of the names in argv[start..argc) — or if * there are no filters, in which case every member matches. */ -static int ar_name_selected(const char* name, int argc, char** argv, +static int ar_name_selected(CfreeSlice name, int argc, char** argv, int start) { int i; if (start >= argc) return 1; for (i = start; i < argc; ++i) { const char* base = driver_basename(argv[i]); - if (driver_streq(name, base)) return 1; + if (cfree_slice_eq_cstr(name, base)) return 1; } return 0; } @@ -140,14 +142,15 @@ static int ar_name_selected(const char* name, int argc, char** argv, /* Open the archive bytes via file_io. Caller releases fd via ctx. */ static int ar_open_for_read(DriverEnv* env, const char* path, CfreeContext* ctx_out, CfreeFileData* fd_out, - CfreeBytes* input_out) { + CfreeSlice* input_out) { *ctx_out = driver_env_to_context(env); if (ctx_out->file_io->read_all(ctx_out->file_io->user, path, fd_out) != CFREE_OK) { - driver_errf(AR_TOOL, "failed to read: %s", path); + driver_errf(AR_TOOL, "failed to read: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(path))); return 0; } - input_out->name = path; + (void)path; input_out->data = fd_out->data; input_out->len = fd_out->size; return 1; @@ -156,7 +159,7 @@ static int ar_open_for_read(DriverEnv* env, const char* path, static int ar_do_list(DriverEnv* env, const char* archive_path, int verbose) { CfreeContext ctx; CfreeFileData fd = {0}; - CfreeBytes input; + CfreeSlice input; CfreeWriter* out; int rc; @@ -173,7 +176,8 @@ static int ar_do_list(DriverEnv* env, const char* archive_path, int verbose) { CfreeArIter* it = NULL; CfreeArMember m; if (cfree_ar_iter_new(&ctx, &input, &it) != CFREE_OK) { - driver_errf(AR_TOOL, "not an archive: %s", archive_path); + driver_errf(AR_TOOL, "not an archive: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(archive_path))); cfree_writer_close(out); ctx.file_io->release(ctx.file_io->user, &fd); return 1; @@ -181,13 +185,16 @@ static int ar_do_list(DriverEnv* env, const char* archive_path, int verbose) { for (;;) { CfreeIterResult r = cfree_ar_iter_next(it, &m); if (r != CFREE_ITER_ITEM) break; - driver_printf("%zu\t%s\n", m.size, m.name); + driver_printf("%zu\t%.*s\n", m.size, + CFREE_SLICE_ARG(m.name)); } cfree_ar_iter_free(it); rc = cfree_writer_status(out) == CFREE_OK ? 0 : 1; } else { rc = cfree_ar_list(&input, out) == CFREE_OK ? 0 : 1; - if (rc) driver_errf(AR_TOOL, "failed to read archive: %s", archive_path); + if (rc) + driver_errf(AR_TOOL, "failed to read archive: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(archive_path))); } cfree_writer_close(out); ctx.file_io->release(ctx.file_io->user, &fd); @@ -198,14 +205,15 @@ static int ar_do_extract(DriverEnv* env, const char* archive_path, int argc, char** argv, int start, int verbose) { CfreeContext ctx; CfreeFileData fd = {0}; - CfreeBytes input; + CfreeSlice input; CfreeArIter* it = NULL; CfreeArMember m; int rc = 0; if (!ar_open_for_read(env, archive_path, &ctx, &fd, &input)) return 1; if (cfree_ar_iter_new(&ctx, &input, &it) != CFREE_OK) { - driver_errf(AR_TOOL, "not an archive: %s", archive_path); + driver_errf(AR_TOOL, "not an archive: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(archive_path))); ctx.file_io->release(ctx.file_io->user, &fd); return 1; } @@ -216,18 +224,22 @@ static int ar_do_extract(DriverEnv* env, const char* archive_path, int argc, if (r != CFREE_ITER_ITEM) break; if (!ar_name_selected(m.name, argc, argv, start)) continue; - if (ctx.file_io->open_writer(ctx.file_io->user, m.name, &out) != CFREE_OK) { - driver_errf(AR_TOOL, "failed to open: %s", m.name); + if (ctx.file_io->open_writer(ctx.file_io->user, m.name.s, &out) != + CFREE_OK) { + driver_errf(AR_TOOL, "failed to open: %.*s", + CFREE_SLICE_ARG(m.name)); rc = 1; continue; } if (m.size) cfree_writer_write(out, m.data, m.size); if (cfree_writer_status(out) != CFREE_OK) { - driver_errf(AR_TOOL, "write failed: %s", m.name); + driver_errf(AR_TOOL, "write failed: %.*s", + CFREE_SLICE_ARG(m.name)); rc = 1; } cfree_writer_close(out); - if (verbose) driver_printf("x - %s\n", m.name); + if (verbose) + driver_printf("x - %.*s\n", CFREE_SLICE_ARG(m.name)); } cfree_ar_iter_free(it); @@ -239,7 +251,7 @@ static int ar_do_print(DriverEnv* env, const char* archive_path, int argc, char** argv, int start, int verbose) { CfreeContext ctx; CfreeFileData fd = {0}; - CfreeBytes input; + CfreeSlice input; CfreeArIter* it = NULL; CfreeArMember m; CfreeWriter* out; @@ -249,7 +261,8 @@ static int ar_do_print(DriverEnv* env, const char* archive_path, int argc, if (!ar_open_for_read(env, archive_path, &ctx, &fd, &input)) return 1; if (cfree_ar_iter_new(&ctx, &input, &it) != CFREE_OK) { - driver_errf(AR_TOOL, "not an archive: %s", archive_path); + driver_errf(AR_TOOL, "not an archive: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(archive_path))); ctx.file_io->release(ctx.file_io->user, &fd); return 1; } @@ -266,7 +279,10 @@ static int ar_do_print(DriverEnv* env, const char* archive_path, int argc, CfreeIterResult r = cfree_ar_iter_next(it, &m); if (r != CFREE_ITER_ITEM) break; if (!ar_name_selected(m.name, argc, argv, start)) continue; - if (header) driver_printf("%s(%s):\n", archive_path, m.name); + if (header) + driver_printf("%.*s(%.*s):\n", + CFREE_SLICE_ARG(cfree_slice_cstr(archive_path)), + CFREE_SLICE_ARG(m.name)); if (m.size) cfree_writer_write(out, m.data, m.size); } if (cfree_writer_status(out) != CFREE_OK) rc = 1; @@ -290,7 +306,7 @@ static int ar_do_write(DriverEnv* env, const char* archive_path, int nmembers, char** member_paths, int has_r, int has_c, int has_s, int has_v) { uint32_t nnew = nmembers > 0 ? (uint32_t)nmembers : 0u; - CfreeBytes* members = NULL; + CfreeArInput* members = NULL; CfreeFileData* new_fds = NULL; size_t members_cap = 0; uint32_t nm = 0; /* count of entries in `members` */ @@ -320,7 +336,7 @@ static int ar_do_write(DriverEnv* env, const char* archive_path, int nmembers, /* `r`: read existing archive (if any) and seed `members` with it. */ if (has_r) { - CfreeBytes input; + CfreeSlice input; CfreeArIter* it = NULL; CfreeArMember m; uint32_t nold = 0; @@ -328,11 +344,11 @@ static int ar_do_write(DriverEnv* env, const char* archive_path, int nmembers, if (ctx.file_io->read_all(ctx.file_io->user, archive_path, &old_fd) == CFREE_OK) { have_old = 1; - input.name = archive_path; input.data = old_fd.data; input.len = old_fd.size; if (cfree_ar_iter_new(&ctx, &input, &it) != CFREE_OK) { - driver_errf(AR_TOOL, "not an archive: %s", archive_path); + driver_errf(AR_TOOL, "not an archive: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(archive_path))); rc = 1; goto done; } @@ -342,18 +358,19 @@ static int ar_do_write(DriverEnv* env, const char* archive_path, int nmembers, CfreeIterResult r = cfree_ar_iter_next(it, &m); if (r != CFREE_ITER_ITEM) break; nold++; - old_name_bytes += driver_strlen(m.name) + 1; + old_name_bytes += m.name.len + 1; } cfree_ar_iter_free(it); it = NULL; } else if (!has_c) { /* POSIX: warn (not an error) when `r` creates a new archive. */ - driver_errf(AR_TOOL, "creating %s", archive_path); + driver_errf(AR_TOOL, "creating %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(archive_path))); } members_cap = (size_t)nold + (size_t)nnew; if (members_cap > 0) { - members = (CfreeBytes*)driver_alloc_zeroed( + members = (CfreeArInput*)driver_alloc_zeroed( env, members_cap * sizeof(*members)); if (!members) { driver_errf(AR_TOOL, "out of memory"); @@ -380,14 +397,15 @@ static int ar_do_write(DriverEnv* env, const char* archive_path, int nmembers, while (nm < nold) { CfreeIterResult r = cfree_ar_iter_next(it, &m); char* dst; - const char* p; + size_t j; if (r != CFREE_ITER_ITEM) break; dst = old_name_storage + cursor; - for (p = m.name; *p; ++p) *dst++ = *p; + for (j = 0; j < m.name.len; ++j) *dst++ = m.name.s[j]; *dst++ = '\0'; - members[nm].name = old_name_storage + cursor; - members[nm].data = m.data; - members[nm].len = m.size; + members[nm].name.s = old_name_storage + cursor; + members[nm].name.len = m.name.len; + members[nm].bytes.data = m.data; + members[nm].bytes.len = m.size; cursor = (size_t)(dst - old_name_storage); nm++; } @@ -397,7 +415,7 @@ static int ar_do_write(DriverEnv* env, const char* archive_path, int nmembers, /* `c`: overwrite. */ members_cap = (size_t)nnew; if (members_cap > 0) { - members = (CfreeBytes*)driver_alloc_zeroed( + members = (CfreeArInput*)driver_alloc_zeroed( env, members_cap * sizeof(*members)); if (!members) { driver_errf(AR_TOOL, "out of memory"); @@ -420,7 +438,8 @@ static int ar_do_write(DriverEnv* env, const char* archive_path, int nmembers, const char* base = driver_basename(path); if (ctx.file_io->read_all(ctx.file_io->user, path, &new_fds[i]) != CFREE_OK) { - driver_errf(AR_TOOL, "failed to read: %s", path); + driver_errf(AR_TOOL, "failed to read: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(path))); rc = 1; goto done; } @@ -430,27 +449,30 @@ static int ar_do_write(DriverEnv* env, const char* archive_path, int nmembers, uint32_t j; int replaced = 0; for (j = 0; j < nm; ++j) { - if (driver_streq(members[j].name, base)) { - members[j].name = base; - members[j].data = new_fds[i].data; - members[j].len = new_fds[i].size; + if (driver_streq(members[j].name.s, base)) { + members[j].name = cfree_slice_cstr(base); + members[j].bytes.data = new_fds[i].data; + members[j].bytes.len = new_fds[i].size; replaced = 1; break; } } if (!replaced) { - members[nm].name = base; - members[nm].data = new_fds[i].data; - members[nm].len = new_fds[i].size; + members[nm].name = cfree_slice_cstr(base); + members[nm].bytes.data = new_fds[i].data; + members[nm].bytes.len = new_fds[i].size; nm++; } - if (has_v) driver_printf("%c - %s\n", replaced ? 'r' : 'a', base); + if (has_v) + driver_printf("%c - %.*s\n", replaced ? 'r' : 'a', + CFREE_SLICE_ARG(cfree_slice_cstr(base))); } else { - members[nm].name = base; - members[nm].data = new_fds[i].data; - members[nm].len = new_fds[i].size; + members[nm].name = cfree_slice_cstr(base); + members[nm].bytes.data = new_fds[i].data; + members[nm].bytes.len = new_fds[i].size; nm++; - if (has_v) driver_printf("a - %s\n", base); + if (has_v) + driver_printf("a - %.*s\n", CFREE_SLICE_ARG(cfree_slice_cstr(base))); } } } @@ -468,16 +490,12 @@ static int ar_do_write(DriverEnv* env, const char* archive_path, int nmembers, goto done; } for (i = 0; i < nm; ++i) { - CfreeBytes in; + CfreeSlice in = members[i].bytes; void* blob = NULL; size_t blob_size = 0; - const char** names = NULL; + const CfreeSlice* names = NULL; uint32_t count = 0; - in.name = members[i].name; - in.data = members[i].data; - in.len = members[i].len; - if (driver_collect_obj_global_syms(env, &ctx, AR_TOOL, &in, &blob, &blob_size, &names, &count) != 0) { rc = 1; @@ -496,7 +514,8 @@ static int ar_do_write(DriverEnv* env, const char* archive_path, int nmembers, if (ctx.file_io->open_writer(ctx.file_io->user, archive_path, &out) != CFREE_OK) { - driver_errf(AR_TOOL, "failed to open: %s", archive_path); + driver_errf(AR_TOOL, "failed to open: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(archive_path))); rc = 1; } else { rc = cfree_ar_write(out, members, nm, &opts) == CFREE_OK ? 0 : 1; @@ -598,12 +617,14 @@ int driver_ar(int argc, char** argv) { { int kinds = !!do_write + !!do_list + !!do_extract + !!do_print; if (kinds == 0) { - driver_errf(AR_TOOL, "no operation in mode: %s", mode); + driver_errf(AR_TOOL, "no operation in mode: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(mode))); ar_usage(); return 2; } if (kinds > 1) { - driver_errf(AR_TOOL, "conflicting operations: %s", mode); + driver_errf(AR_TOOL, "conflicting operations: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(mode))); return 2; } } diff --git a/driver/as.c b/driver/as.c @@ -22,14 +22,16 @@ typedef struct AsOptions { } AsOptions; static void as_usage(void) { - driver_errf(AS_TOOL, "%s", + driver_errf(AS_TOOL, "%.*s", + CFREE_SLICE_ARG(CFREE_SLICE_LIT( "usage: cfree as [-g] [-target TRIPLE] -o out.o input.{s,S}\n" - " cfree as --help for full option reference"); + " cfree as --help for full option reference"))); } void driver_help_as(void) { driver_printf( - "%s", + "%.*s", + CFREE_SLICE_ARG(CFREE_SLICE_LIT( "cfree as — standalone assembler\n" "\n" "USAGE\n" @@ -57,7 +59,7 @@ void driver_help_as(void) { " -h, --help Show this help and exit\n" "\n" "EXIT CODES\n" - " 0 success 1 assemble error 2 bad usage\n"); + " 0 success 1 assemble error 2 bad usage\n"))); } /* Returns 0 on success; non-zero on bad args (already reported). */ @@ -95,14 +97,16 @@ static int as_parse(int argc, char** argv, AsOptions* o, DriverEnv* env, return 1; } if (driver_target_from_triple(argv[i], &o->target) != 0) { - driver_errf(AS_TOOL, "unrecognized target: %s", argv[i]); + driver_errf(AS_TOOL, "unrecognized target: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(argv[i]))); return 1; } continue; } if (a[0] == '-' && a[1] != '\0') { - driver_errf(AS_TOOL, "unknown flag: %s", a); + driver_errf(AS_TOOL, "unknown flag: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(a))); return 1; } @@ -135,8 +139,8 @@ int driver_as(int argc, char** argv) { CfreeWriter* writer = NULL; CfreeWriter* pp_writer = NULL; CfreeFileData src = {0}; - CfreeBytes input; - CfreeBytes asm_input; + CfreeSlice input; + CfreeSlice asm_input; CfreeAsmCompileOptions copts; CfreeAsmCompileOptions zero = {0}; const uint8_t* pp_data; @@ -167,14 +171,16 @@ int driver_as(int argc, char** argv) { ctx = driver_env_to_context(&env); if (ctx.file_io->read_all(ctx.file_io->user, o.source, &src) != CFREE_OK) { - driver_errf(AS_TOOL, "failed to read: %s", o.source); + driver_errf(AS_TOOL, "failed to read: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(o.source))); goto out; } loaded = 1; if (ctx.file_io->open_writer(ctx.file_io->user, o.output_path, &writer) != CFREE_OK) { - driver_errf(AS_TOOL, "failed to open output: %s", o.output_path); + driver_errf(AS_TOOL, "failed to open output: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(o.output_path))); goto out; } @@ -186,7 +192,6 @@ int driver_as(int argc, char** argv) { copts = zero; copts.code.debug_info = o.debug_info; - input.name = o.source; input.data = src.data; input.len = src.size; asm_input = input; @@ -196,10 +201,12 @@ int driver_as(int argc, char** argv) { driver_errf(AS_TOOL, "out of memory"); goto out; } - if (cfree_cpp_preprocess(compiler, &pp, &input, pp_writer) != CFREE_OK) + if (cfree_cpp_preprocess(compiler, &pp, cfree_slice_cstr(o.source), &input, + pp_writer) != CFREE_OK) goto out; if (cfree_writer_status(pp_writer) != CFREE_OK) { - driver_errf(AS_TOOL, "failed to preprocess: %s", o.source); + driver_errf(AS_TOOL, "failed to preprocess: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(o.source))); goto out; } pp_data = cfree_writer_mem_bytes(pp_writer, &pp_len); @@ -219,6 +226,7 @@ int driver_as(int argc, char** argv) { sopts.compile.diagnostics = copts.diagnostics; sopts.compile.language_options = &copts; memset(&sin, 0, sizeof(sin)); + sin.name = cfree_slice_cstr(o.source); sin.bytes = asm_input; sin.lang = CFREE_LANG_ASM; st = cfree_compile_session_new(compiler, &sopts, &session); diff --git a/driver/cc.c b/driver/cc.c @@ -1,4 +1,4 @@ -#include "lang/c/c.h" +#include "c/c.h" #include <cfree/compile.h> #include <cfree/core.h> @@ -209,15 +209,17 @@ typedef struct CcOptions { } CcOptions; static void cc_usage(void) { - driver_errf(CC_TOOL, "%s", + driver_errf(CC_TOOL, "%.*s", + CFREE_SLICE_ARG(CFREE_SLICE_LIT( "usage: cfree cc [-c|-E|-shared] [-o out] " "[options...] inputs...\n" - " cfree cc --help for full option reference"); + " cfree cc --help for full option reference"))); } void driver_help_cc(void) { driver_printf( - "%s", + "%.*s", + CFREE_SLICE_ARG(CFREE_SLICE_LIT( "cfree cc — C compiler driver\n" "\n" "USAGE\n" @@ -232,7 +234,7 @@ void driver_help_cc(void) { " --sysroot DIR / -isysroot DIR hosted SDK/sysroot\n" " --support-dir DIR cfree support root\n" "\n" - "(see source for the full GCC-subset flag reference)\n"); + "(see source for the full GCC-subset flag reference)\n"))); } static int cc_alloc_arrays(CcOptions* o, int argc) { @@ -685,7 +687,8 @@ static int cc_record_build_id(CcOptions* o, const char* val) { o->build_id_mode = CFREE_BUILDID_USER; return 0; } - driver_errf(CC_TOOL, "unknown --build-id value: %s", val); + driver_errf(CC_TOOL, "unknown --build-id value: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(val))); return 1; } @@ -702,12 +705,14 @@ static int cc_record_mcmodel(CcOptions* o, const char* val) { o->target.code_model = CFREE_CM_LARGE; return 0; } - driver_errf(CC_TOOL, "unknown -mcmodel value: %s", val); + driver_errf(CC_TOOL, "unknown -mcmodel value: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(val))); return 1; } static void cc_log_ignored(const char* arg) { - driver_errf(CC_TOOL, "ignoring accepted compatibility flag: %s", arg); + driver_errf(CC_TOOL, "ignoring accepted compatibility flag: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(arg))); } static int cc_set_probe(CcOptions* o, int kind, const char* arg) { @@ -729,17 +734,21 @@ static int cc_run_probe(CcOptions* o) { switch (o->probe_kind) { case CC_PROBE_PRINT_SEARCH_DIRS: - driver_printf("install: %s\n", o->support_dir ? o->support_dir : ""); + driver_printf("install: %.*s\n", CFREE_SLICE_ARG(cfree_slice_cstr( + o->support_dir ? o->support_dir : ""))); driver_printf("programs: =\n"); driver_printf("libraries: ="); - if (o->sysroot) driver_printf("%s/lib", o->sysroot); + if (o->sysroot) + driver_printf("%.*s/lib", CFREE_SLICE_ARG(cfree_slice_cstr(o->sysroot))); driver_printf("\n"); return 0; case CC_PROBE_PRINT_FILE_NAME: - driver_printf("%s\n", o->probe_arg ? o->probe_arg : ""); + driver_printf("%.*s\n", CFREE_SLICE_ARG(cfree_slice_cstr( + o->probe_arg ? o->probe_arg : ""))); return 0; case CC_PROBE_PRINT_PROG_NAME: - driver_printf("%s\n", o->probe_arg ? o->probe_arg : ""); + driver_printf("%.*s\n", CFREE_SLICE_ARG(cfree_slice_cstr( + o->probe_arg ? o->probe_arg : ""))); return 0; case CC_PROBE_PRINT_LIBGCC_FILE_NAME: driver_printf("libcfree_rt.a\n"); @@ -748,10 +757,11 @@ static int cc_run_probe(CcOptions* o) { driver_printf(".\n"); return 0; case CC_PROBE_PRINT_RESOURCE_DIR: - driver_printf("%s\n", o->support_dir ? o->support_dir : ""); + driver_printf("%.*s\n", CFREE_SLICE_ARG(cfree_slice_cstr( + o->support_dir ? o->support_dir : ""))); return 0; case CC_PROBE_DUMPMACHINE: - driver_printf("%s\n", triple); + driver_printf("%.*s\n", CFREE_SLICE_ARG(cfree_slice_cstr(triple))); return 0; case CC_PROBE_DUMPVERSION: driver_printf("0\n"); @@ -778,7 +788,7 @@ static int cc_record_stdin(CcOptions* o) { return 1; } in = &o->source_memory[o->nsource_memory++]; - in->bytes.name = "<stdin>"; + in->name = CFREE_SLICE_LIT("<stdin>"); in->bytes.data = o->stdin_buf; in->bytes.len = o->stdin_size; in->lang = CFREE_LANG_C; @@ -827,7 +837,8 @@ static int cc_classify_positional(CcOptions* o, const char* a, cc_push_link_item(o, CC_LINK_DSO, o->ndsos - 1u); return 0; } - driver_errf(CC_TOOL, "input does not have a recognized suffix: %s", a); + driver_errf(CC_TOOL, "input does not have a recognized suffix: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(a))); return 1; } @@ -847,7 +858,8 @@ static int cc_resolve_pending_libs(CcOptions* o) { if (driver_lib_resolve_for_os(o->env, pl->name, mode, resolve_os, o->lib_search_paths, o->nlib_search_paths, &p, &sz, &kind) != 0) { - driver_errf(CC_TOOL, "library not found: -l%s", pl->name); + driver_errf(CC_TOOL, "library not found: -l%.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(pl->name))); return 1; } if (kind == LIB_RESOLVE_KIND_SHARED || kind == LIB_RESOLVE_KIND_TBD) { @@ -924,7 +936,8 @@ static int cc_apply_hosted_profile(CcOptions* o) { static int cc_apply_env(CcOptions* o) { const char* sde = driver_getenv("SOURCE_DATE_EPOCH"); if (sde && cc_parse_u64(sde, &o->epoch) != 0) { - driver_errf(CC_TOOL, "invalid SOURCE_DATE_EPOCH: %s", sde); + driver_errf(CC_TOOL, "invalid SOURCE_DATE_EPOCH: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(sde))); return 1; } return 0; @@ -1115,7 +1128,8 @@ static int cc_parse(int argc, char** argv, CcOptions* o) { } if (driver_streq(a, "-isysroot") || driver_streq(a, "--sysroot")) { if (++i >= argc) { - driver_errf(CC_TOOL, "%s requires an argument", a); + driver_errf(CC_TOOL, "%.*s requires an argument", + CFREE_SLICE_ARG(cfree_slice_cstr(a))); return 1; } o->sysroot = argv[i]; @@ -1176,7 +1190,8 @@ static int cc_parse(int argc, char** argv, CcOptions* o) { } if (driver_streq(a, "-include")) { if (++i >= argc) { - driver_errf(CC_TOOL, "%s requires an argument", a); + driver_errf(CC_TOOL, "%.*s requires an argument", + CFREE_SLICE_ARG(cfree_slice_cstr(a))); return 1; } cc_log_ignored(a); @@ -1332,7 +1347,8 @@ static int cc_parse(int argc, char** argv, CcOptions* o) { return 1; } if (driver_target_from_triple(argv[i], &o->target) != 0) { - driver_errf(CC_TOOL, "unrecognized target triple: %s", argv[i]); + driver_errf(CC_TOOL, "unrecognized target triple: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(argv[i]))); return 1; } o->target_set = 1; @@ -1340,7 +1356,8 @@ static int cc_parse(int argc, char** argv, CcOptions* o) { } if (driver_strneq(a, "--target=", 9)) { if (driver_target_from_triple(a + 9, &o->target) != 0) { - driver_errf(CC_TOOL, "unrecognized target triple: %s", a + 9); + driver_errf(CC_TOOL, "unrecognized target triple: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(a + 9))); return 1; } o->target_set = 1; @@ -1352,7 +1369,8 @@ static int cc_parse(int argc, char** argv, CcOptions* o) { return 1; } if (driver_target_from_triple(argv[i], &o->target) != 0) { - driver_errf(CC_TOOL, "unrecognized target triple: %s", argv[i]); + driver_errf(CC_TOOL, "unrecognized target triple: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(argv[i]))); return 1; } o->target_set = 1; @@ -1385,7 +1403,8 @@ static int cc_parse(int argc, char** argv, CcOptions* o) { continue; } { - driver_errf(CC_TOOL, "unsupported -x language: %s", argv[i]); + driver_errf(CC_TOOL, "unsupported -x language: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(argv[i]))); return 1; } } @@ -1449,7 +1468,8 @@ static int cc_parse(int argc, char** argv, CcOptions* o) { } if (driver_streq(a, "-MT") || driver_streq(a, "-MQ")) { if (++i >= argc) { - driver_errf(CC_TOOL, "%s requires an argument", a); + driver_errf(CC_TOOL, "%.*s requires an argument", + CFREE_SLICE_ARG(cfree_slice_cstr(a))); return 1; } o->dep_targets[o->ndep_targets++] = argv[i]; @@ -1467,7 +1487,8 @@ static int cc_parse(int argc, char** argv, CcOptions* o) { continue; } if (a[0] == '-' && a[1] != '\0') { - driver_errf(CC_TOOL, "unknown flag: %s", a); + driver_errf(CC_TOOL, "unknown flag: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(a))); return 1; } @@ -1568,10 +1589,12 @@ static int cc_parse(int argc, char** argv, CcOptions* o) { return 0; } -/* Borrow the single source as a CfreeBytes. `*loaded` is set nonzero only +static const char* cc_primary_source_name(const CcOptions* o); + +/* Borrow the single source as a CfreeSlice. `*loaded` is set nonzero only * when the file was opened via file_io and must be released. */ static int cc_load_single_source(const CfreeContext* ctx, const CcOptions* o, - CfreeBytes* in, CfreeFileData* fd, + CfreeSlice* in, CfreeFileData* fd, int* loaded) { *loaded = 0; if (o->nsource_memory == 1) { @@ -1580,11 +1603,11 @@ static int cc_load_single_source(const CfreeContext* ctx, const CcOptions* o, } if (ctx->file_io->read_all(ctx->file_io->user, o->source_files[0], fd) != CFREE_OK) { - driver_errf(CC_TOOL, "failed to read: %s", o->source_files[0]); + driver_errf(CC_TOOL, "failed to read: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(o->source_files[0]))); return 1; } *loaded = 1; - in->name = o->source_files[0]; in->data = fd->data; in->len = fd->size; return 0; @@ -1596,7 +1619,7 @@ static int cc_preprocess(DriverEnv* env, const CcOptions* o, CfreeCompiler* compiler = NULL; CfreeWriter* writer = NULL; CfreeFileData fd = {0}; - CfreeBytes input = {0}; + CfreeSlice input = {0}; int rc = 1; int loaded = 0; @@ -1605,7 +1628,8 @@ static int cc_preprocess(DriverEnv* env, const CcOptions* o, if (o->output_path) { if (ctx.file_io->open_writer(ctx.file_io->user, o->output_path, &writer) != CFREE_OK) { - driver_errf(CC_TOOL, "failed to open output: %s", o->output_path); + driver_errf(CC_TOOL, "failed to open output: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(o->output_path))); goto out; } } else { @@ -1621,7 +1645,9 @@ static int cc_preprocess(DriverEnv* env, const CcOptions* o, goto out; } - rc = cfree_cpp_preprocess(compiler, pp_opts, &input, writer) == CFREE_OK + rc = cfree_cpp_preprocess(compiler, pp_opts, + cfree_slice_cstr(cc_primary_source_name(o)), &input, + writer) == CFREE_OK ? 0 : 1; @@ -1849,7 +1875,7 @@ static int cc_dep_collect(DriverEnv* env, CfreeCompiler* compiler, CfreeIterResult r = cfree_dep_iter_next(it, &e); if (r != CFREE_ITER_ITEM) break; if (system_filter && e.from_system_path) continue; - if (cc_dep_list_push(env, list, e.included_name) != 0) { + if (cc_dep_list_push(env, list, e.included_name.s) != 0) { cfree_dep_iter_free(it); return 1; } @@ -1911,7 +1937,7 @@ static CfreeWriter* cc_dep_open_writer(DriverEnv* env, const CfreeContext* ctx, } static const char* cc_primary_source_name(const CcOptions* o) { - if (o->nsource_memory == 1) return o->source_memory[0].bytes.name; + if (o->nsource_memory == 1) return o->source_memory[0].name.s; return o->source_files[0]; } @@ -1950,8 +1976,9 @@ static int cc_dep_finish(DriverEnv* env, const CfreeContext* ctx, dep_w = cc_dep_open_writer(env, ctx, o, &owned_path, &owned_size); if (!dep_w) { driver_errf( - CC_TOOL, "failed to open dep output: %s", - o->dep_file ? o->dep_file : (owned_path ? owned_path : "<stdout>")); + CC_TOOL, "failed to open dep output: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr( + o->dep_file ? o->dep_file : (owned_path ? owned_path : "<stdout>")))); goto out; } @@ -1988,7 +2015,7 @@ static int cc_run_deps_only(DriverEnv* env, const CcOptions* o, CfreeCompiler* compiler = NULL; CfreeWriter* discard = NULL; CfreeFileData fd = {0}; - CfreeBytes input = {0}; + CfreeSlice input = {0}; int loaded = 0; int rc = 1; @@ -2005,7 +2032,10 @@ static int cc_run_deps_only(DriverEnv* env, const CcOptions* o, goto out; } - if (cfree_cpp_preprocess(compiler, pp, &input, discard) != CFREE_OK) goto out; + if (cfree_cpp_preprocess(compiler, pp, + cfree_slice_cstr(cc_primary_source_name(o)), &input, + discard) != CFREE_OK) + goto out; rc = cc_dep_finish(env, &ctx, compiler, o); @@ -2019,7 +2049,8 @@ out: static CfreeStatus cc_compile_source_obj(CfreeCompiler* compiler, CfreeLanguage lang, const CfreeCCompileOptions* copts, - const CfreeBytes* input, + CfreeSlice name, + const CfreeSlice* input, CfreeObjBuilder** out) { CfreeCompileSessionOptions sopts; CfreeCompileSession* session = NULL; @@ -2040,6 +2071,7 @@ static CfreeStatus cc_compile_source_obj(CfreeCompiler* compiler, sopts.compile.language_options = copts; } memset(&sin, 0, sizeof(sin)); + sin.name = name; sin.bytes = *input; sin.lang = lang; st = cfree_compile_session_new(compiler, &sopts, &session); @@ -2051,10 +2083,12 @@ static CfreeStatus cc_compile_source_obj(CfreeCompiler* compiler, static CfreeStatus cc_compile_source_emit(CfreeCompiler* compiler, CfreeLanguage lang, const CfreeCCompileOptions* copts, - const CfreeBytes* input, + CfreeSlice name, + const CfreeSlice* input, CfreeWriter* out) { CfreeObjBuilder* ob = NULL; - CfreeStatus st = cc_compile_source_obj(compiler, lang, copts, input, &ob); + CfreeStatus st = + cc_compile_source_obj(compiler, lang, copts, name, input, &ob); if (st == CFREE_OK && !copts->code.emit_c_source) st = cfree_obj_builder_emit(ob, out); cfree_obj_builder_free(ob); @@ -2068,7 +2102,7 @@ static int cc_run_compile_one(DriverEnv* env, const CcOptions* o, CfreeCompiler* compiler = NULL; CfreeWriter* obj_w = NULL; CfreeFileData fd = {0}; - CfreeBytes input = {0}; + CfreeSlice input = {0}; CfreeCCompileOptions copts; int loaded = 0; int rc = 1; @@ -2078,18 +2112,19 @@ static int cc_run_compile_one(DriverEnv* env, const CcOptions* o, } else { if (ctx.file_io->read_all(ctx.file_io->user, o->source_files[index], &fd) != CFREE_OK) { - driver_errf(CC_TOOL, "failed to read: %s", o->source_files[index]); + driver_errf(CC_TOOL, "failed to read: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(o->source_files[index]))); goto out; } loaded = 1; - input.name = o->source_files[index]; input.data = fd.data; input.len = fd.size; } if (ctx.file_io->open_writer(ctx.file_io->user, out_path, &obj_w) != CFREE_OK) { - driver_errf(CC_TOOL, "failed to open output: %s", out_path); + driver_errf(CC_TOOL, "failed to open output: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(out_path))); goto out; } @@ -2111,8 +2146,10 @@ static int cc_run_compile_one(DriverEnv* env, const CcOptions* o, ? o->source_memory[index].lang : cc_resolve_lang(compiler, o->source_files[index], o->source_langs[index]); + CfreeSlice in_name = is_memory ? o->source_memory[index].name + : cfree_slice_cstr(o->source_files[index]); CfreeStatus st; - st = cc_compile_source_emit(compiler, lang, &copts, &input, obj_w); + st = cc_compile_source_emit(compiler, lang, &copts, in_name, &input, obj_w); if (st != CFREE_OK) goto out; } @@ -2172,10 +2209,10 @@ static int cc_run_link_exe(DriverEnv* env, const CcOptions* o, DriverLoad* arch_lf = NULL; DriverLoad script_lf = {0}; DriverLoad* dso_lf = NULL; - CfreeBytes* src_bytes = NULL; - CfreeBytes* obj_in = NULL; + CfreeSlice* src_bytes = NULL; + CfreeSlice* obj_in = NULL; CfreeLinkArchiveInput* arch_in = NULL; - CfreeBytes* dso_in = NULL; + CfreeSlice* dso_in = NULL; CfreeLinkInputOrder* order = NULL; CfreeObjBuilder** objs = NULL; CfreeLinkScript* script = NULL; @@ -2263,7 +2300,7 @@ static int cc_run_link_exe(DriverEnv* env, const CcOptions* o, } if (o->linker_script) { - CfreeBytes dummy; + CfreeSlice dummy; if (driver_load_bytes(io, CC_TOOL, o->linker_script, &script_lf, &dummy) != 0) goto out; @@ -2275,8 +2312,9 @@ static int cc_run_link_exe(DriverEnv* env, const CcOptions* o, } if (script_lf.loaded) { - if (cfree_link_script_parse(&ctx, (const char*)script_lf.fd.data, - script_lf.fd.size, &script) != CFREE_OK) + CfreeSlice script_text = {.s = (const char*)script_lf.fd.data, + .len = script_lf.fd.size}; + if (cfree_link_script_parse(&ctx, script_text, &script) != CFREE_OK) goto out; } @@ -2285,29 +2323,43 @@ static int cc_run_link_exe(DriverEnv* env, const CcOptions* o, CfreeLanguage lang = cc_resolve_lang(compiler, o->source_files[i], o->source_langs[i]); CfreeStatus st; - st = cc_compile_source_obj(compiler, lang, &copts, &src_bytes[i], &objs[i]); + st = cc_compile_source_obj(compiler, lang, &copts, + cfree_slice_cstr(o->source_files[i]), + &src_bytes[i], &objs[i]); if (st != CFREE_OK) goto out; } for (i = 0; i < o->nsource_memory; ++i) { CfreeStatus st; st = cc_compile_source_obj(compiler, o->source_memory[i].lang, &copts, + o->source_memory[i].name, &o->source_memory[i].bytes, &objs[o->nsource_files + i]); if (st != CFREE_OK) goto out; } if (io->open_writer(io->user, o->output_path, &out_w) != CFREE_OK) { - driver_errf(CC_TOOL, "failed to open output: %s", o->output_path); + driver_errf(CC_TOOL, "failed to open output: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(o->output_path))); goto out; } { CfreeLinkSessionOptions lopts; CfreeStatus st; + CfreeSlice* rpath_slices = NULL; + if (o->nrpaths) { + rpath_slices = driver_alloc_zeroed(env, o->nrpaths * sizeof(*rpath_slices)); + if (!rpath_slices) { + driver_errf(CC_TOOL, "out of memory"); + goto out; + } + for (i = 0; i < o->nrpaths; ++i) + rpath_slices[i] = cfree_slice_cstr(o->rpaths[i]); + } memset(&lopts, 0, sizeof(lopts)); lopts.output_kind = o->shared ? CFREE_LINK_OUTPUT_SHARED : CFREE_LINK_OUTPUT_EXE; - lopts.entry = o->entry; + lopts.entry = cfree_slice_cstr(o->entry); lopts.linker_script = script; lopts.build_id_mode = o->build_id_mode; lopts.build_id_bytes = o->build_id_bytes; @@ -2315,13 +2367,13 @@ static int cc_run_link_exe(DriverEnv* env, const CcOptions* o, lopts.gc_sections = o->gc_sections; lopts.pie = o->pie; lopts.pe_subsystem = o->pe_subsystem; - lopts.interp_path = o->interp_path; - lopts.soname = o->soname; + lopts.interp_path = cfree_slice_cstr(o->interp_path); + lopts.soname = cfree_slice_cstr(o->soname); if (o->new_dtags) { - lopts.runpaths = o->rpaths; + lopts.runpaths = rpath_slices; lopts.nrunpaths = o->nrpaths; } else { - lopts.rpaths = o->rpaths; + lopts.rpaths = rpath_slices; lopts.nrpaths = o->nrpaths; } lopts.allow_undefined = 1; @@ -2340,20 +2392,25 @@ static int cc_run_link_exe(DriverEnv* env, const CcOptions* o, link, objs[o->nsource_files + item->index]); break; case CC_LINK_OBJECT: - st = cfree_link_session_add_obj_bytes(link, &obj_in[item->index]); + st = cfree_link_session_add_obj_bytes( + link, cfree_slice_cstr(o->object_files[item->index]), + &obj_in[item->index]); break; case CC_LINK_ARCHIVE: st = cfree_link_session_add_archive_bytes(link, &arch_in[item->index]); break; case CC_LINK_DSO: - st = cfree_link_session_add_dso_bytes(link, &dso_in[item->index]); + st = cfree_link_session_add_dso_bytes( + link, cfree_slice_cstr(o->dsos[item->index].path), + &dso_in[item->index]); break; case CC_LINK_LIB: { const CcPendingLib* pl = &o->pending_libs[item->index]; if (pl->resolved_kind == CC_LINK_DSO) { st = cfree_link_session_add_dso_bytes( - link, &dso_in[pl->resolved_index]); + link, cfree_slice_cstr(o->dsos[pl->resolved_index].path), + &dso_in[pl->resolved_index]); } else { st = cfree_link_session_add_archive_bytes( link, &arch_in[pl->resolved_index]); @@ -2366,11 +2423,13 @@ static int cc_run_link_exe(DriverEnv* env, const CcOptions* o, for (i = 0; i < nsrc && st == CFREE_OK; ++i) st = cfree_link_session_add_obj(link, objs[i]); for (i = 0; i < o->nobject_files && st == CFREE_OK; ++i) - st = cfree_link_session_add_obj_bytes(link, &obj_in[i]); + st = cfree_link_session_add_obj_bytes( + link, cfree_slice_cstr(o->object_files[i]), &obj_in[i]); for (i = 0; i < o->narchives && st == CFREE_OK; ++i) st = cfree_link_session_add_archive_bytes(link, &arch_in[i]); for (i = 0; i < o->ndsos && st == CFREE_OK; ++i) - st = cfree_link_session_add_dso_bytes(link, &dso_in[i]); + st = cfree_link_session_add_dso_bytes( + link, cfree_slice_cstr(o->dsos[i].path), &dso_in[i]); } if (st == CFREE_OK) st = cfree_link_session_emit(link, out_w); rc = st == CFREE_OK ? 0 : 1; @@ -2381,7 +2440,8 @@ out: cfree_link_session_free(link); if (rc == 0 && o->output_path) { if (driver_mark_executable_output(o->output_path) != 0) { - driver_errf(CC_TOOL, "failed to set executable mode: %s", o->output_path); + driver_errf(CC_TOOL, "failed to set executable mode: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(o->output_path))); rc = 1; } } diff --git a/driver/cflags.c b/driver/cflags.c @@ -62,11 +62,11 @@ static int cflags_record_define(DriverCflags* cf, DriverEnv* env, name[n] = '\0'; cf->_owned_define_names[cf->ndefines] = name; cf->_owned_define_name_sizes[cf->ndefines] = bytes; - d->name = name; - d->body = eq + 1; + d->name = (CfreeSlice){ .s = name, .len = n }; + d->body = cfree_slice_cstr(eq + 1); } else { - d->name = arg; - d->body = NULL; + d->name = cfree_slice_cstr(arg); + d->body = CFREE_SLICE_NULL; } cf->ndefines++; return 0; @@ -84,7 +84,8 @@ static const char* cflags_pull_value(const char* tool, int argc, char** argv, const char* a = argv[*i]; if (a[prefix_len]) return a + prefix_len; if (++(*i) >= argc) { - driver_errf(tool, "%s requires an argument", flag_label); + driver_errf(tool, "%.*s requires an argument", + CFREE_SLICE_ARG(cfree_slice_cstr(flag_label))); return NULL; } return argv[*i]; @@ -138,7 +139,7 @@ int driver_cflags_try_consume(DriverCflags* cf, DriverEnv* env, if (driver_strneq(a, "-U", 2)) { const char* arg = cflags_pull_value(tool, argc, argv, i, 2, "-U"); if (!arg) return -1; - cf->undefines[cf->nundefines++] = arg; + cf->undefines[cf->nundefines++] = cfree_slice_cstr(arg); return 1; } diff --git a/driver/cflags.h b/driver/cflags.h @@ -33,7 +33,7 @@ typedef struct DriverCflags { uint32_t nsystem_include_dirs; CfreeDefine* defines; uint32_t ndefines; - const char** undefines; + CfreeSlice* undefines; uint32_t nundefines; /* Internal storage for the names of `-Dname=body` defines we had to diff --git a/driver/cpp.c b/driver/cpp.c @@ -35,7 +35,8 @@ typedef struct CppOptions { void driver_help_cpp(void) { driver_printf( - "%s", + "%.*s", + CFREE_SLICE_ARG(CFREE_SLICE_LIT( "cfree cpp — standalone C preprocessor\n" "\n" "USAGE\n" @@ -60,13 +61,14 @@ void driver_help_cpp(void) { "\n" "EXIT CODES\n" " 0 success 1 preprocess / I/O error 2 bad " - "usage\n"); + "usage\n"))); } static void cpp_usage(void) { - driver_errf(CPP_TOOL, "%s", + driver_errf(CPP_TOOL, "%.*s", + CFREE_SLICE_ARG(CFREE_SLICE_LIT( "usage: cfree cpp [options] INPUT.c\n" - " cfree cpp --help for full option reference"); + " cfree cpp --help for full option reference"))); } static int cpp_parse(int argc, char** argv, CppOptions* o, DriverEnv* env, @@ -98,7 +100,8 @@ static int cpp_parse(int argc, char** argv, CppOptions* o, DriverEnv* env, return 1; } if (driver_target_from_triple(argv[i], &o->target) != 0) { - driver_errf(CPP_TOOL, "unrecognized target: %s", argv[i]); + driver_errf(CPP_TOOL, "unrecognized target: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(argv[i]))); return 1; } continue; @@ -114,7 +117,8 @@ static int cpp_parse(int argc, char** argv, CppOptions* o, DriverEnv* env, } if (a[0] == '-' && a[1] != '\0') { - driver_errf(CPP_TOOL, "unknown flag: %s", a); + driver_errf(CPP_TOOL, "unknown flag: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(a))); return 1; } @@ -142,7 +146,8 @@ int driver_cpp(int argc, char** argv) { CfreeCompiler* compiler = NULL; CfreeWriter* writer = NULL; CfreeFileData src = {0}; - CfreeBytes input; + CfreeSlice input; + CfreeSlice input_name = CFREE_SLICE_NULL; uint8_t* stdin_buf = NULL; size_t stdin_size = 0; int rc = 1; @@ -175,17 +180,18 @@ int driver_cpp(int argc, char** argv) { driver_errf(CPP_TOOL, "failed to read stdin"); goto out; } - input.name = "<stdin>"; + input_name = CFREE_SLICE_LIT("<stdin>"); input.data = stdin_buf; input.len = stdin_size; } else { if (ctx.file_io->read_all(ctx.file_io->user, o.source_path, &src) != CFREE_OK) { - driver_errf(CPP_TOOL, "failed to read: %s", o.source_path); + driver_errf(CPP_TOOL, "failed to read: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(o.source_path))); goto out; } loaded = 1; - input.name = o.source_path; + input_name = cfree_slice_cstr(o.source_path); input.data = src.data; input.len = src.size; } @@ -193,7 +199,8 @@ int driver_cpp(int argc, char** argv) { if (o.output_path) { if (ctx.file_io->open_writer(ctx.file_io->user, o.output_path, &writer) != CFREE_OK) { - driver_errf(CPP_TOOL, "failed to open output: %s", o.output_path); + driver_errf(CPP_TOOL, "failed to open output: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(o.output_path))); goto out; } } else { @@ -210,7 +217,10 @@ int driver_cpp(int argc, char** argv) { } rc = - cfree_cpp_preprocess(compiler, &pp, &input, writer) == CFREE_OK ? 0 : 1; + cfree_cpp_preprocess(compiler, &pp, input_name, &input, writer) == + CFREE_OK + ? 0 + : 1; out: if (compiler) driver_compiler_free(compiler); diff --git a/driver/dbg.c b/driver/dbg.c @@ -66,7 +66,8 @@ typedef struct DbgOpts { void driver_help_dbg(void) { driver_printf( - "%s", + "%.*s", + CFREE_SLICE_ARG(CFREE_SLICE_LIT( "cfree dbg — interactive JIT debugger\n" "\n" "USAGE\n" @@ -139,7 +140,7 @@ void driver_help_dbg(void) { "\n" "EXIT CODES\n" " 0 clean exit 1 compile/link or session error 2 bad " - "usage\n"); + "usage\n"))); } static int dbg_alloc_arrays(DbgOpts* o, int argc) { @@ -182,7 +183,8 @@ static int dbg_parse_language_name(const char* name, CfreeLanguage* out) { static int dbg_set_default_language(DbgOpts* o, const char* name) { CfreeLanguage lang = CFREE_LANG_COUNT; if (!dbg_parse_language_name(name, &lang)) { - driver_errf(DBG_TOOL, "unsupported language: %s", name ? name : ""); + driver_errf(DBG_TOOL, "unsupported language: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(name))); return 1; } o->default_lang = lang; @@ -243,7 +245,8 @@ static int dbg_parse(int argc, char** argv, DbgOpts* o) { if (driver_streq(a, "-x") || driver_streq(a, "--language") || driver_streq(a, "--lang")) { if (++i >= argc) { - driver_errf(DBG_TOOL, "%s requires an argument", a); + driver_errf(DBG_TOOL, "%.*s requires an argument", + CFREE_SLICE_ARG(cfree_slice_cstr(a))); return 1; } if (dbg_set_default_language(o, argv[i]) != 0) return 1; @@ -259,7 +262,8 @@ static int dbg_parse(int argc, char** argv, DbgOpts* o) { } if (a[0] == '-' && a[1] != '\0') { - driver_errf(DBG_TOOL, "unknown flag: %s", a); + driver_errf(DBG_TOOL, "unknown flag: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(a))); return 1; } @@ -267,7 +271,8 @@ static int dbg_parse(int argc, char** argv, DbgOpts* o) { int r = driver_inputs_classify(&o->inputs, a); if (r < 0) return 1; if (r == 0) { - driver_errf(DBG_TOOL, "input does not have a recognized suffix: %s", a); + driver_errf(DBG_TOOL, "input does not have a recognized suffix: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(a))); return 1; } } @@ -599,7 +604,8 @@ static int dbg_resolve_loc(DbgState* s, const char* spec, BpKind* kind_out, uint64_t pc; if (file_n == 0) { - driver_errf(DBG_TOOL, "empty file in '%s'", spec); + driver_errf(DBG_TOOL, "empty file in '%.*s'", + CFREE_SLICE_ARG(cfree_slice_cstr(spec))); return 1; } file = dbg_dup(s->env, spec, file_n, &file_size); @@ -609,20 +615,23 @@ static int dbg_resolve_loc(DbgState* s, const char* spec, BpKind* kind_out, } used = dbg_parse_uint(colon + 1, &line64); if (!used || colon[1 + used] != '\0') { - driver_errf(DBG_TOOL, "expected file.c:LINE, got '%s'", spec); + driver_errf(DBG_TOOL, "expected file.c:LINE, got '%.*s'", + CFREE_SLICE_ARG(cfree_slice_cstr(spec))); driver_free(s->env, file, file_size); return 1; } if (!s->dwarf) { - driver_errf(DBG_TOOL, "no DWARF: cannot resolve %s", spec); + driver_errf(DBG_TOOL, "no DWARF: cannot resolve %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(spec))); driver_free(s->env, file, file_size); return 1; } { - CfreeStatus rc = - cfree_dwarf_line_to_addr(s->dwarf, file, (uint32_t)line64, &pc); + CfreeStatus rc = cfree_dwarf_line_to_addr( + s->dwarf, cfree_slice_cstr(file), (uint32_t)line64, &pc); if (rc == CFREE_NOT_FOUND) { - driver_errf(DBG_TOOL, "no line %u in %s", (uint32_t)line64, file); + driver_errf(DBG_TOOL, "no line %u in %.*s", (uint32_t)line64, + CFREE_SLICE_ARG(cfree_slice_cstr(file))); driver_free(s->env, file, file_size); return 1; } @@ -630,22 +639,25 @@ static int dbg_resolve_loc(DbgState* s, const char* spec, BpKind* kind_out, CfreeDwarfLineMatch cands[8]; uint32_t n = 0; uint32_t k; - cfree_dwarf_line_to_addr_all(s->dwarf, file, (uint32_t)line64, cands, - 8u, &n); - driver_errf(DBG_TOOL, "ambiguous: %s:%u matches %u files", file, - (uint32_t)line64, (unsigned)n); + cfree_dwarf_line_to_addr_all(s->dwarf, cfree_slice_cstr(file), + (uint32_t)line64, cands, 8u, &n); + driver_errf(DBG_TOOL, "ambiguous: %.*s:%u matches %u files", + CFREE_SLICE_ARG(cfree_slice_cstr(file)), (uint32_t)line64, + (unsigned)n); for (k = 0; k < n && k < 8u; ++k) { - driver_errf(DBG_TOOL, " %s (0x%llx)", cands[k].file, + driver_errf(DBG_TOOL, " %.*s (0x%llx)", + CFREE_SLICE_ARG(cands[k].file), (unsigned long long)cands[k].pc); } if (n > 8u) driver_errf(DBG_TOOL, " ... and %u more", n - 8u); - driver_errf(DBG_TOOL, "use a longer path suffix (e.g. b dir/%s:%u)", - file, (uint32_t)line64); + driver_errf(DBG_TOOL, "use a longer path suffix (e.g. b dir/%.*s:%u)", + CFREE_SLICE_ARG(cfree_slice_cstr(file)), (uint32_t)line64); driver_free(s->env, file, file_size); return 1; } if (rc != CFREE_OK) { - driver_errf(DBG_TOOL, "no line entry for %s", spec); + driver_errf(DBG_TOOL, "no line entry for %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(spec))); driver_free(s->env, file, file_size); return 1; } @@ -662,7 +674,8 @@ static int dbg_resolve_loc(DbgState* s, const char* spec, BpKind* kind_out, uint64_t v; size_t used = dbg_parse_uint(spec, &v); if (!used || spec[used] != '\0') { - driver_errf(DBG_TOOL, "trailing junk in address '%s'", spec); + driver_errf(DBG_TOOL, "trailing junk in address '%.*s'", + CFREE_SLICE_ARG(cfree_slice_cstr(spec))); return 1; } *kind_out = BP_ADDR; @@ -680,7 +693,8 @@ static int dbg_resolve_loc(DbgState* s, const char* spec, BpKind* kind_out, uint64_t off = 0; if (name_n == 0) { - driver_errf(DBG_TOOL, "empty symbol in '%s'", spec); + driver_errf(DBG_TOOL, "empty symbol in '%.*s'", + CFREE_SLICE_ARG(cfree_slice_cstr(spec))); return 1; } name = dbg_dup(s->env, spec, name_n, &name_size); @@ -688,9 +702,10 @@ static int dbg_resolve_loc(DbgState* s, const char* spec, BpKind* kind_out, driver_errf(DBG_TOOL, "out of memory"); return 1; } - resolved = cfree_jit_lookup(s->jit, name); + resolved = cfree_jit_lookup(s->jit, cfree_slice_cstr(name)); if (!resolved) { - driver_errf(DBG_TOOL, "symbol not found: %s", name); + driver_errf(DBG_TOOL, "symbol not found: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(name))); driver_free(s->env, name, name_size); return 1; } @@ -699,7 +714,8 @@ static int dbg_resolve_loc(DbgState* s, const char* spec, BpKind* kind_out, if (plus) { size_t used = dbg_parse_uint(plus + 1, &off); if (!used || plus[1 + used] != '\0') { - driver_errf(DBG_TOOL, "bad offset in '%s'", spec); + driver_errf(DBG_TOOL, "bad offset in '%.*s'", + CFREE_SLICE_ARG(cfree_slice_cstr(spec))); return 1; } } @@ -725,24 +741,25 @@ static int dbg_resolve_loc(DbgState* s, const char* spec, BpKind* kind_out, * ============================================================ */ static void dbg_print_pc(DbgState* s, uint64_t pc) { - const char* sym = NULL; + CfreeSlice sym = CFREE_SLICE_NULL; uint64_t off = 0; - const char* file = NULL; + CfreeSlice file = CFREE_SLICE_NULL; uint32_t line = 0; uint32_t col = 0; driver_printf("0x%llx", (unsigned long long)pc); - if (cfree_jit_addr_to_sym(s->jit, pc, &sym, &off) == CFREE_OK && sym) { + if (cfree_jit_addr_to_sym(s->jit, pc, &sym, &off) == CFREE_OK && sym.s) { if (off) - driver_printf(" <%s+0x%llx>", sym, (unsigned long long)off); + driver_printf(" <%.*s+0x%llx>", CFREE_SLICE_ARG(sym), + (unsigned long long)off); else - driver_printf(" <%s>", sym); + driver_printf(" <%.*s>", CFREE_SLICE_ARG(sym)); } if (s->dwarf && cfree_dwarf_addr_to_line(s->dwarf, dbg_pc_rt_to_img(s, pc), &file, &line, &col) == CFREE_OK && - file) { - driver_printf(" at %s:%u", file, line); + file.s) { + driver_printf(" at %.*s:%u", CFREE_SLICE_ARG(file), line); if (col) driver_printf(":%u", col); } } @@ -759,7 +776,8 @@ static void dbg_render_stop(DbgState* s, const CfreeStopInfo* st) { } } if (b) - driver_printf("Breakpoint %d (%s) hit at ", b->id, b->spec); + driver_printf("Breakpoint %d (%.*s) hit at ", b->id, + CFREE_SLICE_ARG(cfree_slice_cstr(b->spec))); else driver_printf("Breakpoint hit at "); dbg_print_pc(s, st->regs.pc); @@ -819,9 +837,10 @@ static int dbg_drive(DbgState* s, DbgRunMode mode) { driver_errf(DBG_TOOL, "no entry symbol configured"); return 1; } - s->entry_addr = cfree_jit_lookup(s->jit, s->entry_name); + s->entry_addr = cfree_jit_lookup(s->jit, cfree_slice_cstr(s->entry_name)); if (!s->entry_addr) { - driver_errf(DBG_TOOL, "entry symbol not found: %s", s->entry_name); + driver_errf(DBG_TOOL, "entry symbol not found: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(s->entry_name))); return 1; } } @@ -862,9 +881,11 @@ static int dbg_drive(DbgState* s, DbgRunMode mode) { if (rc != CFREE_OK) { driver_errf(DBG_TOOL, - "session %s failed (st=%d) — " + "session %.*s failed (st=%d) — " "JIT session implementation pending", - mode == RUN_FRESH ? "call" : "resume", (int)rc); + CFREE_SLICE_ARG(cfree_slice_cstr(mode == RUN_FRESH ? "call" + : "resume")), + (int)rc); return 1; } @@ -917,25 +938,28 @@ static void dbg_cmd_bt(DbgState* s) { driver_printf("0x%llx", (unsigned long long)frame.pc); { - const char* sym = NULL; + CfreeSlice sym = CFREE_SLICE_NULL; uint64_t off = 0; if (cfree_jit_addr_to_sym(s->jit, frame.pc, &sym, &off) == CFREE_OK && - sym) { + sym.s) { if (off) - driver_printf(" <%s+0x%llx>", sym, (unsigned long long)off); + driver_printf(" <%.*s+0x%llx>", CFREE_SLICE_ARG(sym), + (unsigned long long)off); else - driver_printf(" <%s>", sym); + driver_printf(" <%.*s>", CFREE_SLICE_ARG(sym)); } } img_frame = dbg_frame_for_dwarf(s, &frame); have_sp = (cfree_dwarf_subprogram_at(s->dwarf, img_frame.pc, &sp) == CFREE_OK); - if (have_sp && sp.name) { + if (have_sp && sp.name.s) { CfreeDwarfParamIter* it = NULL; CfreeDwarfVar p; int first = 1; - driver_printf(" in %s%s (", sp.name, sp.inlined ? " [inlined]" : ""); + driver_printf(" in %.*s%.*s (", CFREE_SLICE_ARG(sp.name), + CFREE_SLICE_ARG(sp.inlined ? CFREE_SLICE_LIT(" [inlined]") + : CFREE_SLICE_NULL)); if (cfree_dwarf_param_iter_new(s->dwarf, img_frame.pc, &it) == CFREE_OK) { for (;;) { CfreeIterResult r; @@ -946,7 +970,8 @@ static void dbg_cmd_bt(DbgState* s) { r = cfree_dwarf_param_iter_next(it, &p); if (r != CFREE_ITER_ITEM) break; if (!first) driver_printf(", "); - driver_printf("%s=", p.name ? p.name : "?"); + driver_printf("%.*s=", CFREE_SLICE_ARG(p.name.s ? p.name + : CFREE_SLICE_LIT("?"))); dbg_translate_loc(s, &p.loc); if (dbg_read_value(s, &p.loc, &frame, stack_buf, sizeof(stack_buf), &buf, &alloc, &got) == 0) { @@ -963,13 +988,13 @@ static void dbg_cmd_bt(DbgState* s) { } { - const char* file = NULL; + CfreeSlice file = CFREE_SLICE_NULL; uint32_t line = 0; uint32_t col = 0; CfreeStatus rc = cfree_dwarf_addr_to_line(s->dwarf, img_frame.pc, &file, &line, &col); - if (rc == CFREE_OK && file) { - driver_printf(" at %s:%u", file, line); + if (rc == CFREE_OK && file.s) { + driver_printf(" at %.*s:%u", CFREE_SLICE_ARG(file), line); if (col) driver_printf(":%u", col); } else if (rc == CFREE_NOT_FOUND) { driver_printf(" [no debug info for this frame]"); @@ -1095,7 +1120,7 @@ static void dbg_print_value(DbgState* s, const CfreeDwarfType* type, int64_t v = dbg_load_le_s(buf, got); CfreeDwarfEnumIter* it = NULL; CfreeDwarfEnumVal ev; - const char* match = NULL; + CfreeSlice match = CFREE_SLICE_NULL; if (cfree_dwarf_enum_iter_new(s->dwarf, type, &it) == CFREE_OK) { for (;;) { CfreeIterResult r = cfree_dwarf_enum_iter_next(it, &ev); @@ -1107,8 +1132,8 @@ static void dbg_print_value(DbgState* s, const CfreeDwarfType* type, } cfree_dwarf_enum_iter_free(it); } - if (match) - driver_printf("%s (%lld)", match, (long long)v); + if (match.s) + driver_printf("%.*s (%lld)", CFREE_SLICE_ARG(match), (long long)v); else driver_printf("%lld", (long long)v); return; @@ -1153,7 +1178,9 @@ static void dbg_print_value(DbgState* s, const CfreeDwarfType* type, if (r != CFREE_ITER_ITEM) break; size_t fsz = 0; dbg_indent(depth + 1); - driver_printf(".%s = ", (f.name && *f.name) ? f.name : "<anon>"); + driver_printf(".%.*s = ", + CFREE_SLICE_ARG(f.name.len ? f.name + : CFREE_SLICE_LIT("<anon>"))); if (f.bit_size) { /* Bitfield: read up to 8 bytes spanning the storage * unit at byte_offset, shift, mask. */ @@ -1256,16 +1283,17 @@ static void dbg_cmd_print(DbgState* s, const char* name) { CfreeStatus rc = s->dwarf ? cfree_dwarf_var_at(s->dwarf, dbg_pc_rt_to_img(s, s->last_stop.regs.pc), - name, &loc) + cfree_slice_cstr(name), &loc) : CFREE_NOT_FOUND; if (rc == CFREE_OK) { dbg_translate_loc(s, &loc); if (dbg_read_value(s, &loc, &s->last_stop.regs, stack_buf, sizeof(stack_buf), &buf, &alloc, &got) != 0) { - driver_errf(DBG_TOOL, "could not read %s", name); + driver_errf(DBG_TOOL, "could not read %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(name))); return; } - driver_printf("%s = ", name); + driver_printf("%.*s = ", CFREE_SLICE_ARG(cfree_slice_cstr(name))); dbg_print_value(s, loc.type, buf, got, 0); driver_printf("\n"); dbg_release_value_buf(s, buf, alloc); @@ -1274,19 +1302,21 @@ static void dbg_cmd_print(DbgState* s, const char* name) { /* DWARF didn't know about it — try a global symbol. */ { - void* p = cfree_jit_lookup(s->jit, name); + void* p = cfree_jit_lookup(s->jit, cfree_slice_cstr(name)); if (p) { union { void* p; uint64_t u; } cv; cv.p = p; - driver_printf("%s = 0x%llx (no DWARF type info)\n", name, + driver_printf("%.*s = 0x%llx (no DWARF type info)\n", + CFREE_SLICE_ARG(cfree_slice_cstr(name)), (unsigned long long)cv.u); return; } } - driver_errf(DBG_TOOL, "no variable or symbol named '%s'", name); + driver_errf(DBG_TOOL, "no variable or symbol named '%.*s'", + CFREE_SLICE_ARG(cfree_slice_cstr(name))); } } @@ -1312,10 +1342,11 @@ static void dbg_cmd_set(DbgState* s, const char* name, uint64_t value) { CfreeStatus rc = s->dwarf ? cfree_dwarf_var_at(s->dwarf, dbg_pc_rt_to_img(s, s->last_stop.regs.pc), - name, &loc) + cfree_slice_cstr(name), &loc) : CFREE_NOT_FOUND; if (rc != CFREE_OK) { - driver_errf(DBG_TOOL, "no variable named '%s'", name); + driver_errf(DBG_TOOL, "no variable named '%.*s'", + CFREE_SLICE_ARG(cfree_slice_cstr(name))); return; } } @@ -1355,8 +1386,8 @@ static void dbg_cmd_set(DbgState* s, const char* name, uint64_t value) { return; } case CFREE_DLOC_EXPR: - driver_errf(DBG_TOOL, "cannot set '%s': location is a DWARF expression", - name); + driver_errf(DBG_TOOL, "cannot set '%.*s': location is a DWARF expression", + CFREE_SLICE_ARG(cfree_slice_cstr(name))); return; } } @@ -1398,14 +1429,15 @@ static void dbg_cmd_info_vars(DbgState* s, uint32_t mask, const char* label) { return; } if (!s->dwarf) { - driver_errf(DBG_TOOL, "no DWARF: %s unavailable", label); + driver_errf(DBG_TOOL, "no DWARF: %.*s unavailable", + CFREE_SLICE_ARG(cfree_slice_cstr(label))); return; } if (cfree_dwarf_vars_at_new(s->dwarf, dbg_pc_rt_to_img(s, s->last_stop.regs.pc), mask, &it) != CFREE_OK) { - driver_printf("No %s.\n", label); + driver_printf("No %.*s.\n", CFREE_SLICE_ARG(cfree_slice_cstr(label))); return; } for (;;) { @@ -1419,16 +1451,17 @@ static void dbg_cmd_info_vars(DbgState* s, uint32_t mask, const char* label) { dbg_translate_loc(s, &v.loc); if (dbg_read_value(s, &v.loc, &s->last_stop.regs, stack_buf, sizeof(stack_buf), &buf, &alloc, &got) != 0) { - driver_printf(" %s = <unreadable>\n", v.name); + driver_printf(" %.*s = <unreadable>\n", CFREE_SLICE_ARG(v.name)); continue; } - driver_printf(" %s = ", v.name); + driver_printf(" %.*s = ", CFREE_SLICE_ARG(v.name)); dbg_print_value(s, v.loc.type, buf, got, 1); driver_printf("\n"); dbg_release_value_buf(s, buf, alloc); } cfree_dwarf_vars_at_free(it); - if (!printed) driver_printf("No %s.\n", label); + if (!printed) + driver_printf("No %.*s.\n", CFREE_SLICE_ARG(cfree_slice_cstr(label))); } static void dbg_cmd_info_reg(DbgState* s) { @@ -1451,7 +1484,7 @@ static void dbg_cmd_info_reg(DbgState* s) { CfreeArchReg r; if (cfree_arch_register_at(arch, i, &r) != CFREE_OK) continue; if (r.dwarf_idx >= 32) continue; /* outside CfreeUnwindFrame.regs */ - driver_printf("%-6s 0x%016llx\n", r.name, + driver_printf("%-6.*s 0x%016llx\n", CFREE_SLICE_ARG(r.name), (unsigned long long)s->last_stop.regs.regs[r.dwarf_idx]); } } @@ -1495,8 +1528,9 @@ static void dbg_cmd_info_syms(DbgState* s, CfreeSymKind want, CfreeIterResult r = cfree_jit_sym_iter_next(it, &sym); if (r != CFREE_ITER_ITEM) break; if (sym.kind != want) continue; - if (pattern && !dbg_glob(pattern, sym.name)) continue; - driver_printf("0x%016llx %s\n", (unsigned long long)sym.addr, sym.name); + if (pattern && !dbg_glob(pattern, sym.name.s)) continue; + driver_printf("0x%016llx %.*s\n", (unsigned long long)sym.addr, + CFREE_SLICE_ARG(sym.name)); printed = 1; } cfree_jit_sym_iter_free(it); @@ -1660,12 +1694,13 @@ static int dbg_jit_compile_append_ex(DbgState* s, CfreeLanguage lang, s->jit_counter++; memset(&sin, 0, sizeof(sin)); - sin.bytes.name = input_name ? input_name : dbg_jit_default_name(lang); + sin.name = cfree_slice_cstr(input_name ? input_name + : dbg_jit_default_name(lang)); sin.bytes.data = (const uint8_t*)src; sin.bytes.len = len; sin.lang = lang; sin.input_kind = input_kind; - sin.repl_entry_name = repl_entry_name; + sin.repl_entry_name = cfree_slice_cstr(repl_entry_name); st = dbg_compile_session_for(s, lang, &session); if (st == CFREE_OK) st = cfree_compile_session_compile(session, &sin, &ob); if (st != CFREE_OK || !ob) { @@ -1691,9 +1726,9 @@ static int dbg_jit_compile_append_ex(DbgState* s, CfreeLanguage lang, return 1; } dbg_refresh_dwarf(s); - driver_printf("JIT generation %llu (%s)\n", + driver_printf("JIT generation %llu (%.*s)\n", (unsigned long long)cfree_jit_generation(s->jit), - dbg_jit_language_name(lang)); + CFREE_SLICE_ARG(cfree_slice_cstr(dbg_jit_language_name(lang)))); return 0; } @@ -1834,15 +1869,21 @@ static void dbg_cmd_language(DbgState* s, const char* rest) { while (p[n] && !dbg_isspace((unsigned char)p[n])) ++n; if (n == 0) { const CfreePreprocessOptions* pp = &s->copts.preprocess; - driver_printf("Language: %s\n", dbg_jit_language_name(s->default_jit_lang)); + driver_printf("Language: %.*s\n", + CFREE_SLICE_ARG(cfree_slice_cstr( + dbg_jit_language_name(s->default_jit_lang)))); driver_printf( - "Language options: input=%s opt=-O%d debug=%s includes=%u " - "system-includes=%u defines=%u undefines=%u session=%s\n", - s->default_jit_name ? s->default_jit_name : "", s->copts.code.opt_level, - s->copts.code.debug_info ? "on" : "off", (unsigned)pp->ninclude_dirs, - (unsigned)pp->nsystem_include_dirs, (unsigned)pp->ndefines, - (unsigned)pp->nundefines, - s->compile_sessions[s->default_jit_lang] ? "cached" : "not-created"); + "Language options: input=%.*s opt=-O%d debug=%.*s includes=%u " + "system-includes=%u defines=%u undefines=%u session=%.*s\n", + CFREE_SLICE_ARG(cfree_slice_cstr(s->default_jit_name)), + s->copts.code.opt_level, + CFREE_SLICE_ARG( + cfree_slice_cstr(s->copts.code.debug_info ? "on" : "off")), + (unsigned)pp->ninclude_dirs, (unsigned)pp->nsystem_include_dirs, + (unsigned)pp->ndefines, (unsigned)pp->nundefines, + CFREE_SLICE_ARG(cfree_slice_cstr( + s->compile_sessions[s->default_jit_lang] ? "cached" + : "not-created"))); return; } if (n >= sizeof(tmp)) { @@ -1854,12 +1895,14 @@ static void dbg_cmd_language(DbgState* s, const char* rest) { lang = dbg_jit_language_for_tag(s, tmp, &name); (void)name; if (lang == CFREE_LANG_COUNT) { - driver_errf(DBG_TOOL, "unsupported language: %s", tmp); + driver_errf(DBG_TOOL, "unsupported language: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(tmp))); return; } s->default_jit_lang = lang; s->default_jit_name = dbg_jit_default_name(lang); - driver_printf("Language: %s\n", dbg_jit_language_name(lang)); + driver_printf("Language: %.*s\n", + CFREE_SLICE_ARG(cfree_slice_cstr(dbg_jit_language_name(lang)))); } static size_t dbg_u64_dec(char* dst, size_t cap, uint64_t v) { @@ -1996,9 +2039,10 @@ static void dbg_cmd_expr(DbgState* s, const char* expr) { } } - entry = cfree_jit_lookup(s->jit, name); + entry = cfree_jit_lookup(s->jit, cfree_slice_cstr(name)); if (!entry) { - driver_errf(DBG_TOOL, "expression thunk not found: %s", name); + driver_errf(DBG_TOOL, "expression thunk not found: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(name))); goto out; } if (dbg_call_u64_entry(s, entry, NULL, 0, &ret) == 0) { @@ -2033,9 +2077,10 @@ static void dbg_cmd_call(DbgState* s, const char* rest) { driver_errf(DBG_TOOL, "usage: call SYMBOL [INT_OR_ADDR ...]"); goto out; } - entry = cfree_jit_lookup(s->jit, sym); + entry = cfree_jit_lookup(s->jit, cfree_slice_cstr(sym)); if (!entry) { - driver_errf(DBG_TOOL, "symbol not found: %s", sym); + driver_errf(DBG_TOOL, "symbol not found: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(sym))); goto out; } while (*p) { @@ -2050,7 +2095,8 @@ static void dbg_cmd_call(DbgState* s, const char* rest) { } used = dbg_parse_uint(a, &v); if (!used || a[used] != '\0') { - driver_errf(DBG_TOOL, "expected integer/address argument, got '%s'", a); + driver_errf(DBG_TOOL, "expected integer/address argument, got '%.*s'", + CFREE_SLICE_ARG(cfree_slice_cstr(a))); goto out; } args[nargs++] = v; @@ -2121,7 +2167,8 @@ static void dbg_cmd_list(DbgState* s, const char* spec) { const CfreeFileIO* io; if (!s->dwarf) { - driver_errf(DBG_TOOL, "no DWARF: cannot resolve %s", spec); + driver_errf(DBG_TOOL, "no DWARF: cannot resolve %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(spec))); return; } @@ -2132,7 +2179,8 @@ static void dbg_cmd_list(DbgState* s, const char* spec) { } flen = (size_t)(colon - spec); if (flen == 0 || flen >= sizeof(path)) { - driver_errf(DBG_TOOL, "bad file in '%s'", spec); + driver_errf(DBG_TOOL, "bad file in '%.*s'", + CFREE_SLICE_ARG(cfree_slice_cstr(spec))); return; } driver_memcpy(path, spec, flen); @@ -2145,21 +2193,23 @@ static void dbg_cmd_list(DbgState* s, const char* spec) { /* Validate via DWARF first. */ { - CfreeStatus st = - cfree_dwarf_line_to_addr(s->dwarf, path, (uint32_t)line_u, &pc); + CfreeStatus st = cfree_dwarf_line_to_addr( + s->dwarf, cfree_slice_cstr(path), (uint32_t)line_u, &pc); if (st == CFREE_NOT_FOUND) { - driver_errf(DBG_TOOL, "no line %u in %s", (uint32_t)line_u, path); + driver_errf(DBG_TOOL, "no line %u in %.*s", (uint32_t)line_u, + CFREE_SLICE_ARG(cfree_slice_cstr(path))); return; } if (st == CFREE_AMBIGUOUS) { driver_errf(DBG_TOOL, - "ambiguous: %s:%u matches multiple files; " + "ambiguous: %.*s:%u matches multiple files; " "use a longer path suffix", - path, (uint32_t)line_u); + CFREE_SLICE_ARG(cfree_slice_cstr(path)), (uint32_t)line_u); return; } if (st != CFREE_OK) { - driver_errf(DBG_TOOL, "no line entry for %s", spec); + driver_errf(DBG_TOOL, "no line entry for %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(spec))); return; } rc = 0; @@ -2170,8 +2220,9 @@ static void dbg_cmd_list(DbgState* s, const char* spec) { * DWARF-only summary line per doc/DBG.md §10. */ io = s->env && s->env->file_io.read_all ? &s->env->file_io : NULL; if (!io || io->read_all(io->user, path, &fd) != CFREE_OK) { - driver_printf("%s:%u [source not available; pc=0x%llx]\n", path, - (uint32_t)line_u, (unsigned long long)pc); + driver_printf("%.*s:%u [source not available; pc=0x%llx]\n", + CFREE_SLICE_ARG(cfree_slice_cstr(path)), (uint32_t)line_u, + (unsigned long long)pc); return; } @@ -2190,7 +2241,9 @@ static void dbg_cmd_list(DbgState* s, const char* spec) { if (eol) { if (cur >= lo && cur <= hi) { size_t len = (size_t)(p - line_start); - driver_printf("%6u%s %.*s\n", cur, cur == target ? " >" : " ", + driver_printf("%6u%.*s %.*s\n", cur, + CFREE_SLICE_ARG( + cfree_slice_cstr(cur == target ? " >" : " ")), (int)len, (const char*)line_start); } ++cur; @@ -2269,9 +2322,11 @@ static void dbg_cmd_break(DbgState* s, const char* spec) { } s->nbps++; - driver_printf("Breakpoint %d at 0x%llx (%s)%s\n", b->id, - (unsigned long long)addr, spec, - b->session_id ? "" : " [disarmed]"); + driver_printf("Breakpoint %d at 0x%llx (%.*s)%.*s\n", b->id, + (unsigned long long)addr, + CFREE_SLICE_ARG(cfree_slice_cstr(spec)), + CFREE_SLICE_ARG( + cfree_slice_cstr(b->session_id ? "" : " [disarmed]"))); } static void dbg_cmd_info_b(DbgState* s) { @@ -2283,11 +2338,13 @@ static void dbg_cmd_info_b(DbgState* s) { driver_printf("Num Enb Address Skip Max Spec\n"); for (i = 0; i < s->nbps; ++i) { Bp* b = &s->bps[i]; - driver_printf("%-4d %-4s 0x%-18llx %-6llu %-6llu %s%s\n", b->id, + driver_printf("%-4d %-4s 0x%-18llx %-6llu %-6llu %.*s%.*s\n", b->id, b->enabled ? "y" : "n", (unsigned long long)b->addr, (unsigned long long)b->skip_count, - (unsigned long long)b->max_hits, b->spec ? b->spec : "", - b->session_id ? "" : " [disarmed]"); + (unsigned long long)b->max_hits, + CFREE_SLICE_ARG(cfree_slice_cstr(b->spec)), + CFREE_SLICE_ARG( + cfree_slice_cstr(b->session_id ? "" : " [disarmed]"))); } } @@ -2345,7 +2402,8 @@ static void dbg_cmd_set_enabled(DbgState* s, int id, int enable) { static void dbg_cmd_help(void) { driver_printf( - "%s", + "%.*s", + CFREE_SLICE_ARG(CFREE_SLICE_LIT( "Commands (abbrev. shown):\n" " h, help show this help\n" " q, quit exit (Ctrl-D also works)\n" @@ -2379,7 +2437,7 @@ static void dbg_cmd_help(void) { " info locals list locals at current PC\n" " info args list args at current PC\n" " info functions [PATTERN] list JIT functions matching PATTERN\n" - " info variables [PATTERN] list JIT globals matching PATTERN\n"); + " info variables [PATTERN] list JIT globals matching PATTERN\n"))); } static CfreeLanguage dbg_default_language_from_inputs(CfreeCompiler* c, @@ -2539,7 +2597,8 @@ static int dbg_dispatch(DbgState* s, char* line) { dbg_take_word(rest, &pat); dbg_cmd_info_syms(s, CFREE_SK_OBJ, *pat ? pat : NULL); } else { - driver_errf(DBG_TOOL, "unknown 'info' subcommand: %s", what); + driver_errf(DBG_TOOL, "unknown 'info' subcommand: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(what))); } return 0; } @@ -2568,7 +2627,8 @@ static int dbg_dispatch(DbgState* s, char* line) { } used = dbg_parse_uint(val_s, &v); if (!used || val_s[used] != '\0') { - driver_errf(DBG_TOOL, "expected integer value, got '%s'", val_s); + driver_errf(DBG_TOOL, "expected integer value, got '%.*s'", + CFREE_SLICE_ARG(cfree_slice_cstr(val_s))); return 0; } dbg_cmd_set(s, name, v); @@ -2585,7 +2645,8 @@ static int dbg_dispatch(DbgState* s, char* line) { } used = dbg_parse_uint(addr_s, &addr); if (!used || addr_s[used] != '\0') { - driver_errf(DBG_TOOL, "bad address '%s'", addr_s); + driver_errf(DBG_TOOL, "bad address '%.*s'", + CFREE_SLICE_ARG(cfree_slice_cstr(addr_s))); return 0; } dbg_cmd_jump(s, addr); @@ -2679,14 +2740,16 @@ static int dbg_dispatch(DbgState* s, char* line) { } used = dbg_parse_uint(addr_s, &addr); if (!used || addr_s[used] != '\0') { - driver_errf(DBG_TOOL, "bad address '%s'", addr_s); + driver_errf(DBG_TOOL, "bad address '%.*s'", + CFREE_SLICE_ARG(cfree_slice_cstr(addr_s))); return 0; } dbg_take_word(rest, &count_s); if (*count_s) { used = dbg_parse_uint(count_s, &count); if (!used || count_s[used] != '\0') { - driver_errf(DBG_TOOL, "bad count '%s'", count_s); + driver_errf(DBG_TOOL, "bad count '%.*s'", + CFREE_SLICE_ARG(cfree_slice_cstr(count_s))); return 0; } } @@ -2702,7 +2765,8 @@ static int dbg_dispatch(DbgState* s, char* line) { if (s->session) { dbg_cmd_expr(s, raw); } else { - driver_errf(DBG_TOOL, "unknown command: %s (try 'h')", cmd); + driver_errf(DBG_TOOL, "unknown command: %.*s (try 'h')", + CFREE_SLICE_ARG(cfree_slice_cstr(cmd))); } return 0; } @@ -2796,9 +2860,10 @@ int driver_dbg(int argc, char** argv) { st.entry_name = o.entry; if (driver_inputs_count(&o.inputs) != 0) { - st.entry_addr = cfree_jit_lookup(jit, o.entry); + st.entry_addr = cfree_jit_lookup(jit, cfree_slice_cstr(o.entry)); if (!st.entry_addr) { - driver_errf(DBG_TOOL, "entry symbol not found: %s", o.entry); + driver_errf(DBG_TOOL, "entry symbol not found: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(o.entry))); cfree_jit_free(jit); driver_compiler_free(compiler); dbg_options_release(&o); diff --git a/driver/driver.h b/driver/driver.h @@ -227,7 +227,7 @@ int driver_edit_temp(DriverEnv *, const char *suffix, const uint8_t *initial, size_t initial_size, uint8_t **out_data, size_t *out_size); /* Path-shaped input loader. Wraps env.file_io.read_all so each tool can - * convert a list of paths to a list of CfreeBytes without re-implementing + * convert a list of paths to a list of CfreeSlice without re-implementing * load/release/error bookkeeping. `loaded` is set to 1 on success; release is * idempotent and does nothing when loaded is already 0. driver_load_bytes * fills `in.name = path` plus the loaded data/len; driver_release_bytes hands @@ -239,7 +239,7 @@ typedef struct DriverLoad { } DriverLoad; int driver_load_bytes(const CfreeFileIO *, const char *tool, const char *path, - DriverLoad *out, CfreeBytes *in); + DriverLoad *out, CfreeSlice *in); void driver_release_bytes(const CfreeFileIO *, DriverLoad *); /* Read one line from stdin into `buf` (cap >= 2). Strips the trailing @@ -268,6 +268,6 @@ void driver_restore_sigint(void); * `user` is ignored and may be NULL. Wired into `cfree run` so JITed code * can call libc symbols (printf, malloc, ...) without an explicit linker * step. */ -void *driver_dlsym_resolver(void *user, const char *name); +void *driver_dlsym_resolver(void *user, CfreeSlice name); #endif diff --git a/driver/emu.c b/driver/emu.c @@ -40,14 +40,16 @@ typedef struct EmuOptions { } EmuOptions; static void emu_usage(void) { - driver_errf(EMU_TOOL, "%s", - "usage: cfree emu [options] guest.elf [-- guest-arg...]\n" - " cfree emu --help for full option reference"); + driver_errf(EMU_TOOL, "%.*s", + CFREE_SLICE_ARG(CFREE_SLICE_LIT( + "usage: cfree emu [options] guest.elf [-- guest-arg...]\n" + " cfree emu --help for full option reference"))); } void driver_help_emu(void) { driver_printf( - "%s", + "%.*s", + CFREE_SLICE_ARG(CFREE_SLICE_LIT( "cfree emu — run a guest user-mode ELF on the host\n" "\n" "USAGE\n" @@ -81,7 +83,7 @@ void driver_help_emu(void) { "\n" "EXIT CODES\n" " Returns the guest's exit code on clean exit, or 1 on internal\n" - " failure. 2 on bad command-line usage.\n"); + " failure. 2 on bad command-line usage.\n"))); } static int emu_alloc_arrays(EmuOptions* o, int argc) { @@ -108,7 +110,8 @@ static int emu_record_arch(EmuOptions* o, const char* val) { o->guest_arch_set = 1; return 0; } - driver_errf(EMU_TOOL, "unsupported -arch value: %s", val); + driver_errf(EMU_TOOL, "unsupported -arch value: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(val))); return 1; } @@ -165,13 +168,15 @@ static int emu_parse(int argc, char** argv, EmuOptions* o) { } if (a[0] == '-' && a[1] != '\0') { - driver_errf(EMU_TOOL, "unknown flag: %s", a); + driver_errf(EMU_TOOL, "unknown flag: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(a))); return 1; } if (o->elf_path) { - driver_errf(EMU_TOOL, "multiple guest ELF inputs: %s, %s", o->elf_path, - a); + driver_errf(EMU_TOOL, "multiple guest ELF inputs: %.*s, %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(o->elf_path)), + CFREE_SLICE_ARG(cfree_slice_cstr(a))); return 1; } o->elf_path = a; @@ -220,18 +225,19 @@ static const char* emu_arch_name(CfreeEmuArch a) { /* Auto-detect the guest arch from the ELF magic when -arch was not set. * Honors a user-supplied -arch verbatim (no cross-check against the ELF; * mismatches surface as decode failures inside the emu). */ -static int emu_resolve_arch(EmuOptions* o, const CfreeBytes* elf) { +static int emu_resolve_arch(EmuOptions* o, const CfreeSlice* elf) { CfreeTarget detected; if (o->guest_arch_set) return 0; if (cfree_detect_target(elf->data, elf->len, &detected) != CFREE_OK) { - driver_errf(EMU_TOOL, "could not detect target from %s; pass -arch", - o->elf_path); + driver_errf(EMU_TOOL, "could not detect target from %.*s; pass -arch", + CFREE_SLICE_ARG(cfree_slice_cstr(o->elf_path))); return 1; } if (emu_arch_from_kind(detected.arch, &o->guest_arch) != 0) { driver_errf(EMU_TOOL, - "unsupported guest arch in %s; v1 supports aarch64 and riscv64", - o->elf_path); + "unsupported guest arch in %.*s; v1 supports aarch64 and " + "riscv64", + CFREE_SLICE_ARG(cfree_slice_cstr(o->elf_path))); return 1; } o->guest_arch_set = 1; @@ -258,7 +264,7 @@ int driver_emu(int argc, char** argv) { CfreeContext ctx; CfreeCompiler* compiler = NULL; DriverLoad elf_lf = {0}; - CfreeBytes elf_in; + CfreeSlice elf_in; CfreeEmuOptions opts; const char** guest_argv; int exit_code = 0; @@ -314,8 +320,9 @@ int driver_emu(int argc, char** argv) { opts.envp = 0; if (cfree_emu_run(compiler, &opts, &exit_code) != CFREE_OK) { - driver_errf(EMU_TOOL, "emulation of %s (%s) failed", eo.elf_path, - emu_arch_name(eo.guest_arch)); + driver_errf(EMU_TOOL, "emulation of %.*s (%.*s) failed", + CFREE_SLICE_ARG(cfree_slice_cstr(eo.elf_path)), + CFREE_SLICE_ARG(cfree_slice_cstr(emu_arch_name(eo.guest_arch)))); goto out; } diff --git a/driver/env.c b/driver/env.c @@ -183,16 +183,18 @@ static void diag_stderr_emit(CfreeDiagSink *s, CfreeDiagKind k, CfreeSrcLoc loc, const char *fmt, va_list ap) { (void)s; if (loc.file_id || loc.line) { - const char *name = + CfreeSlice name = cfree_compiler_file_name(g_diag_active_compiler, loc.file_id); - if (name && *name) { - fprintf(stderr, "%s:%u:%u: %s: ", name, loc.line, loc.col, diag_label(k)); + if (name.len) { + fprintf(stderr, "%.*s:%u:%u: %.*s: ", + CFREE_SLICE_ARG(name), loc.line, loc.col, + CFREE_SLICE_ARG(cfree_slice_cstr(diag_label(k)))); } else { - fprintf(stderr, "<file:%u>:%u:%u: %s: ", loc.file_id, loc.line, loc.col, - diag_label(k)); + fprintf(stderr, "<file:%u>:%u:%u: %.*s: ", loc.file_id, loc.line, loc.col, + CFREE_SLICE_ARG(cfree_slice_cstr(diag_label(k)))); } } else { - fprintf(stderr, "%s: ", diag_label(k)); + fprintf(stderr, "%.*s: ", CFREE_SLICE_ARG(cfree_slice_cstr(diag_label(k)))); } vfprintf(stderr, fmt, ap); fputc('\n', stderr); @@ -1354,25 +1356,44 @@ CfreeDbgHost driver_env_to_dbg_host(const DriverEnv *e) { /* ---------------- host-shim helpers ---------------- */ -int driver_streq(const char *a, const char *b) { return strcmp(a, b) == 0; } +/* The driver's only NUL-terminated-string handling: thin boundary shims that + * route every length scan through cfree_slice_cstr and otherwise use the + * length-based mem* primitives. No libc str* is used. */ + +int driver_streq(const char *a, const char *b) { + return cfree_slice_eq(cfree_slice_cstr(a), cfree_slice_cstr(b)); +} int driver_strneq(const char *a, const char *b, size_t n) { - return strncmp(a, b, n) == 0; + size_t i; + for (i = 0; i < n; ++i) { + unsigned char ca = (unsigned char)a[i], cb = (unsigned char)b[i]; + if (ca != cb) return 0; + if (ca == '\0') return 1; + } + return 1; } -size_t driver_strlen(const char *s) { return strlen(s); } +size_t driver_strlen(const char *s) { return cfree_slice_cstr(s).len; } -const char *driver_strchr(const char *s, int c) { return strchr(s, c); } +const char *driver_strchr(const char *s, int c) { + /* search includes the terminator so driver_strchr(s, 0) works like strchr */ + return (const char *)memchr(s, c, cfree_slice_cstr(s).len + 1u); +} const char *driver_basename(const char *path) { - const char *slash = strrchr(path, '/'); - return slash ? slash + 1 : path; + size_t i = cfree_slice_cstr(path).len; + while (i > 0) { + if (path[i - 1] == '/') return path + i; + --i; + } + return path; } int driver_has_suffix(const char *s, const char *suffix) { - size_t ls = strlen(s); - size_t lf = strlen(suffix); - return ls >= lf && strcmp(s + ls - lf, suffix) == 0; + size_t ls = cfree_slice_cstr(s).len; + size_t lf = cfree_slice_cstr(suffix).len; + return ls >= lf && memcmp(s + ls - lf, suffix, lf) == 0; } int driver_path_exists(const char *path) { @@ -1413,7 +1434,7 @@ int driver_mkdir_p(DriverEnv *env, const char *path) { if (!path || !path[0]) return 1; - len = strlen(path); + len = cfree_slice_cstr(path).len; buf = (char *)driver_alloc(env, len + 1); if (!buf) return 1; @@ -1425,7 +1446,7 @@ int driver_mkdir_p(DriverEnv *env, const char *path) { continue; if (!at_end) buf[i] = '\0'; - if (buf[0] != '\0' && strcmp(buf, ".") != 0) { + if (buf[0] != '\0' && !driver_streq(buf, ".")) { if (mkdir(buf, 0755) != 0 && errno != EEXIST) { driver_free(env, buf, len + 1); return 1; @@ -1477,7 +1498,7 @@ void driver_memcpy(void *dst, const void *src, size_t n) { void driver_errf(const char *tool, const char *fmt, ...) { va_list ap; - fprintf(stderr, "%s: ", tool); + fprintf(stderr, "%.*s: ", CFREE_SLICE_ARG(cfree_slice_cstr(tool))); va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); @@ -1511,7 +1532,7 @@ uint64_t driver_now_ns(void) { const char *driver_getenv(const char *name) { return getenv(name); } int driver_load_bytes(const CfreeFileIO *io, const char *tool, const char *path, - DriverLoad *out, CfreeBytes *in) { + DriverLoad *out, CfreeSlice *in) { out->loaded = 0; out->fd.data = NULL; out->fd.size = 0; @@ -1521,11 +1542,11 @@ int driver_load_bytes(const CfreeFileIO *io, const char *tool, const char *path, return 1; } if (io->read_all(io->user, path, &out->fd) != CFREE_OK) { - driver_errf(tool, "failed to read: %s", path); + driver_errf(tool, "failed to read: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(path))); return 1; } out->loaded = 1; - in->name = path; in->data = out->fd.data; in->len = out->fd.size; return 0; @@ -1655,12 +1676,12 @@ int driver_edit_temp(DriverEnv *e, const char *suffix, const uint8_t *initial, return 0; *out_data = NULL; *out_size = 0; - suffix_len = suffix ? strlen(suffix) : 0u; + suffix_len = suffix ? cfree_slice_cstr(suffix).len : 0u; tmpdir = getenv("TMPDIR"); if (!tmpdir || !*tmpdir) tmpdir = "/tmp"; - tmpdir_len = strlen(tmpdir); - base_len = strlen(base); + tmpdir_len = cfree_slice_cstr(tmpdir).len; + base_len = cfree_slice_cstr(base).len; path_len = tmpdir_len + base_len + suffix_len; path = e->heap->alloc(e->heap, path_len + 1u, 1); if (!path) @@ -1690,7 +1711,7 @@ int driver_edit_temp(DriverEnv *e, const char *suffix, const uint8_t *initial, if (!editor || !*editor) editor = "vi"; { - size_t editor_len = strlen(editor); + size_t editor_len = cfree_slice_cstr(editor).len; size_t quoted_len = 0; char *quoted = driver_shell_quote_path(e, path, path_len, &quoted_len); char *cmd; @@ -1746,10 +1767,13 @@ out: return ok; } -void *driver_dlsym_resolver(void *user, const char *name) { +void *driver_dlsym_resolver(void *user, CfreeSlice name_s) { + /* The linker hands us interned/pool slices that are NUL-terminated, so + * we can pass .s straight to dlsym (a host libc boundary). */ + const char *name = name_s.s; void *p; (void)user; - if (!name) + if (!name || name_s.len == 0) return NULL; /* On Mach-O hosts the linker hands us C names with a leading underscore * (obj_format_c_mangle), but dlsym(RTLD_DEFAULT) expects the diff --git a/driver/hosted.c b/driver/hosted.c @@ -51,7 +51,8 @@ static int hosted_add_required(DriverHostedInput* items, uint32_t* n, return 1; } if (!driver_path_exists(path)) { - driver_errf(req->tool, "hosted profile missing required file: %s", path); + driver_errf(req->tool, "hosted profile missing required file: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(path))); driver_free(req->env, path, size); return 1; } @@ -84,8 +85,8 @@ static int hosted_add_existing_include(DriverHostedPlan* plan, DriverEnv* env, static int hosted_add_define(DriverHostedPlan* plan, const char* name, const char* body) { if (plan->ndefines >= DRIVER_HOSTED_MAX_DEFINES) return 1; - plan->defines[plan->ndefines].name = name; - plan->defines[plan->ndefines].body = body; + plan->defines[plan->ndefines].name = cfree_slice_cstr(name); + plan->defines[plan->ndefines].body = cfree_slice_cstr(body); plan->ndefines++; return 0; } @@ -188,8 +189,8 @@ static int hosted_resolve_darwin(const DriverHostedRequest* req, } } if (!driver_path_exists(libsystem)) { - driver_errf(req->tool, "hosted profile missing required file: %s", - libsystem); + driver_errf(req->tool, "hosted profile missing required file: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(libsystem))); driver_free(req->env, libsystem, size); return 1; } @@ -366,8 +367,8 @@ static int hosted_resolve_linux(const DriverHostedRequest* req, if (!req->static_link && has_libc_so) return hosted_resolve_linux_musl_dynamic(req, plan); driver_errf(req->tool, - "no supported Linux hosted libc found under sysroot: %s", - req->sysroot); + "no supported Linux hosted libc found under sysroot: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(req->sysroot))); return 1; } diff --git a/driver/inputs.c b/driver/inputs.c @@ -53,7 +53,7 @@ static int inputs_record_stdin(DriverInputs* in) { return -1; } slot = &in->source_memory[in->nsource_memory++]; - slot->bytes.name = "<stdin>"; + slot->name = CFREE_SLICE_LIT("<stdin>"); slot->bytes.data = in->stdin_buf; slot->bytes.len = in->stdin_size; slot->lang = CFREE_LANG_C; @@ -85,7 +85,7 @@ uint32_t driver_inputs_count(const DriverInputs* in) { const char* driver_inputs_first_name(const DriverInputs* in) { if (in->nsources) return in->sources[0]; - if (in->nsource_memory) return in->source_memory[0].bytes.name; + if (in->nsource_memory) return in->source_memory[0].name.s; if (in->nobject_files) return in->object_files[0]; if (in->narchives) return in->archives[0]; return NULL; @@ -98,7 +98,7 @@ int driver_inputs_compile_and_jit(DriverInputs* in, CfreeCompiler* compiler, const CfreeJitHost* host, const CfreeCCompileOptions* copts, const char* entry, - void* (*extern_resolver)(void*, const char*), + void* (*extern_resolver)(void*, CfreeSlice), void* extern_resolver_user, CfreeJit** out_jit) { DriverEnv* env = in->env; @@ -108,8 +108,8 @@ int driver_inputs_compile_and_jit(DriverInputs* in, CfreeCompiler* compiler, DriverLoad* src_lf = NULL; DriverLoad* obj_lf = NULL; DriverLoad* arch_lf = NULL; - CfreeBytes* src_bytes = NULL; /* per-path source bytes for loads */ - CfreeBytes* obj_in = NULL; + CfreeSlice* src_bytes = NULL; /* per-path source bytes for loads */ + CfreeSlice* obj_in = NULL; CfreeLinkArchiveInput* arch_in = NULL; CfreeObjBuilder** objs = NULL; CfreeLinkSession* link = NULL; @@ -154,7 +154,7 @@ int driver_inputs_compile_and_jit(DriverInputs* in, CfreeCompiler* compiler, } } - /* Load source files into CfreeBytes and compile them into object builders. */ + /* Load source files into CfreeSlice and compile them into object builders. */ cfree_frontend_metrics_scope_begin(compiler, "driver.load_sources"); for (i = 0; i < in->nsources; ++i) { if (driver_load_bytes(io, tool, in->sources[i], &src_lf[i], @@ -184,6 +184,7 @@ int driver_inputs_compile_and_jit(DriverInputs* in, CfreeCompiler* compiler, sopts.compile.language_options = copts; } memset(&sin, 0, sizeof(sin)); + sin.name = cfree_slice_cstr(in->sources[i]); sin.bytes = src_bytes[i]; sin.lang = lang; st = cfree_compile_session_new(compiler, &sopts, &session); @@ -236,7 +237,7 @@ int driver_inputs_compile_and_jit(DriverInputs* in, CfreeCompiler* compiler, CfreeStatus st; memset(&lopts, 0, sizeof(lopts)); lopts.output_kind = CFREE_LINK_OUTPUT_JIT; - lopts.entry = entry; + lopts.entry = cfree_slice_cstr(entry); lopts.jit_host = host; lopts.extern_resolver = extern_resolver; lopts.extern_resolver_user = extern_resolver_user; @@ -245,7 +246,8 @@ int driver_inputs_compile_and_jit(DriverInputs* in, CfreeCompiler* compiler, for (i = 0; st == CFREE_OK && i < nsrc; ++i) st = cfree_link_session_add_obj(link, objs[i]); for (i = 0; st == CFREE_OK && i < in->nobject_files; ++i) - st = cfree_link_session_add_obj_bytes(link, &obj_in[i]); + st = cfree_link_session_add_obj_bytes( + link, cfree_slice_cstr(in->object_files[i]), &obj_in[i]); for (i = 0; st == CFREE_OK && i < in->narchives; ++i) st = cfree_link_session_add_archive_bytes(link, &arch_in[i]); cfree_frontend_metrics_scope_end(compiler, "driver.link_setup"); @@ -280,9 +282,9 @@ out: * ---------------------------------------------------------------------- */ int driver_collect_obj_global_syms(DriverEnv* env, const CfreeContext* ctx, - const char* tool, const CfreeBytes* member, + const char* tool, const CfreeSlice* member, void** blob_out, size_t* blob_size_out, - const char*** names_out, + const CfreeSlice** names_out, uint32_t* count_out) { CfreeObjFile* of = NULL; CfreeObjSymIter* it = NULL; @@ -291,7 +293,7 @@ int driver_collect_obj_global_syms(DriverEnv* env, const CfreeContext* ctx, size_t name_bytes = 0; size_t alloc_sz; char* blob; - const char** name_arr; + CfreeSlice* name_arr; char* name_storage; size_t cursor = 0; @@ -300,7 +302,7 @@ int driver_collect_obj_global_syms(DriverEnv* env, const CfreeContext* ctx, *names_out = NULL; *count_out = 0; - if (cfree_obj_open(ctx, member, &of) != CFREE_OK) { + if (cfree_obj_open(ctx, CFREE_SLICE_NULL, member, &of) != CFREE_OK) { /* Not a recognized object — caller treats as "no symbols". */ return 0; } @@ -316,13 +318,9 @@ int driver_collect_obj_global_syms(DriverEnv* env, const CfreeContext* ctx, if (r != CFREE_ITER_ITEM) break; if (si.bind != CFREE_SB_GLOBAL) continue; if (si.section == CFREE_SECTION_NONE) continue; - if (!si.name || !si.name[0]) continue; + if (!si.name.len) continue; count += 1; - { - const char* p = si.name; - while (*p++) ++name_bytes; - name_bytes += 1; /* NUL */ - } + name_bytes += si.name.len + 1; /* +NUL */ } cfree_obj_symiter_free(it); @@ -331,15 +329,15 @@ int driver_collect_obj_global_syms(DriverEnv* env, const CfreeContext* ctx, return 0; } - alloc_sz = (size_t)count * sizeof(const char*) + name_bytes; + alloc_sz = (size_t)count * sizeof(CfreeSlice) + name_bytes; blob = (char*)driver_alloc_zeroed(env, alloc_sz); if (!blob) { cfree_obj_free(of); driver_errf(tool, "out of memory"); return 1; } - name_arr = (const char**)blob; - name_storage = blob + (size_t)count * sizeof(const char*); + name_arr = (CfreeSlice*)blob; + name_storage = blob + (size_t)count * sizeof(CfreeSlice); /* Pass B: copy names. */ if (cfree_obj_symiter_new(of, &it) != CFREE_OK) { @@ -352,17 +350,18 @@ int driver_collect_obj_global_syms(DriverEnv* env, const CfreeContext* ctx, uint32_t k = 0; for (;;) { CfreeIterResult r; - const char* p; char* dst; + size_t j; if (k >= count) break; r = cfree_obj_symiter_next(it, &si); if (r != CFREE_ITER_ITEM) break; if (si.bind != CFREE_SB_GLOBAL) continue; if (si.section == CFREE_SECTION_NONE) continue; - if (!si.name || !si.name[0]) continue; + if (!si.name.len) continue; dst = name_storage + cursor; - name_arr[k] = dst; - for (p = si.name; *p; ++p) *dst++ = *p; + name_arr[k].s = dst; + name_arr[k].len = si.name.len; + for (j = 0; j < si.name.len; ++j) *dst++ = si.name.s[j]; *dst++ = '\0'; cursor = (size_t)(dst - name_storage); k++; diff --git a/driver/inputs.h b/driver/inputs.h @@ -89,8 +89,7 @@ int driver_inputs_compile_and_jit(DriverInputs *, CfreeCompiler *, const CfreeJitHost *, const CfreeCCompileOptions *copts, const char *entry, - void *(*extern_resolver)(void *, - const char *), + void *(*extern_resolver)(void *, CfreeSlice), void *extern_resolver_user, CfreeJit **out_jit); @@ -104,8 +103,9 @@ int driver_inputs_compile_and_jit(DriverInputs *, CfreeCompiler *, * of every SB_GLOBAL symbol with a defining section. * * driver_collect_obj_global_syms allocates a single heap block laid out - * as [const char* names[count]][NUL-separated name bytes]. The caller - * frees the block via driver_collect_obj_global_syms_free. + * as [CfreeSlice names[count]][NUL-separated name bytes]. The caller + * frees the block via driver_collect_obj_global_syms_free. Each name + * slice points into the name-byte region and is NUL-terminated there. * * Returns: * 0 member parsed, output filled (count may be 0 if the object has @@ -116,9 +116,9 @@ int driver_inputs_compile_and_jit(DriverInputs *, CfreeCompiler *, */ int driver_collect_obj_global_syms(DriverEnv *env, const CfreeContext *ctx, const char *tool, - const CfreeBytes *member, void **blob_out, + const CfreeSlice *member, void **blob_out, size_t *blob_size_out, - const char ***names_out, + const CfreeSlice **names_out, uint32_t *count_out); void driver_collect_obj_global_syms_free(DriverEnv *env, void *blob, diff --git a/driver/ld.c b/driver/ld.c @@ -46,7 +46,7 @@ /* Per-archive metadata mirroring the relevant subset of * CfreeLinkArchiveInput plus driver-side ownership info. */ typedef struct LdArchive { - const char* path; /* path used for both open and CfreeBytesInput.name */ + const char* path; /* path used for both open and CfreeSliceInput.name */ int owned; /* 1 if `path` was alloc'd by lib_resolve */ size_t owned_size; /* allocation size (for driver_free) */ uint8_t whole_archive; /* nonzero == --whole-archive */ @@ -55,11 +55,11 @@ typedef struct LdArchive { } LdArchive; /* Per-DSO ownership info. The DSO bytes are loaded straight off disk - * via env->file_io into the CfreeBytes passed to libcfree; only + * via env->file_io into the CfreeSlice passed to libcfree; only * the path itself may need to be free'd if it came from -l<name> * resolution. */ typedef struct LdDso { - const char* path; /* path used for both open and CfreeBytesInput.name */ + const char* path; /* path used for both open and CfreeSliceInput.name */ int owned; /* 1 if `path` was alloc'd by lib_resolve */ size_t owned_size; /* allocation size (for driver_free) */ } LdDso; @@ -129,14 +129,16 @@ typedef struct LdOptions { } LdOptions; static void ld_usage(void) { - driver_errf(LD_TOOL, "%s", + driver_errf(LD_TOOL, "%.*s", + CFREE_SLICE_ARG(CFREE_SLICE_LIT( "usage: cfree ld -o out [options...] inputs.o|inputs.a...\n" - " cfree ld --help for full option reference"); + " cfree ld --help for full option reference"))); } void driver_help_ld(void) { driver_printf( - "%s", + "%.*s", + CFREE_SLICE_ARG(CFREE_SLICE_LIT( "cfree ld — link objects/archives into an executable or shared library\n" "\n" "USAGE\n" @@ -210,7 +212,7 @@ void driver_help_ld(void) { " -h, --help Show this help and exit\n" "\n" "EXIT CODES\n" - " 0 success 1 link error 2 bad usage\n"); + " 0 success 1 link error 2 bad usage\n"))); } /* ---------- argv-sized scratch arrays ---------- */ @@ -356,7 +358,8 @@ static int ld_parse_build_id(LdOptions* o, const char* val) { return 0; } - driver_errf(LD_TOOL, "--build-id: unknown value: %s", val); + driver_errf(LD_TOOL, "--build-id: unknown value: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(val))); return 1; } @@ -428,7 +431,8 @@ static int ld_parse_pe_subsystem(LdOptions* o, const char* val) { o->pe_subsystem = CFREE_PE_SUBSYSTEM_WINDOWS_GUI; return 0; } - driver_errf(LD_TOOL, "unsupported subsystem: %s", val); + driver_errf(LD_TOOL, "unsupported subsystem: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(val))); return 1; } @@ -479,7 +483,8 @@ static int ld_try_ms_flag(LdOptions* o, const char* a) { if (driver_lib_resolve_for_os(o->env, val, mode, LIB_RESOLVE_OS_WINDOWS, o->lib_dirs, o->nlib_dirs, &resolved, &resolved_size, &kind) != 0) { - driver_errf(LD_TOOL, "/DEFAULTLIB: cannot find %s", val); + driver_errf(LD_TOOL, "/DEFAULTLIB: cannot find %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(val))); return -1; } if (kind == LIB_RESOLVE_KIND_SHARED || kind == LIB_RESOLVE_KIND_TBD) { @@ -503,7 +508,8 @@ static int ld_try_ms_flag(LdOptions* o, const char* a) { /* Any other `/key[:val]` shape under --ms-link-driver: warn + skip. * We treat the entire arg as consumed so it doesn't fall through to * the positional path and try to open a file. */ - driver_errf(LD_TOOL, "ignoring unsupported MS-style flag: %s", a); + driver_errf(LD_TOOL, "ignoring unsupported MS-style flag: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(a))); return 1; } @@ -667,7 +673,8 @@ static int ld_parse(int argc, char** argv, LdOptions* o) { if (driver_lib_resolve_for_os(o->env, name, mode, resolve_os, o->lib_dirs, o->nlib_dirs, &resolved, &resolved_size, &kind) != 0) { - driver_errf(LD_TOOL, "cannot find -l%s", name); + driver_errf(LD_TOOL, "cannot find -l%.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(name))); return 1; } if (kind == LIB_RESOLVE_KIND_SHARED || kind == LIB_RESOLVE_KIND_TBD) { @@ -690,7 +697,8 @@ static int ld_parse(int argc, char** argv, LdOptions* o) { if (driver_lib_resolve_for_os(o->env, val, mode, resolve_os, o->lib_dirs, o->nlib_dirs, &resolved, &resolved_size, &kind) != 0) { - driver_errf(LD_TOOL, "cannot find -l%s", val); + driver_errf(LD_TOOL, "cannot find -l%.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(val))); return 1; } if (kind == LIB_RESOLVE_KIND_SHARED || kind == LIB_RESOLVE_KIND_TBD) { @@ -717,7 +725,8 @@ static int ld_parse(int argc, char** argv, LdOptions* o) { if (driver_lib_resolve_for_os(o->env, argv[i], mode, resolve_os, o->lib_dirs, o->nlib_dirs, &resolved, &resolved_size, &kind) != 0) { - driver_errf(LD_TOOL, "cannot find -l%s", argv[i]); + driver_errf(LD_TOOL, "cannot find -l%.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(argv[i]))); return 1; } if (kind == LIB_RESOLVE_KIND_SHARED || kind == LIB_RESOLVE_KIND_TBD) { @@ -839,7 +848,8 @@ static int ld_parse(int argc, char** argv, LdOptions* o) { o->allow_undefined = 0; continue; } - driver_errf(LD_TOOL, "unsupported -z option: %s", argv[i]); + driver_errf(LD_TOOL, "unsupported -z option: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(argv[i]))); return 1; } @@ -900,7 +910,8 @@ static int ld_parse(int argc, char** argv, LdOptions* o) { } if (a[0] == '-' && a[1] != '\0') { - driver_errf(LD_TOOL, "unknown flag: %s", a); + driver_errf(LD_TOOL, "unknown flag: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(a))); return 1; } @@ -1031,9 +1042,9 @@ static int ld_run_link(LdOptions* o) { LoadedFile* arch_lf = NULL; LoadedFile* dso_lf = NULL; LoadedFile script_lf = {0}; - CfreeBytes* obj_in = NULL; + CfreeSlice* obj_in = NULL; CfreeLinkArchiveInput* arch_in = NULL; - CfreeBytes* dso_in = NULL; + CfreeSlice* dso_in = NULL; CfreeLinkScript* script = NULL; CfreeLinkSession* link = NULL; uint32_t i; @@ -1074,10 +1085,10 @@ static int ld_run_link(LdOptions* o) { for (i = 0; i < o->nobject_files; ++i) { const char* path = o->object_files[i]; if (load_file(io, path, &obj_lf[i]) != 0) { - driver_errf(LD_TOOL, "failed to read: %s", path); + driver_errf(LD_TOOL, "failed to read: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(path))); goto out; } - obj_in[i].name = path; obj_in[i].data = obj_lf[i].data.data; obj_in[i].len = obj_lf[i].data.size; } @@ -1085,10 +1096,11 @@ static int ld_run_link(LdOptions* o) { for (i = 0; i < o->narchives; ++i) { const LdArchive* a = &o->archives[i]; if (load_file(io, a->path, &arch_lf[i]) != 0) { - driver_errf(LD_TOOL, "failed to read: %s", a->path); + driver_errf(LD_TOOL, "failed to read: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(a->path))); goto out; } - arch_in[i].bytes.name = a->path; + arch_in[i].name = cfree_slice_cstr(a->path); arch_in[i].bytes.data = arch_lf[i].data.data; arch_in[i].bytes.len = arch_lf[i].data.size; arch_in[i].whole_archive = a->whole_archive; @@ -1099,10 +1111,10 @@ static int ld_run_link(LdOptions* o) { for (i = 0; i < o->ndsos; ++i) { const LdDso* d = &o->dsos[i]; if (load_file(io, d->path, &dso_lf[i]) != 0) { - driver_errf(LD_TOOL, "failed to read: %s", d->path); + driver_errf(LD_TOOL, "failed to read: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(d->path))); goto out; } - dso_in[i].name = d->path; dso_in[i].data = dso_lf[i].data.data; dso_in[i].len = dso_lf[i].data.size; } @@ -1112,7 +1124,8 @@ static int ld_run_link(LdOptions* o) { * compiler is destroyed. */ if (o->script_path) { if (load_file(io, o->script_path, &script_lf) != 0) { - driver_errf(LD_TOOL, "failed to read: %s", o->script_path); + driver_errf(LD_TOOL, "failed to read: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(o->script_path))); goto out; } } @@ -1135,15 +1148,17 @@ static int ld_run_link(LdOptions* o) { } if (script_lf.loaded) { - if (cfree_link_script_parse(&ctx, (const char*)script_lf.data.data, - script_lf.data.size, &script) != CFREE_OK) { + CfreeSlice script_text = {.s = (const char*)script_lf.data.data, + .len = script_lf.data.size}; + if (cfree_link_script_parse(&ctx, script_text, &script) != CFREE_OK) { /* The parser reports a diagnostic via env.diag. */ goto out; } } if (io->open_writer(io->user, o->output_path, &writer) != CFREE_OK) { - driver_errf(LD_TOOL, "failed to open output: %s", o->output_path); + driver_errf(LD_TOOL, "failed to open output: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(o->output_path))); goto out; } @@ -1157,11 +1172,23 @@ static int ld_run_link(LdOptions* o) { { CfreeLinkSessionOptions lopts; CfreeStatus st; + CfreeSlice* rpath_slices = NULL; + /* Lift the argv-derived -rpath dirs into slices for the linker. */ + if (o->nrpaths) { + rpath_slices = + driver_alloc_zeroed(o->env, o->nrpaths * sizeof(*rpath_slices)); + if (!rpath_slices) { + driver_errf(LD_TOOL, "out of memory"); + goto out; + } + for (i = 0; i < o->nrpaths; ++i) + rpath_slices[i] = cfree_slice_cstr(o->rpaths[i]); + } memset(&lopts, 0, sizeof(lopts)); lopts.output_kind = o->relocatable ? CFREE_LINK_OUTPUT_RELOCATABLE : o->shared ? CFREE_LINK_OUTPUT_SHARED : CFREE_LINK_OUTPUT_EXE; - lopts.entry = o->entry; + lopts.entry = cfree_slice_cstr(o->entry); lopts.linker_script = script; lopts.build_id_mode = o->build_id_mode; lopts.build_id_bytes = o->build_id_bytes; @@ -1169,8 +1196,8 @@ static int ld_run_link(LdOptions* o) { lopts.gc_sections = o->gc_sections; lopts.pie = o->pie; lopts.pe_subsystem = o->pe_subsystem; - lopts.interp_path = o->interp_path; - lopts.soname = o->soname; + lopts.interp_path = cfree_slice_cstr(o->interp_path); + lopts.soname = cfree_slice_cstr(o->soname); /* Per --enable-new-dtags / --disable-new-dtags: when new_dtags is * set (the default), -rpath entries land in DT_RUNPATH; otherwise * in DT_RPATH. -rpath-link is link-time-only and is forwarded as @@ -1179,10 +1206,10 @@ static int ld_run_link(LdOptions* o) { * write itself, so this matches GNU-ld behaviour where rpath-link * does not appear in DT_*PATH). */ if (o->new_dtags) { - lopts.runpaths = o->rpaths; + lopts.runpaths = rpath_slices; lopts.nrunpaths = o->nrpaths; } else { - lopts.rpaths = o->rpaths; + lopts.rpaths = rpath_slices; lopts.nrpaths = o->nrpaths; } /* By default shared output may resolve symbols against its loader at @@ -1197,24 +1224,30 @@ static int ld_run_link(LdOptions* o) { switch ((CfreeLinkInputOrderKind)ord->kind) { case CFREE_LINK_INPUT_OBJ: case CFREE_LINK_INPUT_OBJ_BYTES: - st = cfree_link_session_add_obj_bytes(link, &obj_in[ord->index]); + st = cfree_link_session_add_obj_bytes( + link, cfree_slice_cstr(o->object_files[ord->index]), + &obj_in[ord->index]); break; case CFREE_LINK_INPUT_ARCHIVE: st = cfree_link_session_add_archive_bytes(link, &arch_in[ord->index]); break; case CFREE_LINK_INPUT_DSO: - st = cfree_link_session_add_dso_bytes(link, &dso_in[ord->index]); + st = cfree_link_session_add_dso_bytes( + link, cfree_slice_cstr(o->dsos[ord->index].path), + &dso_in[ord->index]); break; } } } else { for (i = 0; i < o->nobject_files && st == CFREE_OK; ++i) - st = cfree_link_session_add_obj_bytes(link, &obj_in[i]); + st = cfree_link_session_add_obj_bytes( + link, cfree_slice_cstr(o->object_files[i]), &obj_in[i]); for (i = 0; i < o->narchives && st == CFREE_OK; ++i) st = cfree_link_session_add_archive_bytes(link, &arch_in[i]); for (i = 0; i < o->ndsos && st == CFREE_OK; ++i) - st = cfree_link_session_add_dso_bytes(link, &dso_in[i]); + st = cfree_link_session_add_dso_bytes( + link, cfree_slice_cstr(o->dsos[i].path), &dso_in[i]); } if (st == CFREE_OK) st = cfree_link_session_emit(link, writer); rc = st == CFREE_OK ? 0 : 1; @@ -1228,7 +1261,8 @@ out: * the writer so the bits are stable on disk. */ if (rc == 0 && o->output_path && !o->relocatable) { if (driver_mark_executable_output(o->output_path) != 0) { - driver_errf(LD_TOOL, "failed to set executable mode: %s", o->output_path); + driver_errf(LD_TOOL, "failed to set executable mode: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(o->output_path))); rc = 1; } } diff --git a/driver/main.c b/driver/main.c @@ -115,7 +115,8 @@ int driver_argv_wants_help(int argc, char** argv, int accept_short_h) { void driver_help_top(void) { driver_printf( - "%s", + "%.*s", + CFREE_SLICE_ARG(CFREE_SLICE_LIT( "cfree — freestanding C compiler toolchain\n" "\n" "USAGE\n" @@ -151,7 +152,7 @@ void driver_help_top(void) { "EXIT CODES\n" " 0 success\n" " 1 tool-reported error (compile, link, I/O, ...)\n" - " 2 bad command-line usage\n"); + " 2 bad command-line usage\n"))); } int driver_main(int argc, char** argv) { @@ -184,7 +185,8 @@ int driver_main(int argc, char** argv) { return 0; } if (print_tool_help(argv[2]) == 0) return 0; - driver_errf("cfree", "no such tool: %s", argv[2]); + driver_errf("cfree", "no such tool: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(argv[2]))); return 2; } @@ -196,7 +198,8 @@ int driver_main(int argc, char** argv) { if (rc != -1) return rc; } - driver_errf("cfree", "no such tool: %s", argv[1]); + driver_errf("cfree", "no such tool: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(argv[1]))); driver_help_top(); return 2; } diff --git a/driver/objcopy.c b/driver/objcopy.c @@ -35,7 +35,8 @@ void driver_help_objcopy(void) { driver_printf( - "%s", + "%.*s", + CFREE_SLICE_ARG(CFREE_SLICE_LIT( "cfree objcopy — copy and transform an object file\n" "\n" "USAGE\n" @@ -63,7 +64,7 @@ void driver_help_objcopy(void) { " names: elf*, mach-o / macho*, coff*, wasm*\n" "\n" "EXIT CODES\n" - " 0 success 1 I/O or strip error 2 bad usage\n"); + " 0 success 1 I/O or strip error 2 bad usage\n"))); } typedef enum CopyOp { @@ -117,11 +118,11 @@ typedef struct CopyOpts { const char* output; } CopyOpts; -static int name_in_list(const char* name, const char* const* list, uint32_t n) { +static int name_in_list(CfreeSlice name, const char* const* list, uint32_t n) { uint32_t i; - if (!name) return 0; + if (!name.len) return 0; for (i = 0; i < n; ++i) { - if (list[i] && strcmp(list[i], name) == 0) return 1; + if (list[i] && cfree_slice_eq_cstr(name, list[i])) return 1; } return 0; } @@ -168,12 +169,12 @@ static int push_pair(DriverEnv* env, NamePair** arr, uint32_t* n, uint32_t* cap, static int take_value(int* i, int argc, char** argv, const char* flag, const char** out) { const char* a = argv[*i]; - size_t flen = strlen(flag); - if (strncmp(a, flag, flen) == 0 && a[flen] == '=') { + size_t flen = cfree_slice_cstr(flag).len; + if (driver_strneq(a, flag, flen) && a[flen] == '=') { *out = a + flen + 1; return 1; } - if (strcmp(a, flag) == 0) { + if (driver_streq(a, flag)) { if (*i + 1 >= argc) return -1; *out = argv[++(*i)]; return 1; @@ -184,7 +185,7 @@ static int take_value(int* i, int argc, char** argv, const char* flag, /* Split "old=new" / "name=file" at the first '='. */ static int split_pair(DriverEnv* env, const char* spec, const char** out_left, const char** out_right) { - const char* eq = strchr(spec, '='); + const char* eq = driver_strchr(spec, '='); size_t llen; char* left; if (!eq || eq == spec || !eq[1]) return -1; @@ -200,19 +201,20 @@ static int split_pair(DriverEnv* env, const char* spec, const char** out_left, static int parse_fmt_name(const char* name, CfreeObjFmt* out) { if (!name) return -1; - if (strncmp(name, "elf", 3) == 0) { + if (driver_strneq(name, "elf", sizeof("elf") - 1)) { *out = CFREE_OBJ_ELF; return 0; } - if (strncmp(name, "mach", 4) == 0) { + if (driver_strneq(name, "mach", sizeof("mach") - 1)) { *out = CFREE_OBJ_MACHO; return 0; } - if (strncmp(name, "coff", 4) == 0 || strncmp(name, "pe-", 3) == 0) { + if (driver_strneq(name, "coff", sizeof("coff") - 1) || + driver_strneq(name, "pe-", sizeof("pe-") - 1)) { *out = CFREE_OBJ_COFF; return 0; } - if (strncmp(name, "wasm", 4) == 0) { + if (driver_strneq(name, "wasm", sizeof("wasm") - 1)) { *out = CFREE_OBJ_WASM; return 0; } @@ -222,7 +224,7 @@ static int parse_fmt_name(const char* name, CfreeObjFmt* out) { /* Lookup a symbol by name; CFREE_OBJ_SYMBOL_NONE if not found. */ static CfreeObjSymbol find_sym_id(CfreeObjFile* of, const char* name) { CfreeObjSymInfo si; - if (cfree_obj_symbol_by_name(of, name, &si) != CFREE_OK) { + if (cfree_obj_symbol_by_name(of, cfree_slice_cstr(name), &si) != CFREE_OK) { return CFREE_OBJ_SYMBOL_NONE; } return si.id; @@ -231,7 +233,7 @@ static CfreeObjSymbol find_sym_id(CfreeObjFile* of, const char* name) { /* Lookup a section by name; CFREE_SECTION_NONE if not found. */ static CfreeObjSection find_sec_id(CfreeObjFile* of, const char* name) { CfreeObjSection s = CFREE_SECTION_NONE; - if (cfree_obj_section_by_name(of, name, &s) != CFREE_OK) { + if (cfree_obj_section_by_name(of, cfree_slice_cstr(name), &s) != CFREE_OK) { return CFREE_SECTION_NONE; } return s; @@ -377,12 +379,14 @@ static int run_transforms(DriverEnv* env, const CfreeContext* ctx, for (i = 0; i < opts->nrename_sec; ++i) { CfreeObjSection sid = find_sec_id(of, opts->rename_sections[i].old_name); if (sid == CFREE_SECTION_NONE) { - driver_errf(OBJCOPY_TOOL, "rename-section: '%s' not found", - opts->rename_sections[i].old_name); + driver_errf(OBJCOPY_TOOL, "rename-section: '%.*s' not found", + CFREE_SLICE_ARG( + cfree_slice_cstr(opts->rename_sections[i].old_name))); return 1; } - CfreeSym ns = cfree_sym_intern(cfree_obj_builder_compiler(b), - opts->rename_sections[i].new_name); + CfreeSym ns = cfree_sym_intern( + cfree_obj_builder_compiler(b), + cfree_slice_cstr(opts->rename_sections[i].new_name)); cfree_obj_builder_rename_section(b, sid, ns); } @@ -391,15 +395,17 @@ static int run_transforms(DriverEnv* env, const CfreeContext* ctx, CfreeObjSection sid = find_sec_id(of, opts->update_sections[i].old_name); CfreeFileData fd = {0}; if (sid == CFREE_SECTION_NONE) { - driver_errf(OBJCOPY_TOOL, "update-section: '%s' not found", - opts->update_sections[i].old_name); + driver_errf(OBJCOPY_TOOL, "update-section: '%.*s' not found", + CFREE_SLICE_ARG( + cfree_slice_cstr(opts->update_sections[i].old_name))); return 1; } if (ctx->file_io->read_all(ctx->file_io->user, opts->update_sections[i].new_name, &fd) != CFREE_OK) { - driver_errf(OBJCOPY_TOOL, "update-section: cannot read %s", - opts->update_sections[i].new_name); + driver_errf(OBJCOPY_TOOL, "update-section: cannot read %.*s", + CFREE_SLICE_ARG( + cfree_slice_cstr(opts->update_sections[i].new_name))); return 1; } cfree_obj_builder_section_replace_bytes(b, sid, fd.data, fd.size); @@ -415,20 +421,23 @@ static int run_transforms(DriverEnv* env, const CfreeContext* ctx, if (ctx->file_io->read_all(ctx->file_io->user, opts->add_sections[i].new_name, &fd) != CFREE_OK) { - driver_errf(OBJCOPY_TOOL, "add-section: cannot read %s", - opts->add_sections[i].new_name); + driver_errf(OBJCOPY_TOOL, "add-section: cannot read %.*s", + CFREE_SLICE_ARG( + cfree_slice_cstr(opts->add_sections[i].new_name))); return 1; } memset(&desc, 0, sizeof desc); - desc.name = cfree_sym_intern(cfree_obj_builder_compiler(b), - opts->add_sections[i].old_name); + desc.name = cfree_sym_intern( + cfree_obj_builder_compiler(b), + cfree_slice_cstr(opts->add_sections[i].old_name)); desc.kind = CFREE_SEC_OTHER; desc.flags = 0; desc.align = 1; desc.entsize = 0; if (cfree_obj_builder_section(b, &desc, &nsid) != CFREE_OK) { - driver_errf(OBJCOPY_TOOL, "add-section: failed to create '%s'", - opts->add_sections[i].old_name); + driver_errf(OBJCOPY_TOOL, "add-section: failed to create '%.*s'", + CFREE_SLICE_ARG( + cfree_slice_cstr(opts->add_sections[i].old_name))); ctx->file_io->release(ctx->file_io->user, &fd); return 1; } @@ -443,7 +452,7 @@ static int run_transforms(DriverEnv* env, const CfreeContext* ctx, cfree_obj_builder_rename_symbol( b, sid, cfree_sym_intern(cfree_obj_builder_compiler(b), - opts->redefine_syms[i].new_name)); + cfree_slice_cstr(opts->redefine_syms[i].new_name))); } /* --globalize-symbol / --localize-symbol / --weaken-symbol */ @@ -467,21 +476,24 @@ static int run_transforms(DriverEnv* env, const CfreeContext* ctx, } static int copy_one_object(DriverEnv* env, const CfreeContext* ctx, - const CfreeBytes* input, const CopyOpts* opts, - const char* output_path) { + const char* input_name, const CfreeSlice* input, + const CopyOpts* opts, const char* output_path) { CfreeObjFile* of = NULL; CfreeObjBuilder* b; CfreeWriter* w = NULL; CfreeStatus st; int rc = 1; - if (cfree_obj_open(ctx, input, &of) != CFREE_OK) { - driver_errf(OBJCOPY_TOOL, "%s: not a recognized object", input->name); + if (cfree_obj_open(ctx, cfree_slice_cstr(input_name), input, &of) != + CFREE_OK) { + driver_errf(OBJCOPY_TOOL, "%.*s: not a recognized object", + CFREE_SLICE_ARG(cfree_slice_cstr(input_name))); return 1; } b = cfree_obj_file_builder(of); if (!b) { - driver_errf(OBJCOPY_TOOL, "%s: no builder", input->name); + driver_errf(OBJCOPY_TOOL, "%.*s: no builder", + CFREE_SLICE_ARG(cfree_slice_cstr(input_name))); cfree_obj_free(of); return 1; } @@ -491,7 +503,8 @@ static int copy_one_object(DriverEnv* env, const CfreeContext* ctx, } if (ctx->file_io->open_writer(ctx->file_io->user, output_path, &w) != CFREE_OK) { - driver_errf(OBJCOPY_TOOL, "cannot open %s", output_path); + driver_errf(OBJCOPY_TOOL, "cannot open %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(output_path))); cfree_obj_free(of); return 1; } @@ -517,7 +530,7 @@ int driver_objcopy(int argc, char** argv) { CfreeContext ctx; CopyOpts opts; CfreeFileData in_fd = {0}; - CfreeBytes input; + CfreeSlice input; int have_in = 0; int rc = 1; int i; @@ -556,7 +569,8 @@ int driver_objcopy(int argc, char** argv) { goto done; } if (parse_fmt_name(argv[++i], &opts.output_fmt) != 0) { - driver_errf(OBJCOPY_TOOL, "unknown output format: %s", argv[i]); + driver_errf(OBJCOPY_TOOL, "unknown output format: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(argv[i]))); rc = 2; goto done; } @@ -584,8 +598,8 @@ int driver_objcopy(int argc, char** argv) { if (matched) { const char *left, *right; if (split_pair(&env, val, &left, &right) != 0) { - driver_errf(OBJCOPY_TOOL, "rename-section: expected OLD=NEW (got %s)", - val); + driver_errf(OBJCOPY_TOOL, "rename-section: expected OLD=NEW (got %.*s)", + CFREE_SLICE_ARG(cfree_slice_cstr(val))); rc = 2; goto done; } @@ -599,8 +613,8 @@ int driver_objcopy(int argc, char** argv) { if (matched) { const char *left, *right; if (split_pair(&env, val, &left, &right) != 0) { - driver_errf(OBJCOPY_TOOL, "add-section: expected NAME=FILE (got %s)", - val); + driver_errf(OBJCOPY_TOOL, "add-section: expected NAME=FILE (got %.*s)", + CFREE_SLICE_ARG(cfree_slice_cstr(val))); rc = 2; goto done; } @@ -614,8 +628,8 @@ int driver_objcopy(int argc, char** argv) { if (matched) { const char *left, *right; if (split_pair(&env, val, &left, &right) != 0) { - driver_errf(OBJCOPY_TOOL, "update-section: expected NAME=FILE (got %s)", - val); + driver_errf(OBJCOPY_TOOL, "update-section: expected NAME=FILE (got %.*s)", + CFREE_SLICE_ARG(cfree_slice_cstr(val))); rc = 2; goto done; } @@ -629,8 +643,8 @@ int driver_objcopy(int argc, char** argv) { if (matched) { const char *left, *right; if (split_pair(&env, val, &left, &right) != 0) { - driver_errf(OBJCOPY_TOOL, "redefine-sym: expected OLD=NEW (got %s)", - val); + driver_errf(OBJCOPY_TOOL, "redefine-sym: expected OLD=NEW (got %.*s)", + CFREE_SLICE_ARG(cfree_slice_cstr(val))); rc = 2; goto done; } @@ -662,7 +676,8 @@ int driver_objcopy(int argc, char** argv) { continue; } if (a[0] == '-' && a[1] != '\0') { - driver_errf(OBJCOPY_TOOL, "unknown option: %s", a); + driver_errf(OBJCOPY_TOOL, "unknown option: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(a))); rc = 2; goto done; } @@ -671,7 +686,8 @@ int driver_objcopy(int argc, char** argv) { } else if (!opts.output) { opts.output = a; } else { - driver_errf(OBJCOPY_TOOL, "unexpected argument: %s", a); + driver_errf(OBJCOPY_TOOL, "unexpected argument: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(a))); rc = 2; goto done; } @@ -686,15 +702,15 @@ int driver_objcopy(int argc, char** argv) { if (ctx.file_io->read_all(ctx.file_io->user, opts.input, &in_fd) != CFREE_OK) { - driver_errf(OBJCOPY_TOOL, "cannot read %s", opts.input); + driver_errf(OBJCOPY_TOOL, "cannot read %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(opts.input))); goto done; } have_in = 1; - input.name = opts.input; input.data = in_fd.data; input.len = in_fd.size; - rc = copy_one_object(&env, &ctx, &input, &opts, out_path); + rc = copy_one_object(&env, &ctx, opts.input, &input, &opts, out_path); done: if (have_in) ctx.file_io->release(ctx.file_io->user, &in_fd); @@ -729,7 +745,8 @@ done: return rc; missing_value: - driver_errf(OBJCOPY_TOOL, "%s requires a value", argv[i]); + driver_errf(OBJCOPY_TOOL, "%.*s requires a value", + CFREE_SLICE_ARG(cfree_slice_cstr(argv[i]))); rc = 2; goto done; oom: diff --git a/driver/objdump.c b/driver/objdump.c @@ -30,15 +30,17 @@ typedef struct ObjdumpOpts { } ObjdumpOpts; static void objdump_usage(void) { - driver_errf(OBJDUMP_TOOL, "%s", + driver_errf(OBJDUMP_TOOL, "%.*s", + CFREE_SLICE_ARG(CFREE_SLICE_LIT( "usage: cfree objdump [-h] [-t] [-d] [-D] [-r] [-s] [-j NAME " "...] input...\n" - " cfree objdump --help for full option reference"); + " cfree objdump --help for full option reference"))); } void driver_help_objdump(void) { driver_printf( - "%s", + "%.*s", + CFREE_SLICE_ARG(CFREE_SLICE_LIT( "cfree objdump — print info about object files and archives\n" "\n" "USAGE\n" @@ -94,7 +96,7 @@ void driver_help_objdump(void) { "\n" "EXIT CODES\n" " 0 success 1 parse / I/O error 2 bad " - "usage\n"); + "usage\n"))); } /* ---- PE/COFF private-header walker (used by `-p`) ---- @@ -140,7 +142,7 @@ void driver_help_objdump(void) { #define OBJDUMP_IMAGE_SCN_MEM_DISCARDABLE 0x02000000u #define OBJDUMP_IMAGE_SCN_MEM_SHARED 0x10000000u -static int j_match(const ObjdumpOpts* o, const char* name); +static int j_match(const ObjdumpOpts* o, CfreeSlice name); static uint16_t pe_rd_u16(const uint8_t* p) { return (uint16_t)(p[0] | ((uint32_t)p[1] << 8)); @@ -302,7 +304,9 @@ static void pe_dump_imports(const uint8_t* buf, size_t buf_len, size_t sec_off, dll[0] = '\0'; } } - driver_printf(" DLL Name: %s\n", dll[0] ? dll : "(unreadable)"); + driver_printf(" DLL Name: %.*s\n", + CFREE_SLICE_ARG(cfree_slice_cstr(dll[0] ? dll + : "(unreadable)"))); driver_printf(" ILT RVA: 0x%x IAT RVA: 0x%x\n", ilt_rva, iat_rva); /* Prefer walking the original first thunk (ILT) for names. Some * mingw-emitted images zero the ILT and only ship the IAT; fall @@ -330,7 +334,8 @@ static void pe_dump_imports(const uint8_t* buf, size_t buf_len, size_t sec_off, sizeof name) != 0) { continue; } - driver_printf(" Name: %s\n", name); + driver_printf(" Name: %.*s\n", + CFREE_SLICE_ARG(cfree_slice_cstr(name))); } } } @@ -410,17 +415,20 @@ static const char* pe_machine_name(uint16_t m) { * Counterpart to dump_file_header for inputs that cfree_obj_open can't * parse yet (PE executables / DLLs vs .obj). */ static void dump_pe_file_header(const char* label, const PeImage* pe) { - driver_printf("%s:\tfile format pei-%s\n\n", label, - pe_machine_name(pe->machine)); - driver_printf("architecture: %s, flags 0x%04x\n", - pe_machine_name(pe->machine), (unsigned)pe->file_chars); + driver_printf("%.*s:\tfile format pei-%.*s\n\n", + CFREE_SLICE_ARG(cfree_slice_cstr(label)), + CFREE_SLICE_ARG(cfree_slice_cstr(pe_machine_name(pe->machine)))); + driver_printf("architecture: %.*s, flags 0x%04x\n", + CFREE_SLICE_ARG(cfree_slice_cstr(pe_machine_name(pe->machine))), + (unsigned)pe->file_chars); if (pe->opt_magic == PE_OPT_HDR64_MAGIC) { driver_printf("start address 0x%016llx\n", (unsigned long long)(pe->image_base + pe->entry_rva)); driver_printf( - "image base: 0x%llx, entry rva: 0x%x, subsystem: %u (%s)\n\n", + "image base: 0x%llx, entry rva: 0x%x, subsystem: %u (%.*s)\n\n", (unsigned long long)pe->image_base, pe->entry_rva, - (unsigned)pe->subsystem, pe_subsystem_name(pe->subsystem)); + (unsigned)pe->subsystem, + CFREE_SLICE_ARG(cfree_slice_cstr(pe_subsystem_name(pe->subsystem)))); } else { driver_printf("PE32 (magic 0x%x) — only PE32+ inspection is implemented\n\n", (unsigned)pe->opt_magic); @@ -468,7 +476,8 @@ static void dump_pe_sections(const char* label, const PeImage* pe, uint16_t i; char flagbuf[160]; char name[9]; - driver_printf("%s:\tSections (PE image):\n", label); + driver_printf("%.*s:\tSections (PE image):\n", + CFREE_SLICE_ARG(cfree_slice_cstr(label))); driver_printf("Idx Name VMA Size " "FileOff Align Flags\n"); for (i = 0; i < pe->nsec; ++i) { @@ -491,11 +500,12 @@ static void dump_pe_sections(const char* label, const PeImage* pe, ch = pe_rd_u32(buf + sh + 36); align_field = (ch >> 20) & 0xFu; align_log2 = align_field ? (align_field - 1u) : 0u; - if (!j_match(opts, name)) continue; + if (!j_match(opts, cfree_slice_cstr(name))) continue; render_pe_sec_flags(ch, flagbuf, sizeof(flagbuf)); - driver_printf("%3u %-16s %016llx %08x %08x 2**%-2u %s\n", (unsigned)i, + driver_printf("%3u %-16s %016llx %08x %08x 2**%-2u %.*s\n", (unsigned)i, name, (unsigned long long)(pe->image_base + va), - vsize ? vsize : raw_size, raw_off, align_log2, flagbuf); + vsize ? vsize : raw_size, raw_off, align_log2, + CFREE_SLICE_ARG(cfree_slice_cstr(flagbuf))); driver_printf(" Characteristics: 0x%08x\n", ch); } @@ -514,21 +524,24 @@ static void dump_pe_private(const char* label, const uint8_t* buf, uint32_t i; if (!pe_parse_image(buf, buf_len, &pe) || !pe.valid) return; if (pe.opt_magic != PE_OPT_HDR64_MAGIC) { - driver_printf("%s:\tPE optional header magic 0x%x (PE32) — skipping\n", - label, (unsigned)pe.opt_magic); + driver_printf("%.*s:\tPE optional header magic 0x%x (PE32) — skipping\n", + CFREE_SLICE_ARG(cfree_slice_cstr(label)), + (unsigned)pe.opt_magic); return; } - driver_printf("\n%s:\tPE32+ private headers\n", label); + driver_printf("\n%.*s:\tPE32+ private headers\n", + CFREE_SLICE_ARG(cfree_slice_cstr(label))); driver_printf(" Magic: 0x%x (PE32+)\n", pe.opt_magic); - driver_printf(" Machine: 0x%04x (%s)\n", (unsigned)pe.machine, - pe_machine_name(pe.machine)); + driver_printf(" Machine: 0x%04x (%.*s)\n", (unsigned)pe.machine, + CFREE_SLICE_ARG(cfree_slice_cstr(pe_machine_name(pe.machine)))); driver_printf(" Characteristics: 0x%04x\n", (unsigned)pe.file_chars); driver_printf(" ImageBase: 0x%llx\n", (unsigned long long)pe.image_base); driver_printf(" AddressOfEntryPoint: 0x%x\n", pe.entry_rva); - driver_printf(" Subsystem: %u (%s)\n", (unsigned)pe.subsystem, - pe_subsystem_name(pe.subsystem)); + driver_printf(" Subsystem: %u (%.*s)\n", (unsigned)pe.subsystem, + CFREE_SLICE_ARG( + cfree_slice_cstr(pe_subsystem_name(pe.subsystem)))); driver_printf(" DllCharacteristics: 0x%04x\n", (unsigned)pe.dllchars); driver_printf(" NumberOfSections: %u\n", (unsigned)pe.nsec); @@ -626,11 +639,11 @@ static char sym_kind_char(CfreeSymKind k) { return ' '; } -static int j_match(const ObjdumpOpts* o, const char* name) { +static int j_match(const ObjdumpOpts* o, CfreeSlice name) { int i; if (o->nj == 0) return 1; for (i = 0; i < o->nj; ++i) { - if (driver_streq(o->j[i], name)) return 1; + if (cfree_slice_eq_cstr(name, o->j[i])) return 1; } return 0; } @@ -677,7 +690,8 @@ static void render_sec_flags(const CfreeObjSecInfo* sec, CfreeObjFmt fmt, } if (sec->entsize && n + 1 < cap) { char tmp[32]; - int k = snprintf(tmp, sizeof tmp, "%sentsize=%u", n ? "," : "", + int k = snprintf(tmp, sizeof tmp, "%.*sentsize=%u", + CFREE_SLICE_ARG(cfree_slice_cstr(n ? "," : "")), sec->entsize); size_t j; for (j = 0; k > 0 && j < (size_t)k && n + 1 < cap; ++j) @@ -702,10 +716,10 @@ static void dump_sections(CfreeObjFile* f, const ObjdumpOpts* opts) { cfree_obj_section_format_flags(f, i, &raw_type, NULL); render_sec_flags(&sec, fmt, raw_type, flagbuf, sizeof(flagbuf)); driver_printf( - "%3u %-20s %08llx 2**%-2u %s\n", i, sec.name[0] ? sec.name : "(anon)", - (unsigned long long)sec.size, + "%3u %-20s %08llx 2**%-2u %.*s\n", i, + sec.name.len ? sec.name.s : "(anon)", (unsigned long long)sec.size, sec.align ? (unsigned)__builtin_ctz(sec.align ? sec.align : 1) : 0, - flagbuf); + CFREE_SLICE_ARG(cfree_slice_cstr(flagbuf))); /* Show the raw IMAGE_SCN_* value on a continuation line for COFF * inputs — useful when diagnosing why a section ended up with the * tags it did. The hex is much shorter than printing every set bit @@ -736,17 +750,19 @@ static void dump_groups(CfreeObjFile* f, const ObjdumpOpts* opts) { driver_printf("COMDAT groups:\n"); printed_header = 1; } - driver_printf(" group %s (signature sym #%u, %u section%s)\n", - g.name && g.name[0] ? g.name : "(anon)", + driver_printf(" group %.*s (signature sym #%u, %u section%.*s)\n", + CFREE_SLICE_ARG(g.name.len ? g.name + : CFREE_SLICE_LIT("(anon)")), (unsigned)g.signature, (unsigned)g.nsections, - g.nsections == 1 ? "" : "s"); + CFREE_SLICE_ARG(cfree_slice_cstr(g.nsections == 1 ? "" : "s"))); for (k = 0; k < g.nsections; ++k) { CfreeObjSection sid = g.sections[k]; CfreeObjSecInfo si; if (sid == CFREE_SECTION_NONE) continue; if (cfree_obj_section(f, sid, &si) != CFREE_OK) continue; - driver_printf(" [%3u] %s\n", (unsigned)sid, - si.name && si.name[0] ? si.name : "(anon)"); + driver_printf(" [%3u] %.*s\n", (unsigned)sid, + CFREE_SLICE_ARG(si.name.len ? si.name + : CFREE_SLICE_LIT("(anon)"))); } } cfree_obj_groupiter_free(it); @@ -761,20 +777,21 @@ static void dump_symbols(CfreeObjFile* f, const ObjdumpOpts* opts) { if (cfree_obj_symiter_new(f, &it) != CFREE_OK) return; for (;;) { CfreeIterResult r = cfree_obj_symiter_next(it, &sym); - const char* secname; + CfreeSlice secname; if (r != CFREE_ITER_ITEM) break; if (sym.section == CFREE_SECTION_NONE) { - secname = "*UND*"; + secname = CFREE_SLICE_LIT("*UND*"); } else { CfreeObjSecInfo sec; if (cfree_obj_section(f, sym.section, &sec) != CFREE_OK) continue; - secname = sec.name[0] ? sec.name : "(none)"; + secname = sec.name.len ? sec.name : CFREE_SLICE_LIT("(none)"); if (opts->nj && !j_match(opts, secname)) continue; } driver_printf( - "%016llx %c %c %-18s %016llx %s\n", (unsigned long long)sym.value, - sym_bind_char(sym.bind), sym_kind_char(sym.kind), secname, - (unsigned long long)sym.size, sym.name[0] ? sym.name : "(none)"); + "%016llx %c %c %-18s %016llx %.*s\n", (unsigned long long)sym.value, + sym_bind_char(sym.bind), sym_kind_char(sym.kind), secname.s, + (unsigned long long)sym.size, + CFREE_SLICE_ARG(sym.name.len ? sym.name : CFREE_SLICE_LIT("(none)"))); } cfree_obj_symiter_free(it); driver_printf("\n"); @@ -795,8 +812,9 @@ static void dump_hex(CfreeObjFile* f, const ObjdumpOpts* opts) { if (cfree_obj_section_data(f, i, &data, &len) != CFREE_OK) continue; if (!data || len == 0) continue; - driver_printf("Contents of section %s:\n", - sec.name[0] ? sec.name : "(anon)"); + driver_printf("Contents of section %.*s:\n", + CFREE_SLICE_ARG(sec.name.len ? sec.name + : CFREE_SLICE_LIT("(anon)"))); for (ofs = 0; ofs < len; ofs += 16) { size_t j; char ascii[17]; @@ -814,7 +832,7 @@ static void dump_hex(CfreeObjFile* f, const ObjdumpOpts* opts) { if ((j & 1) == 1) driver_printf(" "); } ascii[16] = '\0'; - driver_printf(" %s\n", ascii); + driver_printf(" %.*s\n", CFREE_SLICE_ARG(cfree_slice_cstr(ascii))); } } driver_printf("\n"); @@ -837,23 +855,27 @@ static void dump_relocs(CfreeObjFile* f, const ObjdumpOpts* opts) { if (r.section != cur_sec) { if (printed_header) driver_printf("\n"); - driver_printf("RELOCATION RECORDS FOR [%s]:\n", - sec.name[0] ? sec.name : "(anon)"); + driver_printf("RELOCATION RECORDS FOR [%.*s]:\n", + CFREE_SLICE_ARG(sec.name.len ? sec.name + : CFREE_SLICE_LIT("(anon)"))); driver_printf("OFFSET TYPE VALUE\n"); cur_sec = r.section; printed_header = 1; } if (r.addend) { - driver_printf("%016llx %-17s %s%c0x%llx\n", (unsigned long long)r.offset, - r.kind_name ? r.kind_name : "?", - r.sym_name && r.sym_name[0] ? r.sym_name : "*ABS*", + driver_printf("%016llx %-17s %.*s%c0x%llx\n", + (unsigned long long)r.offset, + r.kind_name.len ? r.kind_name.s : "?", + CFREE_SLICE_ARG(r.sym_name.len ? r.sym_name + : CFREE_SLICE_LIT("*ABS*")), r.addend < 0 ? '-' : '+', (unsigned long long)(r.addend < 0 ? -r.addend : r.addend)); } else { - driver_printf("%016llx %-17s %s\n", (unsigned long long)r.offset, - r.kind_name ? r.kind_name : "?", - r.sym_name && r.sym_name[0] ? r.sym_name : "*ABS*"); + driver_printf("%016llx %-17s %.*s\n", (unsigned long long)r.offset, + r.kind_name.len ? r.kind_name.s : "?", + CFREE_SLICE_ARG(r.sym_name.len ? r.sym_name + : CFREE_SLICE_LIT("*ABS*"))); } emitted_any = 1; } @@ -861,18 +883,18 @@ static void dump_relocs(CfreeObjFile* f, const ObjdumpOpts* opts) { if (emitted_any) driver_printf("\n"); } -static const char* objdump_sym_at(CfreeObjFile* f, uint32_t section_idx, - uint64_t value) { +static CfreeSlice objdump_sym_at(CfreeObjFile* f, uint32_t section_idx, + uint64_t value) { CfreeObjSymIter* it = NULL; CfreeObjSymInfo sym; - const char* best = NULL; + CfreeSlice best = CFREE_SLICE_NULL; - if (cfree_obj_symiter_new(f, &it) != CFREE_OK) return NULL; + if (cfree_obj_symiter_new(f, &it) != CFREE_OK) return CFREE_SLICE_NULL; for (;;) { CfreeIterResult r = cfree_obj_symiter_next(it, &sym); if (r != CFREE_ITER_ITEM) break; if (sym.section != section_idx || sym.value != value) continue; - if (!sym.name || !sym.name[0]) continue; + if (!sym.name.len) continue; if (sym.kind == CFREE_SK_SECTION) continue; best = sym.name; if (sym.kind == CFREE_SK_FUNC || sym.bind != CFREE_SB_LOCAL) break; @@ -907,29 +929,30 @@ static void dump_disasm(const CfreeDisasmContext* dctx, CfreeObjFile* f, if (cfree_obj_section_data(f, i, &data, &len) != CFREE_OK) continue; if (!data || len == 0) continue; - driver_printf("Disassembly of section %s:\n\n", - sec.name[0] ? sec.name : "(anon)"); + driver_printf("Disassembly of section %.*s:\n\n", + CFREE_SLICE_ARG(sec.name.len ? sec.name + : CFREE_SLICE_LIT("(anon)"))); if (cfree_disasm_iter_new(&file_dctx, data, len, 0, f, &dis) != CFREE_OK) continue; for (;;) { CfreeIterResult r = cfree_disasm_iter_next(dis, &insn); uint32_t b; - const char* label; + CfreeSlice label; if (r != CFREE_ITER_ITEM) break; label = objdump_sym_at(f, i, insn.vaddr); - if (label) - driver_printf("%016llx <%s>:\n", (unsigned long long)insn.vaddr, - label); + if (label.len) + driver_printf("%016llx <%.*s>:\n", (unsigned long long)insn.vaddr, + CFREE_SLICE_ARG(label)); driver_printf("%8llx:\t", (unsigned long long)insn.vaddr); for (b = 0; b < insn.nbytes; ++b) driver_printf("%02x ", insn.bytes[b]); for (b = insn.nbytes; b < 8; ++b) driver_printf(" "); - driver_printf("\t%s", insn.mnemonic ? insn.mnemonic : ""); - if (insn.operands && insn.operands[0]) { - driver_printf(" %s", insn.operands); + driver_printf("\t%.*s", CFREE_SLICE_ARG(insn.mnemonic)); + if (insn.operands.len) { + driver_printf(" %.*s", CFREE_SLICE_ARG(insn.operands)); } - if (insn.annotation && insn.annotation[0]) { - driver_printf(" # %s", insn.annotation); + if (insn.annotation.len) { + driver_printf(" # %.*s", CFREE_SLICE_ARG(insn.annotation)); } driver_printf("\n"); } @@ -969,14 +992,15 @@ static void dump_file_header(CfreeObjFile* f, const char* label) { if (has_relocs) flags |= 0x0001u; if (nsym) flags |= 0x0010u; - driver_printf("architecture: %s, flags 0x%08x:\n", arch_str(target.arch), - flags); + driver_printf("architecture: %.*s, flags 0x%08x:\n", + CFREE_SLICE_ARG(cfree_slice_cstr(arch_str(target.arch))), flags); if (has_relocs) driver_printf("HAS_RELOC, "); if (nsym) driver_printf("HAS_SYMS"); if (has_relocs || nsym) driver_printf("\n"); driver_printf("start address 0x%016llx\n", 0ull); - driver_printf("format: %s, sections: %u, symbols: %u\n\n", - fmt_str(fmt, target.ptr_size), nsec, nsym); + driver_printf("format: %.*s, sections: %u, symbols: %u\n\n", + CFREE_SLICE_ARG(cfree_slice_cstr(fmt_str(fmt, target.ptr_size))), + nsec, nsym); (void)label; } @@ -985,8 +1009,10 @@ static void dump_obj(const CfreeDisasmContext* dctx, const char* label, CfreeTarget target = cfree_obj_target(f); CfreeObjFmt fmt = cfree_obj_fmt(f); - driver_printf("%s:\tfile format %s-%s\n\n", label, - fmt_str(fmt, target.ptr_size), arch_str(target.arch)); + driver_printf("%.*s:\tfile format %.*s-%.*s\n\n", + CFREE_SLICE_ARG(cfree_slice_cstr(label)), + CFREE_SLICE_ARG(cfree_slice_cstr(fmt_str(fmt, target.ptr_size))), + CFREE_SLICE_ARG(cfree_slice_cstr(arch_str(target.arch)))); if (opts->f) dump_file_header(f, label); if (opts->h) dump_sections(f, opts); @@ -997,7 +1023,7 @@ static void dump_obj(const CfreeDisasmContext* dctx, const char* label, if (opts->r) dump_relocs(f, opts); } -static int dump_archive(const char* path, const CfreeBytes* input, +static int dump_archive(const char* path, const CfreeSlice* input, const CfreeContext* ctx, const CfreeDisasmContext* dctx, const ObjdumpOpts* opts) { @@ -1006,12 +1032,13 @@ static int dump_archive(const char* path, const CfreeBytes* input, char label[256]; int j; - driver_printf("In archive %s:\n\n", path); + driver_printf("In archive %.*s:\n\n", + CFREE_SLICE_ARG(cfree_slice_cstr(path))); if (cfree_ar_iter_new(ctx, input, &it) != CFREE_OK) return 1; for (;;) { CfreeIterResult r = cfree_ar_iter_next(it, &member); - CfreeBytes min; + CfreeSlice min; CfreeObjFile* f = NULL; if (r != CFREE_ITER_ITEM) break; @@ -1023,18 +1050,18 @@ static int dump_archive(const char* path, const CfreeBytes* input, } label[j++] = '('; { - const char* p = member.name; - while (*p && j < 252) label[j++] = *p++; + size_t k = 0; + while (k < member.name.len && j < 252) label[j++] = member.name.s[k++]; } label[j++] = ')'; label[j] = '\0'; - min.name = member.name; min.data = member.data; min.len = member.size; - if (cfree_obj_open(ctx, &min, &f) != CFREE_OK) { - driver_errf(OBJDUMP_TOOL, "failed to parse member: %s", label); + if (cfree_obj_open(ctx, member.name, &min, &f) != CFREE_OK) { + driver_errf(OBJDUMP_TOOL, "failed to parse member: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(label))); continue; } dump_obj(dctx, label, f, opts); @@ -1153,12 +1180,14 @@ int driver_objdump(int argc, char** argv) { if (a[0] != '-' || a[1] == '\0') continue; if (driver_streq(a, "-j")) { if (i + 1 >= argc) { - driver_errf(OBJDUMP_TOOL, "%s", "-j requires a section name"); + driver_errf(OBJDUMP_TOOL, "%.*s", + CFREE_SLICE_ARG(CFREE_SLICE_LIT("-j requires a section name"))); rc = 2; goto done; } if (opts.nj >= MAX_J_FILTERS) { - driver_errf(OBJDUMP_TOOL, "%s", "too many -j filters"); + driver_errf(OBJDUMP_TOOL, "%.*s", + CFREE_SLICE_ARG(CFREE_SLICE_LIT("too many -j filters"))); rc = 2; goto done; } @@ -1192,7 +1221,7 @@ int driver_objdump(int argc, char** argv) { for (i = 1; i < argc && rc == 0; ++i) { const char* a = argv[i]; CfreeFileData fd = {0}; - CfreeBytes input; + CfreeSlice input; CfreeBinFmt bin; if (a[0] == '-' && a[1] != '\0') { @@ -1202,12 +1231,12 @@ int driver_objdump(int argc, char** argv) { saw_input = 1; if (ctx.file_io->read_all(ctx.file_io->user, a, &fd) != CFREE_OK) { - driver_errf(OBJDUMP_TOOL, "failed to read: %s", a); + driver_errf(OBJDUMP_TOOL, "failed to read: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(a))); rc = 1; break; } - input.name = a; input.data = fd.data; input.len = fd.size; @@ -1227,7 +1256,7 @@ int driver_objdump(int argc, char** argv) { * -h / -p by walking the raw image bytes; -t / -d / -r / -s * still need an ObjFile and are skipped with a soft error so * the other ops don't get swallowed. */ - if (cfree_obj_open(&ctx, &input, &f) != CFREE_OK) { + if (cfree_obj_open(&ctx, cfree_slice_cstr(a), &input, &f) != CFREE_OK) { if (bin == CFREE_BIN_PE) { PeImage pe; int parsed = pe_parse_image(input.data, input.len, &pe) && pe.valid; @@ -1246,13 +1275,14 @@ int driver_objdump(int argc, char** argv) { } if (!handled) { driver_errf(OBJDUMP_TOOL, - "%s: PE images support only -f / -h / -p; " + "%.*s: PE images support only -f / -h / -p; " "use -p for image details", - a); + CFREE_SLICE_ARG(cfree_slice_cstr(a))); rc = 1; } } else { - driver_errf(OBJDUMP_TOOL, "failed to parse: %s", a); + driver_errf(OBJDUMP_TOOL, "failed to parse: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(a))); rc = 1; } } else { @@ -1266,7 +1296,8 @@ int driver_objdump(int argc, char** argv) { } case CFREE_BIN_UNKNOWN: default: - driver_errf(OBJDUMP_TOOL, "unsupported file format: %s", a); + driver_errf(OBJDUMP_TOOL, "unsupported file format: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(a))); rc = 1; break; } diff --git a/driver/ranlib.c b/driver/ranlib.c @@ -24,7 +24,8 @@ void driver_help_ranlib(void) { driver_printf( - "%s", + "%.*s", + CFREE_SLICE_ARG(CFREE_SLICE_LIT( "cfree ranlib — refresh the symbol index of an `ar` archive\n" "\n" "USAGE\n" @@ -45,7 +46,7 @@ void driver_help_ranlib(void) { "\n" "EXIT CODES\n" " 0 success 1 archive I/O error 2 bad " - "usage\n"); + "usage\n"))); } static uint64_t ranlib_epoch_from_env(void) { @@ -63,10 +64,10 @@ int driver_ranlib(int argc, char** argv) { DriverEnv env; CfreeContext ctx; CfreeFileData old_fd = {0}; - CfreeBytes input; + CfreeSlice input; CfreeArIter* it = NULL; CfreeArMember m; - CfreeBytes* members = NULL; + CfreeArInput* members = NULL; char* name_storage = NULL; size_t name_bytes_total = 0; uint32_t nmembers = 0; @@ -95,11 +96,11 @@ int driver_ranlib(int argc, char** argv) { if (ctx.file_io->read_all(ctx.file_io->user, archive_path, &old_fd) != CFREE_OK) { - driver_errf(RANLIB_TOOL, "failed to read: %s", archive_path); + driver_errf(RANLIB_TOOL, "failed to read: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(archive_path))); goto out; } have_old = 1; - input.name = archive_path; input.data = old_fd.data; input.len = old_fd.size; @@ -107,14 +108,15 @@ int driver_ranlib(int argc, char** argv) { * the iterator alias an internal buffer overwritten on each next(), so * we stash a stable copy). */ if (cfree_ar_iter_new(&ctx, &input, &it) != CFREE_OK) { - driver_errf(RANLIB_TOOL, "not an archive: %s", archive_path); + driver_errf(RANLIB_TOOL, "not an archive: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(archive_path))); goto out; } for (;;) { CfreeIterResult r = cfree_ar_iter_next(it, &m); if (r != CFREE_ITER_ITEM) break; nmembers++; - name_bytes_total += driver_strlen(m.name) + 1; + name_bytes_total += m.name.len + 1; } cfree_ar_iter_free(it); it = NULL; @@ -124,7 +126,8 @@ int driver_ranlib(int argc, char** argv) { * GNU ranlib's behaviour). */ if (ctx.file_io->open_writer(ctx.file_io->user, archive_path, &out) != CFREE_OK) { - driver_errf(RANLIB_TOOL, "failed to open: %s", archive_path); + driver_errf(RANLIB_TOOL, "failed to open: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(archive_path))); goto out; } opts.epoch = ranlib_epoch_from_env(); @@ -134,7 +137,7 @@ int driver_ranlib(int argc, char** argv) { goto out; } - members = (CfreeBytes*)driver_alloc_zeroed( + members = (CfreeArInput*)driver_alloc_zeroed( &env, (size_t)nmembers * sizeof(*members)); if (!members) { driver_errf(RANLIB_TOOL, "out of memory"); @@ -159,14 +162,15 @@ int driver_ranlib(int argc, char** argv) { while (k < nmembers) { CfreeIterResult r = cfree_ar_iter_next(it, &m); char* dst; - const char* p; + size_t j; if (r != CFREE_ITER_ITEM) break; dst = name_storage + cursor; - for (p = m.name; *p; ++p) *dst++ = *p; + for (j = 0; j < m.name.len; ++j) *dst++ = m.name.s[j]; *dst++ = '\0'; - members[k].name = name_storage + cursor; - members[k].data = m.data; - members[k].len = m.size; + members[k].name.s = name_storage + cursor; + members[k].name.len = m.name.len; + members[k].bytes.data = m.data; + members[k].bytes.len = m.size; cursor = (size_t)(dst - name_storage); k++; } @@ -188,9 +192,9 @@ int driver_ranlib(int argc, char** argv) { for (i = 0; i < nmembers; ++i) { void* blob = NULL; size_t blob_size = 0; - const char** names = NULL; + const CfreeSlice* names = NULL; uint32_t count = 0; - if (driver_collect_obj_global_syms(&env, &ctx, RANLIB_TOOL, &members[i], + if (driver_collect_obj_global_syms(&env, &ctx, RANLIB_TOOL, &members[i].bytes, &blob, &blob_size, &names, &count) != 0) { goto out; @@ -203,7 +207,8 @@ int driver_ranlib(int argc, char** argv) { if (ctx.file_io->open_writer(ctx.file_io->user, archive_path, &out) != CFREE_OK) { - driver_errf(RANLIB_TOOL, "failed to open: %s", archive_path); + driver_errf(RANLIB_TOOL, "failed to open: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(archive_path))); goto out; } opts.epoch = ranlib_epoch_from_env(); diff --git a/driver/run.c b/driver/run.c @@ -191,14 +191,17 @@ static void run_metrics_finish(RunMetrics* m) { const RunMetricEvent* e = &seg->events[i]; if (e->kind == RUN_METRIC_EVENT_SCOPE) { if (m->bench_time) { - driver_logf("cfree-run %s -- %.3f msec", e->name, + driver_logf("cfree-run %.*s -- %.3f msec", + CFREE_SLICE_ARG(cfree_slice_cstr(e->name)), (double)e->value / 1000000.0); } else { - driver_logf("%*s%s %.3f ms", (int)((unsigned)e->depth * 2u), "", - e->name, (double)e->value / 1000000.0); + driver_logf("%*s%.*s %.3f ms", (int)((unsigned)e->depth * 2u), "", + CFREE_SLICE_ARG(cfree_slice_cstr(e->name)), + (double)e->value / 1000000.0); } } else { - driver_logf("%*s%s=%llu", (int)((unsigned)e->depth * 2u), "", e->name, + driver_logf("%*s%.*s=%llu", (int)((unsigned)e->depth * 2u), "", + CFREE_SLICE_ARG(cfree_slice_cstr(e->name)), (unsigned long long)e->value); } } @@ -217,18 +220,21 @@ static void run_metrics_finish(RunMetrics* m) { } static void run_bench_time(const char* name, uint64_t ns) { - driver_logf("cfree-run %s -- %.3f msec", name, (double)ns / 1000000.0); + driver_logf("cfree-run %.*s -- %.3f msec", + CFREE_SLICE_ARG(cfree_slice_cstr(name)), (double)ns / 1000000.0); } static void run_usage(void) { - driver_errf(RUN_TOOL, "%s", - "usage: cfree run [options] inputs... [-- prog-arg...]\n" - " cfree run --help for full option reference"); + driver_errf(RUN_TOOL, "%.*s", + CFREE_SLICE_ARG(CFREE_SLICE_LIT( + "usage: cfree run [options] inputs... [-- prog-arg...]\n" + " cfree run --help for full option reference"))); } void driver_help_run(void) { driver_printf( - "%s", + "%.*s", + CFREE_SLICE_ARG(CFREE_SLICE_LIT( "cfree run — JIT-compile inputs and invoke the entry symbol in-process\n" "\n" "USAGE\n" @@ -295,7 +301,7 @@ void driver_help_run(void) { "\n" "EXIT CODES\n" " Returns the exit code of the JITed entry, or 1 on internal failure.\n" - " 2 on bad command-line usage.\n"); + " 2 on bad command-line usage.\n"))); } static int run_alloc_arrays(RunOptions* o, int argc) { @@ -348,7 +354,8 @@ static int run_record_mcmodel(RunOptions* o, const char* val) { o->target.code_model = CFREE_CM_LARGE; return 0; } - driver_errf(RUN_TOOL, "unknown -mcmodel value: %s", val); + driver_errf(RUN_TOOL, "unknown -mcmodel value: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(val))); return 1; } @@ -356,7 +363,8 @@ static int run_classify_positional(RunOptions* o, const char* a) { int r = driver_inputs_classify(&o->inputs, a); if (r < 0) return 1; if (r == 0) { - driver_errf(RUN_TOOL, "input does not have a recognized suffix: %s", a); + driver_errf(RUN_TOOL, "input does not have a recognized suffix: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(a))); return 1; } return 0; @@ -483,14 +491,16 @@ static int run_parse(int argc, char** argv, RunOptions* o) { return 1; } if (driver_target_from_triple(argv[i], &o->target) != 0) { - driver_errf(RUN_TOOL, "unrecognized target triple: %s", argv[i]); + driver_errf(RUN_TOOL, "unrecognized target triple: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(argv[i]))); return 1; } continue; } if (driver_streq(a, "--sysroot") || driver_streq(a, "-isysroot")) { if (++i >= argc) { - driver_errf(RUN_TOOL, "%s requires an argument", a); + driver_errf(RUN_TOOL, "%.*s requires an argument", + CFREE_SLICE_ARG(cfree_slice_cstr(a))); return 1; } o->sysroot = argv[i]; @@ -510,8 +520,8 @@ static int run_parse(int argc, char** argv, RunOptions* o) { return 1; } if (!driver_streq(argv[i], "c")) { - driver_errf(RUN_TOOL, "unsupported hosted library for JIT: -l%s", - argv[i]); + driver_errf(RUN_TOOL, "unsupported hosted library for JIT: -l%.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(argv[i]))); return 1; } o->wants_hosted_libc = 1; @@ -519,7 +529,8 @@ static int run_parse(int argc, char** argv, RunOptions* o) { } if (driver_strneq(a, "-l", 2)) { if (!driver_streq(a + 2, "c")) { - driver_errf(RUN_TOOL, "unsupported hosted library for JIT: %s", a); + driver_errf(RUN_TOOL, "unsupported hosted library for JIT: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(a))); return 1; } o->wants_hosted_libc = 1; @@ -540,7 +551,8 @@ static int run_parse(int argc, char** argv, RunOptions* o) { continue; } if (a[0] == '-' && a[1] != '\0') { - driver_errf(RUN_TOOL, "unknown flag: %s", a); + driver_errf(RUN_TOOL, "unknown flag: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(a))); return 1; } @@ -607,7 +619,7 @@ typedef struct RunWasmMemoryPrefix { static int run_call_wasm_entry(RunOptions* ro, CfreeJit* jit, void* entry, int* rc_out) { - void* init_sym = cfree_jit_lookup(jit, "__cfree_wasm_init"); + void* init_sym = cfree_jit_lookup(jit, CFREE_SLICE_LIT("__cfree_wasm_init")); uint8_t* instance; uint8_t* memory; union { @@ -710,10 +722,11 @@ int driver_run(int argc, char** argv) { } run_metrics_begin(metrics, "run.jit_lookup"); - sym = cfree_jit_lookup(jit, ro.entry); + sym = cfree_jit_lookup(jit, cfree_slice_cstr(ro.entry)); run_metrics_end(metrics, "run.jit_lookup"); if (!sym) { - driver_errf(RUN_TOOL, "entry symbol not found: %s", ro.entry); + driver_errf(RUN_TOOL, "entry symbol not found: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(ro.entry))); cfree_jit_free(jit); driver_compiler_free(compiler); run_metrics_finish(metrics); diff --git a/driver/runtime.c b/driver/runtime.c @@ -373,8 +373,8 @@ static int rt_prepare_pp(DriverEnv* env, const DriverRuntimeSupport* support, const RuntimeVariant* variant, int assembler, CfreePreprocessOptions* pp, char*** owned_dirs, size_t** owned_sizes, uint32_t* owned_count) { - static const char* const def_int128_1 = "1"; - static const char* const def_int128_0 = "0"; + static const CfreeSlice def_int128_1 = CFREE_SLICE_LIT("1"); + static const CfreeSlice def_int128_0 = CFREE_SLICE_LIT("0"); char** dirs = NULL; size_t* sizes = NULL; const char** include_dirs; @@ -443,17 +443,17 @@ static int rt_prepare_pp(DriverEnv* env, const DriverRuntimeSupport* support, } } - defs[0].name = "HAS_INT128"; + defs[0].name = CFREE_SLICE_LIT("HAS_INT128"); defs[0].body = variant->has_int128 ? def_int128_1 : def_int128_0; i = 1; if (variant->ldbl128) { - defs[i].name = "CFREERT_LDBL128"; - defs[i].body = "1"; + defs[i].name = CFREE_SLICE_LIT("CFREERT_LDBL128"); + defs[i].body = CFREE_SLICE_LIT("1"); ++i; } if (assembler) { - defs[i].name = "__ASSEMBLER__"; - defs[i].body = "1"; + defs[i].name = CFREE_SLICE_LIT("__ASSEMBLER__"); + defs[i].body = CFREE_SLICE_LIT("1"); } pp->include_dirs = include_dirs; @@ -494,14 +494,14 @@ static int rt_compile_source(DriverEnv* env, const DriverRuntimeSupport* support, const RuntimeVariant* variant, CfreeCompiler* compiler, const char* rel, - CfreeBytes* member, CfreeWriter** obj_writer) { + CfreeArInput* member, CfreeWriter** obj_writer) { CfreeContext ctx = driver_env_to_context(env); char* lib_path = NULL; char* src_path = NULL; size_t lib_path_size = 0; size_t src_path_size = 0; DriverLoad src_load = {0}; - CfreeBytes input = {0}; + CfreeSlice input = {0}; CfreeWriter* writer = NULL; CfreeWriter* pp_writer = NULL; const uint8_t* obj_data; @@ -524,7 +524,7 @@ static int rt_compile_source(DriverEnv* env, preprocess_asm = driver_has_suffix(rel, ".S"); if (is_asm) { CfreeAsmCompileOptions aopts = {0}; - CfreeBytes asm_input = input; + CfreeSlice asm_input = input; if (preprocess_asm) { CfreePreprocessOptions pp; char** owned_dirs = NULL; @@ -537,7 +537,8 @@ static int rt_compile_source(DriverEnv* env, rt_free_pp(env, &pp, owned_dirs, owned_sizes, owned_count); goto out; } - st = cfree_cpp_preprocess(compiler, &pp, &input, pp_writer); + st = cfree_cpp_preprocess(compiler, &pp, cfree_slice_cstr(src_path), + &input, pp_writer); rt_free_pp(env, &pp, owned_dirs, owned_sizes, owned_count); if (st != CFREE_OK || cfree_writer_status(pp_writer) != CFREE_OK) goto out; @@ -554,6 +555,7 @@ static int rt_compile_source(DriverEnv* env, sopts.compile.diagnostics = aopts.diagnostics; sopts.compile.language_options = &aopts; memset(&sin, 0, sizeof(sin)); + sin.name = cfree_slice_cstr(src_path); sin.bytes = asm_input; sin.lang = CFREE_LANG_ASM; st = cfree_compile_session_new(compiler, &sopts, &session); @@ -581,6 +583,7 @@ static int rt_compile_source(DriverEnv* env, sopts.compile.diagnostics = copts.diagnostics; sopts.compile.language_options = &copts; memset(&sin, 0, sizeof(sin)); + sin.name = cfree_slice_cstr(src_path); sin.bytes = input; sin.lang = CFREE_LANG_C; st = cfree_compile_session_new(compiler, &sopts, &session); @@ -591,14 +594,15 @@ static int rt_compile_source(DriverEnv* env, rt_free_pp(env, &copts.preprocess, owned_dirs, owned_sizes, owned_count); } if (st != CFREE_OK || cfree_writer_status(writer) != CFREE_OK) { - driver_errf(RT_TOOL, "failed to build runtime source: %s", src_path); + driver_errf(RT_TOOL, "failed to build runtime source: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(src_path))); goto out; } obj_data = cfree_writer_mem_bytes(writer, &obj_len); - member->name = driver_basename(rel); - member->data = obj_data; - member->len = obj_len; + member->name = cfree_slice_cstr(driver_basename(rel)); + member->bytes.data = obj_data; + member->bytes.len = obj_len; *obj_writer = writer; writer = NULL; rc = 0; @@ -618,14 +622,14 @@ static int rt_build_archive(DriverEnv* env, const DriverRuntimeSupport* support, CfreeContext ctx = driver_env_to_context(env); CfreeCompiler* compiler = NULL; CfreeWriter* archive_writer = NULL; - CfreeBytes* members = NULL; + CfreeArInput* members = NULL; CfreeWriter** obj_writers = NULL; CfreeArWriteOptions ar_opts = {0}; CfreeTarget target; uint32_t i; int rc = 1; - members = (CfreeBytes*)driver_alloc_zeroed( + members = (CfreeArInput*)driver_alloc_zeroed( env, (size_t)variant->nsources * sizeof(*members)); obj_writers = (CfreeWriter**)driver_alloc_zeroed( env, (size_t)variant->nsources * sizeof(*obj_writers)); @@ -656,7 +660,8 @@ static int rt_build_archive(DriverEnv* env, const DriverRuntimeSupport* support, if (ctx.file_io->open_writer(ctx.file_io->user, archive_path, &archive_writer) != CFREE_OK) { - driver_errf(RT_TOOL, "failed to open runtime archive: %s", archive_path); + driver_errf(RT_TOOL, "failed to open runtime archive: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(archive_path))); goto out; } @@ -664,7 +669,8 @@ static int rt_build_archive(DriverEnv* env, const DriverRuntimeSupport* support, ar_opts.long_names = 1; if (cfree_ar_write(archive_writer, members, variant->nsources, &ar_opts) != CFREE_OK) { - driver_errf(RT_TOOL, "failed to write runtime archive: %s", archive_path); + driver_errf(RT_TOOL, "failed to write runtime archive: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(archive_path))); goto out; } rc = 0; @@ -748,15 +754,17 @@ int driver_runtime_ensure_archive(DriverEnv* env, if (!driver_path_exists(archive_path) || rt_is_archive_stale(env, support, variant, archive_path)) { if (driver_mkdir_p(env, cache_dir) != 0) { - driver_errf(RT_TOOL, "failed to create runtime cache: %s", cache_dir); + driver_errf(RT_TOOL, "failed to create runtime cache: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(cache_dir))); driver_free(env, archive_path, archive_path_size); driver_free(env, cache_dir, cache_dir_size); return 1; } if (rt_build_archive(env, support, variant, epoch, archive_path) != 0) { - driver_errf(RT_TOOL, "compiler runtime for %s could not be built", - variant->key); - driver_errf(RT_TOOL, "support dir: %s", support->support_root); + driver_errf(RT_TOOL, "compiler runtime for %.*s could not be built", + CFREE_SLICE_ARG(cfree_slice_cstr(variant->key))); + driver_errf(RT_TOOL, "support dir: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(support->support_root))); driver_free(env, archive_path, archive_path_size); driver_free(env, cache_dir, cache_dir_size); return 1; diff --git a/driver/strip.c b/driver/strip.c @@ -31,7 +31,8 @@ void driver_help_strip(void) { driver_printf( - "%s", + "%.*s", + CFREE_SLICE_ARG(CFREE_SLICE_LIT( "cfree strip — drop debug sections and/or symbols\n" "\n" "USAGE\n" @@ -55,7 +56,7 @@ void driver_help_strip(void) { " executables / shared libraries are not supported yet.\n" "\n" "EXIT CODES\n" - " 0 success 1 I/O or strip error 2 bad usage\n"); + " 0 success 1 I/O or strip error 2 bad usage\n"))); } typedef enum StripOp { @@ -76,11 +77,11 @@ typedef struct StripOpts { const char* input; } StripOpts; -static int name_in_list(const char* name, const char* const* list, uint32_t n) { +static int name_in_list(CfreeSlice name, const char* const* list, uint32_t n) { uint32_t i; - if (!name) return 0; + if (!name.len) return 0; for (i = 0; i < n; ++i) { - if (list[i] && strcmp(list[i], name) == 0) return 1; + if (list[i] && cfree_slice_eq_cstr(name, list[i])) return 1; } return 0; } @@ -109,21 +110,21 @@ static int push_name(DriverEnv* env, const char*** arr, uint32_t* n, static int parse_name_arg(int* i, int argc, char** argv, const char* flag, const char* short_flag, const char** out) { const char* a = argv[*i]; - size_t flen = strlen(flag); - /* --flag=NAME */ - if (strncmp(a, flag, flen) == 0 && a[flen] == '=') { + size_t flen = cfree_slice_cstr(flag).len; + /* --flag=NAME ; prefix match */ + if (driver_strneq(a, flag, flen) && a[flen] == '=') { *out = a + flen + 1; return 1; } /* --flag NAME (no '='): treat as "next argv" form, used when --flag is * passed without value. Not standard; skip. */ - if (strcmp(a, flag) == 0) { + if (driver_streq(a, flag)) { if (*i + 1 >= argc) return -1; *out = argv[++(*i)]; return 1; } /* -K NAME / -N NAME */ - if (short_flag && strcmp(a, short_flag) == 0) { + if (short_flag && driver_streq(a, short_flag)) { if (*i + 1 >= argc) return -1; *out = argv[++(*i)]; return 1; @@ -278,7 +279,7 @@ done: } static int strip_object_bytes(DriverEnv* env, const CfreeContext* ctx, - const CfreeBytes* input, const StripOpts* opts, + const CfreeSlice* input, const StripOpts* opts, uint8_t** out_data, size_t* out_size) { CfreeObjFile* of = NULL; CfreeObjBuilder* b; @@ -291,13 +292,13 @@ static int strip_object_bytes(DriverEnv* env, const CfreeContext* ctx, *out_data = NULL; *out_size = 0; - if (cfree_obj_open(ctx, input, &of) != CFREE_OK) { - driver_errf(STRIP_TOOL, "%s: not a recognized object", input->name); + if (cfree_obj_open(ctx, CFREE_SLICE_NULL, input, &of) != CFREE_OK) { + driver_errf(STRIP_TOOL, "not a recognized object"); return 1; } b = cfree_obj_file_builder(of); if (!b) { - driver_errf(STRIP_TOOL, "%s: no builder for object", input->name); + driver_errf(STRIP_TOOL, "no builder for object"); cfree_obj_free(of); return 1; } @@ -313,7 +314,7 @@ static int strip_object_bytes(DriverEnv* env, const CfreeContext* ctx, return 1; } if (cfree_obj_builder_emit(b, w) != CFREE_OK) { - driver_errf(STRIP_TOOL, "%s: emit failed", input->name); + driver_errf(STRIP_TOOL, "emit failed"); cfree_writer_close(w); cfree_obj_free(of); return 1; @@ -351,11 +352,11 @@ static uint64_t strip_epoch_from_env(void) { * a refreshed System-V symbol index. Non-object members pass through * unchanged. */ static int strip_archive(DriverEnv* env, const CfreeContext* ctx, - const CfreeBytes* input, const StripOpts* opts, + const CfreeSlice* input, const StripOpts* opts, const char* output_path) { CfreeArIter* it = NULL; CfreeArMember m; - CfreeBytes* members = NULL; + CfreeArInput* members = NULL; uint8_t** owned_data = NULL; size_t* owned_size = NULL; char* name_storage = NULL; @@ -370,20 +371,20 @@ static int strip_archive(DriverEnv* env, const CfreeContext* ctx, /* Pass 1: count members + total name bytes. */ if (cfree_ar_iter_new(ctx, input, &it) != CFREE_OK) { - driver_errf(STRIP_TOOL, "%s: not an archive", input->name); + driver_errf(STRIP_TOOL, "not an archive"); return 1; } for (;;) { CfreeIterResult r = cfree_ar_iter_next(it, &m); if (r != CFREE_ITER_ITEM) break; nmembers++; - name_bytes_total += driver_strlen(m.name) + 1; + name_bytes_total += m.name.len + 1; } cfree_ar_iter_free(it); it = NULL; if (nmembers) { - members = (CfreeBytes*)driver_alloc_zeroed( + members = (CfreeArInput*)driver_alloc_zeroed( env, (size_t)nmembers * sizeof(*members)); owned_data = (uint8_t**)driver_alloc_zeroed( env, (size_t)nmembers * sizeof(*owned_data)); @@ -412,18 +413,18 @@ static int strip_archive(DriverEnv* env, const CfreeContext* ctx, k = 0; while (k < nmembers) { CfreeIterResult r = cfree_ar_iter_next(it, &m); - const char* p; + size_t j; char* dst; CfreeBinFmt fmt; - CfreeBytes mbytes; + CfreeSlice mbytes; if (r != CFREE_ITER_ITEM) break; dst = name_storage + cursor; - for (p = m.name; *p; ++p) *dst++ = *p; + for (j = 0; j < m.name.len; ++j) *dst++ = m.name.s[j]; *dst++ = '\0'; - members[k].name = name_storage + cursor; + members[k].name.s = name_storage + cursor; + members[k].name.len = m.name.len; cursor = (size_t)(dst - name_storage); - mbytes.name = members[k].name; mbytes.data = m.data; mbytes.len = m.size; fmt = cfree_detect_fmt(m.data, m.size); @@ -438,11 +439,11 @@ static int strip_archive(DriverEnv* env, const CfreeContext* ctx, } owned_data[k] = sd; owned_size[k] = ss; - members[k].data = sd; - members[k].len = ss; + members[k].bytes.data = sd; + members[k].bytes.len = ss; } else { - members[k].data = m.data; - members[k].len = m.size; + members[k].bytes.data = m.data; + members[k].bytes.len = m.size; } k++; } @@ -465,9 +466,9 @@ static int strip_archive(DriverEnv* env, const CfreeContext* ctx, for (k = 0; k < nmembers; ++k) { void* blob = NULL; size_t blob_size = 0; - const char** names = NULL; + const CfreeSlice* names = NULL; uint32_t count = 0; - if (driver_collect_obj_global_syms(env, ctx, STRIP_TOOL, &members[k], + if (driver_collect_obj_global_syms(env, ctx, STRIP_TOOL, &members[k].bytes, &blob, &blob_size, &names, &count) != 0) { goto done; @@ -481,7 +482,8 @@ static int strip_archive(DriverEnv* env, const CfreeContext* ctx, if (ctx->file_io->open_writer(ctx->file_io->user, output_path, &out) != CFREE_OK) { - driver_errf(STRIP_TOOL, "failed to open: %s", output_path); + driver_errf(STRIP_TOOL, "failed to open: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(output_path))); goto done; } opts_ar.epoch = strip_epoch_from_env(); @@ -524,7 +526,7 @@ int driver_strip(int argc, char** argv) { CfreeContext ctx; StripOpts opts; CfreeFileData input_fd = {0}; - CfreeBytes input; + CfreeSlice input; CfreeWriter* w = NULL; uint8_t* out_data = NULL; size_t out_size = 0; @@ -569,7 +571,8 @@ int driver_strip(int argc, char** argv) { } matched = parse_name_arg(&i, argc, argv, "--keep-symbol", "-K", &val); if (matched < 0) { - driver_errf(STRIP_TOOL, "%s requires a symbol name", a); + driver_errf(STRIP_TOOL, "%.*s requires a symbol name", + CFREE_SLICE_ARG(cfree_slice_cstr(a))); rc = 2; goto done; } @@ -582,7 +585,8 @@ int driver_strip(int argc, char** argv) { } matched = parse_name_arg(&i, argc, argv, "--strip-symbol", "-N", &val); if (matched < 0) { - driver_errf(STRIP_TOOL, "%s requires a symbol name", a); + driver_errf(STRIP_TOOL, "%.*s requires a symbol name", + CFREE_SLICE_ARG(cfree_slice_cstr(a))); rc = 2; goto done; } @@ -595,7 +599,8 @@ int driver_strip(int argc, char** argv) { continue; } if (a[0] == '-' && a[1] != '\0') { - driver_errf(STRIP_TOOL, "unknown option: %s", a); + driver_errf(STRIP_TOOL, "unknown option: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(a))); rc = 2; goto done; } @@ -615,11 +620,11 @@ int driver_strip(int argc, char** argv) { if (ctx.file_io->read_all(ctx.file_io->user, opts.input, &input_fd) != CFREE_OK) { - driver_errf(STRIP_TOOL, "failed to read: %s", opts.input); + driver_errf(STRIP_TOOL, "failed to read: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(opts.input))); goto done; } have_input = 1; - input.name = opts.input; input.data = input_fd.data; input.len = input_fd.size; @@ -636,12 +641,14 @@ int driver_strip(int argc, char** argv) { } if (ctx.file_io->open_writer(ctx.file_io->user, out_path, &w) != CFREE_OK) { - driver_errf(STRIP_TOOL, "failed to open: %s", out_path); + driver_errf(STRIP_TOOL, "failed to open: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(out_path))); goto done; } cfree_writer_write(w, out_data, out_size); if (cfree_writer_status(w) != CFREE_OK) { - driver_errf(STRIP_TOOL, "write failed: %s", out_path); + driver_errf(STRIP_TOOL, "write failed: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(out_path))); goto done; } rc = 0; diff --git a/driver/target.c b/driver/target.c @@ -10,7 +10,7 @@ * layer). */ static int triple_tok_eq(const char* s, size_t n, const char* lit) { - size_t l = strlen(lit); + size_t l = cfree_slice_cstr(lit).len; return n == l && memcmp(s, lit, n) == 0; } @@ -28,9 +28,9 @@ int driver_target_from_triple(const char* triple, CfreeTarget* out) { p = triple; while (np < 4) { - const char* dash = strchr(p, '-'); + const char* dash = driver_strchr(p, '-'); parts[np] = p; - plen[np] = dash ? (size_t)(dash - p) : strlen(p); + plen[np] = dash ? (size_t)(dash - p) : cfree_slice_cstr(p).len; if (plen[np] == 0) return 1; np++; if (!dash) break; @@ -176,6 +176,7 @@ int driver_target_to_triple(CfreeTarget target, char* buf, size_t cap) { break; } - n = snprintf(buf, cap, "%s-%s", arch, os); + n = snprintf(buf, cap, "%.*s-%.*s", CFREE_SLICE_ARG(cfree_slice_cstr(arch)), + CFREE_SLICE_ARG(cfree_slice_cstr(os))); return n < 0 || (size_t)n >= cap; } diff --git a/include/cfree/arch.h b/include/cfree/arch.h @@ -16,11 +16,11 @@ typedef struct CfreeUnwindFrame { typedef struct CfreeArchReg { uint32_t dwarf_idx; - const char *name; + CfreeSlice name; } CfreeArchReg; -const char *cfree_arch_register_name(CfreeArchKind, uint32_t dwarf_idx); -CfreeStatus cfree_arch_register_index(CfreeArchKind, const char *name, +CfreeSlice cfree_arch_register_name(CfreeArchKind, uint32_t dwarf_idx); +CfreeStatus cfree_arch_register_index(CfreeArchKind, CfreeSlice name, uint32_t *idx_out); uint32_t cfree_arch_register_count(CfreeArchKind); CfreeStatus cfree_arch_register_at(CfreeArchKind, uint32_t idx, diff --git a/include/cfree/archive.h b/include/cfree/archive.h @@ -11,7 +11,7 @@ */ typedef struct CfreeArMemberSymbols { - const char *const *names; + const CfreeSlice *names; uint32_t count; } CfreeArMemberSymbols; @@ -22,20 +22,27 @@ typedef struct CfreeArWriteOptions { const CfreeArMemberSymbols *member_symbols; } CfreeArWriteOptions; -CfreeStatus cfree_ar_write(CfreeWriter *out, const CfreeBytes *members, +/* One member to be written into an archive: its name (e.g. "foo.o") and its + * contents. Neither slice needs NUL termination. */ +typedef struct CfreeArInput { + CfreeSlice name; + CfreeSlice bytes; +} CfreeArInput; + +CfreeStatus cfree_ar_write(CfreeWriter *out, const CfreeArInput *members, uint32_t nmembers, const CfreeArWriteOptions *opts); -CfreeStatus cfree_ar_list(const CfreeBytes *archive, CfreeWriter *out); +CfreeStatus cfree_ar_list(const CfreeSlice *archive, CfreeWriter *out); typedef struct CfreeArIter CfreeArIter; typedef struct CfreeArMember { - const char *name; + CfreeSlice name; const uint8_t *data; size_t size; } CfreeArMember; -CfreeStatus cfree_ar_iter_new(const CfreeContext *, const CfreeBytes *archive, +CfreeStatus cfree_ar_iter_new(const CfreeContext *, const CfreeSlice *archive, CfreeArIter **out); CfreeIterResult cfree_ar_iter_next(CfreeArIter *, CfreeArMember *out); void cfree_ar_iter_free(CfreeArIter *); diff --git a/include/cfree/cg.h b/include/cfree/cg.h @@ -932,8 +932,7 @@ typedef struct CfreeCgInlineAsm { * are pre-interned strings. clobber_abi_sets names target-defined ABI register * sets such as all caller-saved registers. */ void cfree_cg_inline_asm(CfreeCg*, CfreeCgInlineAsm asm_block); -void cfree_cg_file_scope_asm(CfreeCg*, const char* asm_source, - size_t asm_source_len); +void cfree_cg_file_scope_asm(CfreeCg*, CfreeSlice asm_source); /* ============================================================ * Data Definitions diff --git a/include/cfree/compile.h b/include/cfree/compile.h @@ -46,10 +46,11 @@ typedef enum CfreeFrontendInputKind { } CfreeFrontendInputKind; typedef struct CfreeSourceInput { - CfreeBytes bytes; + CfreeSlice name; /* diagnostic label / source path; may be empty */ + CfreeSlice bytes; CfreeLanguage lang; CfreeFrontendInputKind input_kind; - const char* repl_entry_name; + CfreeSlice repl_entry_name; } CfreeSourceInput; typedef struct CfreeFrontendCompileOptions { @@ -57,7 +58,7 @@ typedef struct CfreeFrontendCompileOptions { CfreeDiagnosticOptions diagnostics; const void* language_options; CfreeFrontendInputKind input_kind; - const char* repl_entry_name; + CfreeSlice repl_entry_name; } CfreeFrontendCompileOptions; typedef struct CfreeFrontend CfreeFrontend; @@ -74,13 +75,14 @@ typedef struct CfreeFrontendVTable { CfreeFrontendCompileFn compile; CfreeFrontendFreeFn free_frontend; - /* NULL-terminated list of lowercase file extensions (no leading dot) - * that this frontend claims. cfree_language_for_path walks every - * registered frontend's list to map a path's extension back to a - * CfreeLanguage. May be NULL for frontends with no canonical - * extension. Matching is case-insensitive so `.S` and `.s` both map - * to the asm frontend's `"s"` entry. */ - const char* const* extensions; + /* Counted list of lowercase file extensions (no leading dot) that this + * frontend claims. cfree_language_for_path walks every registered + * frontend's list to map a path's extension back to a CfreeLanguage. + * May be NULL/0 for frontends with no canonical extension. Matching is + * case-insensitive so `.S` and `.s` both map to the asm frontend's + * `"s"` entry. */ + const CfreeSlice* extensions; + uint32_t nextensions; } CfreeFrontendVTable; CfreeLanguage cfree_language_for_path(CfreeCompiler*, const char* path); @@ -106,8 +108,8 @@ void cfree_compile_session_free(CfreeCompileSession*); typedef struct CfreeDepIter CfreeDepIter; typedef struct CfreeDepEdge { - const char* includer_name; - const char* included_name; + CfreeSlice includer_name; + CfreeSlice included_name; CfreeSrcLoc include_loc; uint8_t from_system_path; uint8_t bracketed; diff --git a/include/cfree/core.h b/include/cfree/core.h @@ -53,11 +53,63 @@ typedef struct CfreeSrcLoc { uint32_t col; } CfreeSrcLoc; -typedef struct CfreeBytes { - const char* name; /* diagnostic label; may be NULL */ - const uint8_t* data; +/* + * Fat-pointer view over borrowed bytes/text. The pointer can be read as text + * (`s`) or raw bytes (`data`); both name the same address. `len` is the byte + * count and never counts a trailing NUL. cfree never relies on NUL + * termination internally; where a NUL is present it is a boundary convenience + * only. This is the one fat-pointer type used throughout the API. + */ +typedef struct CfreeSlice { + union { + const char* s; + const uint8_t* data; + }; size_t len; -} CfreeBytes; +} CfreeSlice; + +/* Build a slice from a string literal (length is compile-time, no strlen). */ +#define CFREE_SLICE_LIT(lit) \ + ((CfreeSlice){ .s = (lit), .len = sizeof(lit) - 1 }) +/* The empty slice. */ +#define CFREE_SLICE_NULL ((CfreeSlice){ .s = NULL, .len = 0 }) +/* Spread a slice into printf "%.*s" arguments: printf("%.*s", CFREE_SLICE_ARG(x)). */ +#define CFREE_SLICE_ARG(x) (int)(x).len, (x).s + +/* Lift a NUL-terminated C string into a slice. The sanctioned boundary helper + * for strings arriving from the OS (argv, getenv) or other foreign APIs; the + * length scan happens here so callers need none elsewhere. NULL -> empty. */ +static inline CfreeSlice cfree_slice_cstr(const char* z) { + CfreeSlice out; + size_t n = 0; + if (!z) { + out.s = NULL; + out.len = 0; + return out; + } + while (z[n]) ++n; + out.s = z; + out.len = n; + return out; +} + +/* Byte-exact slice equality. */ +static inline bool cfree_slice_eq(CfreeSlice a, CfreeSlice b) { + size_t i; + if (a.len != b.len) return false; + for (i = 0; i < a.len; ++i) + if (a.s[i] != b.s[i]) return false; + return true; +} + +/* Equality against a NUL-terminated string (compares bytes, ignores z's NUL). */ +static inline bool cfree_slice_eq_cstr(CfreeSlice a, const char* z) { + size_t i; + if (!z) return a.len == 0; + for (i = 0; i < a.len; ++i) + if (z[i] == '\0' || z[i] != a.s[i]) return false; + return z[a.len] == '\0'; +} typedef enum CfreeArchKind { CFREE_ARCH_X86_32, @@ -244,11 +296,13 @@ CfreeTarget cfree_compiler_target(CfreeCompiler*); const CfreeContext* cfree_compiler_context(CfreeCompiler*); -const char* cfree_compiler_file_name(CfreeCompiler*, uint32_t file_id); +CfreeSlice cfree_compiler_file_name(CfreeCompiler*, uint32_t file_id); -CfreeSym cfree_sym_intern(CfreeCompiler*, const char* str); -CfreeSym cfree_sym_intern_len(CfreeCompiler*, const char* str, size_t len); -const char* cfree_sym_str(CfreeCompiler*, CfreeSym, size_t* len_out); +/* Intern a slice's bytes, returning its canonical symbol (0 for the empty + * slice). Retrieve the bytes with cfree_sym_str, which returns a slice whose + * pointer is NUL-terminated (the NUL is not counted in len). */ +CfreeSym cfree_sym_intern(CfreeCompiler*, CfreeSlice); +CfreeSlice cfree_sym_str(CfreeCompiler*, CfreeSym); CfreeStatus cfree_writer_mem(CfreeHeap*, CfreeWriter** out); const uint8_t* cfree_writer_mem_bytes(CfreeWriter*, size_t* len_out); diff --git a/include/cfree/disasm.h b/include/cfree/disasm.h @@ -14,9 +14,9 @@ typedef struct CfreeInsn { uint64_t vaddr; const uint8_t *bytes; uint32_t nbytes; - const char *mnemonic; - const char *operands; - const char *annotation; + CfreeSlice mnemonic; + CfreeSlice operands; + CfreeSlice annotation; } CfreeInsn; typedef struct CfreeDisasmIter CfreeDisasmIter; @@ -36,7 +36,7 @@ void cfree_disasm_iter_free(CfreeDisasmIter *); CfreeStatus cfree_disasm_obj(const CfreeContext *, const CfreeObjFile *, CfreeWriter *out); -CfreeStatus cfree_disasm_obj_bytes(const CfreeContext *, const CfreeBytes *, +CfreeStatus cfree_disasm_obj_bytes(const CfreeContext *, const CfreeSlice *, CfreeWriter *out); #endif diff --git a/include/cfree/dwarf.h b/include/cfree/dwarf.h @@ -19,29 +19,29 @@ CfreeStatus cfree_dwarf_open(const CfreeContext *, const CfreeObjFile *, void cfree_dwarf_free(CfreeDebugInfo *); CfreeStatus cfree_dwarf_addr_to_line(CfreeDebugInfo *, uint64_t pc, - const char **file_out, + CfreeSlice *file_out, uint32_t *line_out, uint32_t *col_out); -CfreeStatus cfree_dwarf_line_to_addr(CfreeDebugInfo *, const char *file, +CfreeStatus cfree_dwarf_line_to_addr(CfreeDebugInfo *, CfreeSlice file, uint32_t line, uint64_t *pc_out); typedef struct CfreeDwarfLineMatch { uint64_t pc; - const char *file; + CfreeSlice file; } CfreeDwarfLineMatch; -CfreeStatus cfree_dwarf_line_to_addr_all(CfreeDebugInfo *, const char *file, +CfreeStatus cfree_dwarf_line_to_addr_all(CfreeDebugInfo *, CfreeSlice file, uint32_t line, CfreeDwarfLineMatch *out, uint32_t cap, uint32_t *n_out); CfreeStatus cfree_dwarf_func_at(CfreeDebugInfo *, uint64_t pc, - const char **name_out, uint64_t *low_pc_out, + CfreeSlice *name_out, uint64_t *low_pc_out, uint64_t *high_pc_out); typedef struct CfreeDwarfSubprogram { - const char *name; + CfreeSlice name; uint64_t low_pc; uint64_t high_pc; - const char *decl_file; + CfreeSlice decl_file; uint32_t decl_line; const CfreeDwarfType *return_type; bool inlined; @@ -49,7 +49,7 @@ typedef struct CfreeDwarfSubprogram { CfreeStatus cfree_dwarf_subprogram_at(CfreeDebugInfo *, uint64_t pc, CfreeDwarfSubprogram *out); -CfreeStatus cfree_dwarf_subprogram_named(CfreeDebugInfo *, const char *name, +CfreeStatus cfree_dwarf_subprogram_named(CfreeDebugInfo *, CfreeSlice name, CfreeDwarfSubprogram *out); CfreeStatus cfree_dwarf_unwind_step(CfreeDebugInfo *, CfreeUnwindFrame *); @@ -72,7 +72,7 @@ typedef enum CfreeDwarfTypeKind { typedef struct CfreeDwarfTypeInfo { CfreeDwarfTypeKind kind; uint32_t byte_size; - const char *name; + CfreeSlice name; uint32_t element_count; const CfreeDwarfType *inner; } CfreeDwarfTypeInfo; @@ -81,7 +81,7 @@ CfreeDwarfTypeInfo cfree_dwarf_type_info(const CfreeDwarfType *); typedef struct CfreeDwarfFieldIter CfreeDwarfFieldIter; typedef struct CfreeDwarfField { - const char *name; + CfreeSlice name; uint32_t byte_offset; uint32_t bit_offset; uint32_t bit_size; @@ -97,7 +97,7 @@ void cfree_dwarf_field_iter_free(CfreeDwarfFieldIter *); typedef struct CfreeDwarfEnumIter CfreeDwarfEnumIter; typedef struct CfreeDwarfEnumVal { - const char *name; + CfreeSlice name; int64_t value; } CfreeDwarfEnumVal; @@ -134,7 +134,7 @@ typedef CfreeStatus (*CfreeDwarfReadMemFn)(void *user, uint64_t addr, void *dst, size_t n); CfreeStatus cfree_dwarf_var_at(CfreeDebugInfo *, uint64_t pc, - const char *name, CfreeDwarfVarLoc *out); + CfreeSlice name, CfreeDwarfVarLoc *out); CfreeStatus cfree_dwarf_loc_read(CfreeDebugInfo *, const CfreeDwarfVarLoc *, const CfreeUnwindFrame *, CfreeDwarfReadMemFn read_mem, void *read_user, @@ -154,7 +154,7 @@ typedef enum CfreeDwarfVarRoleMask { } CfreeDwarfVarRoleMask; typedef struct CfreeDwarfVar { - const char *name; + CfreeSlice name; CfreeDwarfVarRole role; CfreeDwarfVarLoc loc; } CfreeDwarfVar; @@ -173,7 +173,7 @@ typedef struct CfreeDwarfParamIter CfreeDwarfParamIter; CfreeStatus cfree_dwarf_param_iter_new(CfreeDebugInfo *, uint64_t pc, CfreeDwarfParamIter **out); CfreeStatus cfree_dwarf_param_iter_new_named(CfreeDebugInfo *, - const char *name, + CfreeSlice name, CfreeDwarfParamIter **out); CfreeIterResult cfree_dwarf_param_iter_next(CfreeDwarfParamIter *, CfreeDwarfVar *out); diff --git a/include/cfree/jit.h b/include/cfree/jit.h @@ -48,7 +48,7 @@ typedef struct CfreeJitHost { } CfreeJitHost; void cfree_jit_free(CfreeJit*); -void* cfree_jit_lookup(CfreeJit*, const char* name); +void* cfree_jit_lookup(CfreeJit*, CfreeSlice name); uint64_t cfree_jit_generation(CfreeJit*); void cfree_jit_run_dtors(CfreeJit*); @@ -71,14 +71,14 @@ CfreeStatus cfree_jit_publish(CfreeJit*, const CfreeJitPublishOptions*, const CfreeObjFile* cfree_jit_view(CfreeJit*); CfreeStatus cfree_jit_addr_to_sym(CfreeJit*, uint64_t addr, - const char** name_out, uint64_t* off_out); + CfreeSlice* name_out, uint64_t* off_out); uint64_t cfree_jit_runtime_to_image(CfreeJit*, uint64_t runtime_pc); uint64_t cfree_jit_image_to_runtime(CfreeJit*, uint64_t image_vaddr); typedef struct CfreeJitSymIter CfreeJitSymIter; typedef struct CfreeJitSym { - const char* name; + CfreeSlice name; uint64_t addr; uint64_t size; CfreeSymKind kind; diff --git a/include/cfree/link.h b/include/cfree/link.h @@ -11,7 +11,7 @@ * response-file handling are driver responsibilities. */ -typedef void* (*CfreeExternResolver)(void* user, const char* name); +typedef void* (*CfreeExternResolver)(void* user, CfreeSlice name); typedef struct CfreeJitHost CfreeJitHost; typedef enum CfreeBuildIdMode { @@ -47,7 +47,7 @@ struct CfreeLinkExpr { uint8_t kind; /* CfreeLinkExprKind */ union { int64_t int_val; - const char* name; + CfreeSlice name; struct { const CfreeLinkExpr* lhs; const CfreeLinkExpr* rhs; @@ -66,15 +66,15 @@ typedef enum CfreeLinkRegionFlag { } CfreeLinkRegionFlag; typedef struct CfreeLinkRegion { - const char* name; + CfreeSlice name; uint8_t flags; /* CfreeLinkRegionFlag */ uint64_t origin; uint64_t length; } CfreeLinkRegion; typedef struct CfreeLinkInputMatch { - const char* file_pattern; /* NULL means "*" */ - const char* section_pattern; + CfreeSlice file_pattern; /* empty means "*" */ + CfreeSlice section_pattern; int keep; } CfreeLinkInputMatch; @@ -86,24 +86,24 @@ typedef enum CfreeLinkAsnKind { typedef struct CfreeLinkAssignment { uint8_t kind; /* CfreeLinkAsnKind */ - const char* sym; + CfreeSlice sym; const CfreeLinkExpr* expr; } CfreeLinkAssignment; typedef struct CfreeLinkOutputSection { - const char* name; + CfreeSlice name; const CfreeLinkExpr* vma; const CfreeLinkExpr* lma; const CfreeLinkInputMatch* inputs; uint32_t ninputs; - const char* region; - const char* load_region; + CfreeSlice region; + CfreeSlice load_region; const CfreeLinkAssignment* asns; uint32_t nasns; } CfreeLinkOutputSection; typedef struct CfreeLinkScript { - const char* entry; + CfreeSlice entry; const CfreeLinkRegion* regions; uint32_t nregions; const CfreeLinkOutputSection* sections; @@ -112,8 +112,8 @@ typedef struct CfreeLinkScript { uint32_t ntop_asns; } CfreeLinkScript; -CfreeStatus cfree_link_script_parse(const CfreeContext*, const char* text, - size_t len, CfreeLinkScript** out); +CfreeStatus cfree_link_script_parse(const CfreeContext*, CfreeSlice text, + CfreeLinkScript** out); void cfree_link_script_free(const CfreeContext*, CfreeLinkScript*); typedef enum CfreeLinkMode { @@ -124,7 +124,8 @@ typedef enum CfreeLinkMode { } CfreeLinkMode; typedef struct CfreeLinkArchiveInput { - CfreeBytes bytes; + CfreeSlice name; /* diagnostic label / archive path; may be empty */ + CfreeSlice bytes; uint8_t link_mode; /* CfreeLinkMode */ bool whole_archive; uint8_t group_id; @@ -162,19 +163,19 @@ typedef struct CfreeLinkSessionOptions { bool gc_sections; bool pie; uint16_t pe_subsystem; /* CfreePeSubsystem; 0 => target default */ - const char* interp_path; - const char* entry; + CfreeSlice interp_path; + CfreeSlice entry; const CfreeLinkScript* linker_script; uint8_t build_id_mode; /* CfreeBuildIdMode */ const uint8_t* build_id_bytes; uint32_t build_id_len; - const char* soname; - const char* const* rpaths; + CfreeSlice soname; + const CfreeSlice* rpaths; uint32_t nrpaths; - const char* const* runpaths; + const CfreeSlice* runpaths; uint32_t nrunpaths; - const char* const* exports; + const CfreeSlice* exports; uint32_t nexports; bool allow_undefined; @@ -187,12 +188,12 @@ CfreeStatus cfree_link_session_new(CfreeCompiler*, const CfreeLinkSessionOptions*, CfreeLinkSession** out); CfreeStatus cfree_link_session_add_obj(CfreeLinkSession*, CfreeObjBuilder*); -CfreeStatus cfree_link_session_add_obj_bytes(CfreeLinkSession*, - const CfreeBytes*); +CfreeStatus cfree_link_session_add_obj_bytes(CfreeLinkSession*, CfreeSlice name, + const CfreeSlice*); CfreeStatus cfree_link_session_add_archive_bytes(CfreeLinkSession*, const CfreeLinkArchiveInput*); -CfreeStatus cfree_link_session_add_dso_bytes(CfreeLinkSession*, - const CfreeBytes*); +CfreeStatus cfree_link_session_add_dso_bytes(CfreeLinkSession*, CfreeSlice name, + const CfreeSlice*); CfreeStatus cfree_link_session_resolve(CfreeLinkSession*); CfreeStatus cfree_link_session_emit(CfreeLinkSession*, CfreeWriter* out); CfreeStatus cfree_link_session_jit(CfreeLinkSession*, CfreeJit** out_jit); diff --git a/include/cfree/object.h b/include/cfree/object.h @@ -60,7 +60,7 @@ typedef struct CfreeRelocKind { } CfreeRelocKind; typedef struct CfreeObjSecInfo { - const char *name; + CfreeSlice name; CfreeSecKind kind; uint32_t flags; /* CfreeSecFlag */ uint64_t size; /* bytes; BSS uses virtual size */ @@ -69,7 +69,7 @@ typedef struct CfreeObjSecInfo { } CfreeObjSecInfo; typedef struct CfreeObjSymInfo { - const char *name; + CfreeSlice name; CfreeObjSymbol id; /* stable handle within this CfreeObjFile / builder; usable as the target of cfree_obj_builder_remove_symbol, rename_symbol, etc. */ @@ -84,10 +84,10 @@ typedef struct CfreeObjReloc { CfreeObjSection section; uint64_t offset; CfreeObjSymbol sym; - const char *sym_name; + CfreeSlice sym_name; int64_t addend; CfreeRelocKind kind; - const char *kind_name; /* diagnostic spelling, when known */ + CfreeSlice kind_name; /* diagnostic spelling, when known */ } CfreeObjReloc; /* ============================================================ @@ -224,7 +224,7 @@ typedef struct CfreeObjRelocIter CfreeObjRelocIter; typedef struct CfreeObjGroupIter CfreeObjGroupIter; typedef struct CfreeObjGroupInfo { - const char *name; + CfreeSlice name; CfreeObjSymbol signature; /* COMDAT key, or CFREE_OBJ_SYMBOL_NONE */ uint32_t flags; /* CfreeObjGroupFlag */ uint32_t nsections; @@ -237,8 +237,8 @@ CfreeBinFmt cfree_detect_fmt(const uint8_t *data, size_t len); CfreeStatus cfree_detect_target(const uint8_t *data, size_t len, CfreeTarget *out); -CfreeStatus cfree_obj_open(const CfreeContext *, const CfreeBytes *, - CfreeObjFile **out); +CfreeStatus cfree_obj_open(const CfreeContext *, CfreeSlice name, + const CfreeSlice *, CfreeObjFile **out); void cfree_obj_free(CfreeObjFile *); CfreeObjFmt cfree_obj_fmt(const CfreeObjFile *); @@ -249,7 +249,7 @@ CfreeStatus cfree_obj_section(const CfreeObjFile *, CfreeObjSection idx, CfreeObjSecInfo *out); CfreeStatus cfree_obj_section_data(const CfreeObjFile *, CfreeObjSection idx, const uint8_t **data_out, size_t *len_out); -CfreeStatus cfree_obj_section_by_name(const CfreeObjFile *, const char *name, +CfreeStatus cfree_obj_section_by_name(const CfreeObjFile *, CfreeSlice name, CfreeObjSection *out); /* Format-specific raw section attributes preserved by the reader. @@ -270,7 +270,7 @@ CfreeStatus cfree_obj_section_format_flags(const CfreeObjFile *, uint32_t *raw_type_out, uint32_t *raw_flags_out); -CfreeStatus cfree_obj_symbol_by_name(const CfreeObjFile *, const char *name, +CfreeStatus cfree_obj_symbol_by_name(const CfreeObjFile *, CfreeSlice name, CfreeObjSymInfo *out); CfreeStatus cfree_obj_symiter_new(CfreeObjFile *, CfreeObjSymIter **out); diff --git a/include/cfree/preprocess.h b/include/cfree/preprocess.h @@ -14,8 +14,8 @@ */ typedef struct CfreeDefine { - const char* name; - const char* body; /* NULL means "1" */ + CfreeSlice name; + CfreeSlice body; /* empty slice means "1" */ } CfreeDefine; typedef CfreeDefine CfreePredefinedMacro; @@ -27,11 +27,12 @@ typedef struct CfreePreprocessOptions { uint32_t nsystem_include_dirs; const CfreeDefine* defines; uint32_t ndefines; - const char* const* undefines; + const CfreeSlice* undefines; uint32_t nundefines; } CfreePreprocessOptions; CfreeStatus cfree_cpp_preprocess(CfreeCompiler*, const CfreePreprocessOptions*, - const CfreeBytes*, CfreeWriter*); + CfreeSlice name, const CfreeSlice*, + CfreeWriter*); #endif diff --git a/include/cfree/source.h b/include/cfree/source.h @@ -13,9 +13,9 @@ CfreeStatus cfree_source_add_file(CfreeCompiler *, const char *path, int system_header, uint32_t *file_id_out); -CfreeStatus cfree_source_add_memory(CfreeCompiler *, const char *name, +CfreeStatus cfree_source_add_memory(CfreeCompiler *, CfreeSlice name, uint32_t *file_id_out); -CfreeStatus cfree_source_add_builtin(CfreeCompiler *, const char *name, +CfreeStatus cfree_source_add_builtin(CfreeCompiler *, CfreeSlice name, uint32_t *file_id_out); CfreeStatus cfree_source_add_include(CfreeCompiler *, uint32_t includer_file_id, uint32_t included_file_id, diff --git a/lang/c/abi/c_abi.c b/lang/c/abi/c_abi.c @@ -138,19 +138,19 @@ const Type* c_abi_va_list_type(TargetABI* a, Pool* p) { case CFREE_ARCH_X86_64: { const Type* vp = type_ptr(p, type_void(p)); const Type* uit = type_prim(p, TY_UINT); - Sym name = pool_intern_cstr(p, "__va_list_tag"); + Sym name = cfree_sym_intern(p->c, CFREE_SLICE_LIT("__va_list_tag")); SrcLoc nl = {0, 0, 0}; TagId tg = type_tag_new(p, TAG_STRUCT, name, nl); TypeRecordBuilder* b = type_record_begin(p, TY_STRUCT, tg, name); type_record_field( - b, (Field){.name = pool_intern_cstr(p, "gp_offset"), .type = uit}); + b, (Field){.name = cfree_sym_intern(p->c, CFREE_SLICE_LIT("gp_offset")), .type = uit}); type_record_field( - b, (Field){.name = pool_intern_cstr(p, "fp_offset"), .type = uit}); + b, (Field){.name = cfree_sym_intern(p->c, CFREE_SLICE_LIT("fp_offset")), .type = uit}); type_record_field( - b, (Field){.name = pool_intern_cstr(p, "overflow_arg_area"), + b, (Field){.name = cfree_sym_intern(p->c, CFREE_SLICE_LIT("overflow_arg_area")), .type = vp}); type_record_field( - b, (Field){.name = pool_intern_cstr(p, "reg_save_area"), .type = vp}); + b, (Field){.name = cfree_sym_intern(p->c, CFREE_SLICE_LIT("reg_save_area")), .type = vp}); return type_record_end(p, b); } case CFREE_ARCH_ARM_64: @@ -159,20 +159,20 @@ const Type* c_abi_va_list_type(TargetABI* a, Pool* p) { } else { const Type* vp = type_ptr(p, type_void(p)); const Type* it = type_prim(p, TY_INT); - Sym name = pool_intern_cstr(p, "__va_list"); + Sym name = cfree_sym_intern(p->c, CFREE_SLICE_LIT("__va_list")); SrcLoc nl = {0, 0, 0}; TagId tg = type_tag_new(p, TAG_STRUCT, name, nl); TypeRecordBuilder* b = type_record_begin(p, TY_STRUCT, tg, name); type_record_field( - b, (Field){.name = pool_intern_cstr(p, "__stack"), .type = vp}); + b, (Field){.name = cfree_sym_intern(p->c, CFREE_SLICE_LIT("__stack")), .type = vp}); type_record_field( - b, (Field){.name = pool_intern_cstr(p, "__gr_top"), .type = vp}); + b, (Field){.name = cfree_sym_intern(p->c, CFREE_SLICE_LIT("__gr_top")), .type = vp}); type_record_field( - b, (Field){.name = pool_intern_cstr(p, "__vr_top"), .type = vp}); + b, (Field){.name = cfree_sym_intern(p->c, CFREE_SLICE_LIT("__vr_top")), .type = vp}); type_record_field( - b, (Field){.name = pool_intern_cstr(p, "__gr_offs"), .type = it}); + b, (Field){.name = cfree_sym_intern(p->c, CFREE_SLICE_LIT("__gr_offs")), .type = it}); type_record_field( - b, (Field){.name = pool_intern_cstr(p, "__vr_offs"), .type = it}); + b, (Field){.name = cfree_sym_intern(p->c, CFREE_SLICE_LIT("__vr_offs")), .type = it}); return type_record_end(p, b); } case CFREE_ARCH_RV64: diff --git a/lang/c/c.c b/lang/c/c.c @@ -16,7 +16,8 @@ static SrcLoc c_no_loc(void) { } static _Noreturn void c_bad_options(Compiler* c, const char* msg) { - compiler_panic(c, c_no_loc(), "bad C frontend options: %s", msg); + compiler_panic(c, c_no_loc(), "bad C frontend options: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(msg))); } static void c_apply_pp_options(Pp* pp, const CfreePreprocessOptions* opts) { @@ -29,11 +30,12 @@ static void c_apply_pp_options(Pp* pp, const CfreePreprocessOptions* opts) { pp_add_include_dir(pp, opts->system_include_dirs[i], 1); } for (i = 0; i < opts->ndefines; ++i) { - const char* body = opts->defines[i].body ? opts->defines[i].body : "1"; - pp_define(pp, opts->defines[i].name, body); + const char* body = + opts->defines[i].body.len ? opts->defines[i].body.s : "1"; + pp_define(pp, opts->defines[i].name.s, body); } for (i = 0; i < opts->nundefines; ++i) { - pp_undef(pp, opts->undefines[i]); + pp_undef(pp, opts->undefines[i].s); } } @@ -60,7 +62,7 @@ static CfreeStatus c_frontend_compile( /* The libcfree pipeline plants the original CfreeCCompileOptions* in * language_options. Recover it for preprocessor configuration. */ const CfreeCCompileOptions* opts; - const CfreeBytes* bytes; + const CfreeSlice* bytes; Pool* pool; Lexer* lex; Pp* pp; @@ -81,7 +83,7 @@ static CfreeStatus c_frontend_compile( cfree_frontend_metrics_scope_end(c, "compile.c.pool_new"); if (!pool) compiler_panic(c, c_no_loc(), "C compiler out of memory"); cfree_frontend_metrics_scope_begin(c, "compile.c.lex_open"); - lex = lex_open_mem(c, bytes->name, (const char*)bytes->data, bytes->len); + lex = lex_open_mem(c, input->name.s, bytes->s, bytes->len); cfree_frontend_metrics_scope_end(c, "compile.c.lex_open"); cfree_frontend_metrics_scope_begin(c, "compile.c.pp_new"); pp = pp_new(c); @@ -142,4 +144,5 @@ const CfreeFrontendVTable cfree_c_frontend_vtable = { c_frontend_compile, c_frontend_free, NULL, + 0, }; diff --git a/lang/c/decl/decl_attrs.c b/lang/c/decl/decl_attrs.c @@ -18,21 +18,21 @@ static void apply_visibility(Compiler* c, const Attr* a, Decl* out) { if (a->v.sym == 0) { compiler_panic(c, a->loc, "visibility attribute missing argument"); } - size_t n = 0; - const char* s = compiler_sym_str(c, a->v.sym, &n); - if (s && strcmp(s, "default") == 0) { + CfreeSlice ss = cfree_sym_str(c, a->v.sym); + const char* s = ss.s; + if (s && cfree_slice_eq_cstr(ss, "default")) { out->visibility = SV_DEFAULT; - } else if (s && strcmp(s, "hidden") == 0) { + } else if (s && cfree_slice_eq_cstr(ss, "hidden")) { out->visibility = SV_HIDDEN; - } else if (s && strcmp(s, "protected") == 0) { + } else if (s && cfree_slice_eq_cstr(ss, "protected")) { out->visibility = SV_PROTECTED; - } else if (s && strcmp(s, "internal") == 0) { + } else if (s && cfree_slice_eq_cstr(ss, "internal")) { out->visibility = SV_INTERNAL; } else { compiler_panic(c, a->loc, - "unknown visibility '%s' (expected default|hidden|" + "unknown visibility '%.*s' (expected default|hidden|" "protected|internal)", - s ? s : ""); + CFREE_SLICE_ARG(cfree_slice_cstr(s ? s : ""))); } } diff --git a/lang/c/parse/cg_adapter.c b/lang/c/parse/cg_adapter.c @@ -1032,11 +1032,11 @@ void pcg_inline_asm(Parser* p, const char* tmpl, const AsmConstraint* outs, CfreeCgAsmOperand* in = NULL; CfreeSym* cl = NULL; memset(&a, 0, sizeof a); - a.tmpl = cfree_sym_intern(p->c, tmpl ? tmpl : ""); + a.tmpl = cfree_sym_intern(p->c, cfree_slice_cstr(tmpl ? tmpl : "")); if (nout) { o = arena_zarray(p->pool->arena, CfreeCgAsmOperand, nout); for (u32 i = 0; i < nout; ++i) { - o[i].constraint = cfree_sym_intern(p->c, outs[i].str ? outs[i].str : ""); + o[i].constraint = cfree_sym_intern(p->c, cfree_slice_cstr(outs[i].str ? outs[i].str : "")); o[i].name = outs[i].name; o[i].type = pcg_tid(p, outs[i].type); o[i].dir = CFREE_CG_ASM_OUT; @@ -1045,7 +1045,7 @@ void pcg_inline_asm(Parser* p, const char* tmpl, const AsmConstraint* outs, if (nin) { in = arena_zarray(p->pool->arena, CfreeCgAsmOperand, nin); for (u32 i = 0; i < nin; ++i) { - in[i].constraint = cfree_sym_intern(p->c, ins[i].str ? ins[i].str : ""); + in[i].constraint = cfree_sym_intern(p->c, cfree_slice_cstr(ins[i].str ? ins[i].str : "")); in[i].name = ins[i].name; in[i].type = pcg_tid(p, ins[i].type); in[i].dir = diff --git a/lang/c/parse/parse.c b/lang/c/parse/parse.c @@ -107,9 +107,11 @@ static Tok fuse_string_lits(Parser* p, Tok a, Tok b) { u16 ae = (u16)(a.flags & STR_ENC_MASK); u16 be = (u16)(b.flags & STR_ENC_MASK); u16 fused_enc; - size_t alen = 0, blen = 0; - const char* as = pool_str(p->pool, a.spelling, &alen); - const char* bs = pool_str(p->pool, b.spelling, &blen); + CfreeSlice a_sl = cfree_sym_str(p->pool->c, a.spelling); + CfreeSlice b_sl = cfree_sym_str(p->pool->c, b.spelling); + size_t alen = a_sl.len, blen = b_sl.len; + const char* as = a_sl.s; + const char* bs = b_sl.s; size_t apfx, bpfx; size_t a_content_len, b_content_len; size_t out_pfx_len; @@ -153,7 +155,7 @@ static Tok fuse_string_lits(Parser* p, Tok a, Tok b) { } buf[k++] = '"'; out = a; - out.spelling = pool_intern(p->pool, buf, k); + out.spelling = cfree_sym_intern(p->pool->c, (CfreeSlice){ .s = buf, .len = k }); out.flags = (u16)((a.flags & ~STR_ENC_MASK) | fused_enc); out.lit = LIT_NONE; h->free(h, buf, 0); @@ -210,7 +212,7 @@ Tok peek1(Parser* p) { void expect_punct(Parser* p, u32 punct, const char* what) { if (!accept_punct(p, punct)) { - perr(p, "expected %s", what); + perr(p, "expected %.*s", CFREE_SLICE_ARG(cfree_slice_cstr(what))); } } @@ -659,8 +661,9 @@ static VLABound* build_param_vla_bounds(Parser* p, const ParamInfo* info, /* Mint a unique linker name for a static local: `<orig>.<counter>`. */ Sym mint_static_local_sym(Parser* p, Sym orig) { - size_t olen = 0; - const char* on = pool_str(p->pool, orig, &olen); + CfreeSlice orig_sl = cfree_sym_str(p->pool->c, orig); + size_t olen = orig_sl.len; + const char* on = orig_sl.s; char buf[128]; u32 wlen = 0; u32 id = ++p->static_local_counter; @@ -679,7 +682,7 @@ Sym mint_static_local_sym(Parser* p, Sym orig) { } while (dn && wlen < sizeof buf - 1) buf[wlen++] = digits[--dn]; } - return pool_intern(p->pool, buf, wlen); + return cfree_sym_intern(p->pool->c, (CfreeSlice){ .s = buf, .len = wlen }); } /* ============================================================ @@ -800,7 +803,7 @@ static void parse_init_declarator(Parser* p, const DeclSpecs* specs) { const Type* composite = NULL; CSemCheck chk = c_sem_check_redeclaration(p->pool, prior->type, var_ty, &composite); - if (!chk.ok) perr(p, "%s", chk.message); + if (!chk.ok) perr(p, "%.*s", CFREE_SLICE_ARG(cfree_slice_cstr(chk.message))); if (cur && cur->kind != SEK_GLOBAL) { perr(p, "redefinition of identifier"); } @@ -903,7 +906,7 @@ static void parse_init_declarator(Parser* p, const DeclSpecs* specs) { const Type* rhs = cg_top_type(p->cg); CSemCheck chk = c_sem_check_assignment(p->pool, var_ty, rhs, C_SEM_ASSIGN_INIT); - if (!chk.ok) perr(p, "%s", chk.message); + if (!chk.ok) perr(p, "%.*s", CFREE_SLICE_ARG(cfree_slice_cstr(chk.message))); } coerce_top_to_lvalue(p); cg_store(p->cg); @@ -1028,7 +1031,7 @@ static SymEntry* declare_function(Parser* p, Sym fname, const Type* fn_ty, const Type* composite = NULL; CSemCheck chk = c_sem_check_redeclaration(p->pool, existing->type, fn_ty, &composite); - if (!chk.ok) perr(p, "%s", chk.message); + if (!chk.ok) perr(p, "%.*s", CFREE_SLICE_ARG(cfree_slice_cstr(chk.message))); if (specs->storage == DS_STATIC && existing->linkage == DL_EXTERNAL) { perr(p, "static declaration follows non-static declaration"); } @@ -1054,7 +1057,7 @@ static SymEntry* declare_function(Parser* p, Sym fname, const Type* fn_ty, const Type* composite = NULL; CSemCheck chk = c_sem_check_redeclaration(p->pool, existing->type, fn_ty, &composite); - if (!chk.ok) perr(p, "%s", chk.message); + if (!chk.ok) perr(p, "%.*s", CFREE_SLICE_ARG(cfree_slice_cstr(chk.message))); if (specs->storage == DS_STATIC && existing->linkage == DL_EXTERNAL) { perr(p, "static declaration follows non-static declaration"); } @@ -1296,10 +1299,9 @@ static void parse_external_decl(Parser* p) { if (fn_alias_target != 0) { SymEntry* te = scope_lookup(p, fn_alias_target); if (!te) { - size_t nl = 0; - const char* nm = pool_str(p->pool, fn_alias_target, &nl); - compiler_panic(p->c, loc, "alias target '%s' is undefined", - nm ? nm : "?"); + const char* nm = cfree_sym_str(p->pool->c, fn_alias_target).s; + compiler_panic(p->c, loc, "alias target '%.*s' is undefined", + CFREE_SLICE_ARG(cfree_slice_cstr(nm ? nm : "?"))); } CfreeCgAlias alias; memset(&alias, 0, sizeof alias); @@ -1310,10 +1312,9 @@ static void parse_external_decl(Parser* p) { (fn_decl_flags & DF_WEAK) ? CFREE_SB_WEAK : CFREE_SB_GLOBAL; alias.sym.visibility = CFREE_CG_VIS_DEFAULT; if (cfree_cg_alias(p->cg, alias) == CFREE_CG_SYM_NONE) { - size_t nl = 0; - const char* nm = pool_str(p->pool, fn_alias_target, &nl); - compiler_panic(p->c, loc, "alias target '%s' is undefined", - nm ? nm : "?"); + const char* nm = cfree_sym_str(p->pool->c, fn_alias_target).s; + compiler_panic(p->c, loc, "alias target '%.*s' is undefined", + CFREE_SLICE_ARG(cfree_slice_cstr(nm ? nm : "?"))); } } return; @@ -1342,7 +1343,7 @@ static void parse_external_decl(Parser* p) { const Type* composite = NULL; CSemCheck chk = c_sem_check_redeclaration(p->pool, existing->type, base_ty, &composite); - if (!chk.ok) perr(p, "%s", chk.message); + if (!chk.ok) perr(p, "%.*s", CFREE_SLICE_ARG(cfree_slice_cstr(chk.message))); if (specs.storage == DS_STATIC && existing->linkage == DL_EXTERNAL) { perr(p, "static declaration follows non-static declaration"); } @@ -1445,7 +1446,8 @@ static void parse_file_scope_asm(Parser* p) { expect_punct(p, ';', "';' after file-scope asm"); if (nbytes > 0) --nbytes; /* drop decode_string_literal's trailing NUL */ if (pcg_emit_enabled(p)) { - cfree_cg_file_scope_asm(p->cg, (const char*)bytes, nbytes); + CfreeSlice asm_src = {{(const char*)bytes}, nbytes}; + cfree_cg_file_scope_asm(p->cg, asm_src); } } @@ -1487,68 +1489,68 @@ void parse_c(Compiler* c, Pool* pool, Pp* pp, DeclTable* decls, CG* cg) { p.pool = pool; for (i = (CKw)1; i < KW_COUNT; ++i) { - p.kw_sym[i] = pool_intern_cstr(p.pool, kw_names[i]); - } - - p.sym_b_alloca = pool_intern_cstr(p.pool, "__builtin_alloca"); - p.sym_b_ctz = pool_intern_cstr(p.pool, "__builtin_ctz"); - p.sym_b_ctzl = pool_intern_cstr(p.pool, "__builtin_ctzl"); - p.sym_b_ctzll = pool_intern_cstr(p.pool, "__builtin_ctzll"); - p.sym_b_clz = pool_intern_cstr(p.pool, "__builtin_clz"); - p.sym_b_clzl = pool_intern_cstr(p.pool, "__builtin_clzl"); - p.sym_b_clzll = pool_intern_cstr(p.pool, "__builtin_clzll"); - p.sym_b_trap = pool_intern_cstr(p.pool, "__builtin_trap"); - p.sym_b_unreachable = pool_intern_cstr(p.pool, "__builtin_unreachable"); - p.sym_b_memcpy = pool_intern_cstr(p.pool, "__builtin_memcpy"); - p.sym_b_memmove = pool_intern_cstr(p.pool, "__builtin_memmove"); - p.sym_b_memcmp = pool_intern_cstr(p.pool, "__builtin_memcmp"); - p.sym_b_memset = pool_intern_cstr(p.pool, "__builtin_memset"); - p.sym_b_clear_cache = pool_intern_cstr(p.pool, "__builtin___clear_cache"); - p.sym_b_isnan = pool_intern_cstr(p.pool, "__builtin_isnan"); - p.sym_b_fabs = pool_intern_cstr(p.pool, "__builtin_fabs"); - p.sym_b_fabsf = pool_intern_cstr(p.pool, "__builtin_fabsf"); - p.sym_b_fabsl = pool_intern_cstr(p.pool, "__builtin_fabsl"); - p.sym_b_inf = pool_intern_cstr(p.pool, "__builtin_inf"); - p.sym_b_inff = pool_intern_cstr(p.pool, "__builtin_inff"); - p.sym_b_infl = pool_intern_cstr(p.pool, "__builtin_infl"); - p.sym_b_huge_val = pool_intern_cstr(p.pool, "__builtin_huge_val"); - p.sym_b_huge_valf = pool_intern_cstr(p.pool, "__builtin_huge_valf"); - p.sym_b_huge_vall = pool_intern_cstr(p.pool, "__builtin_huge_vall"); - p.sym_func = pool_intern_cstr(p.pool, "__func__"); - p.sym_func_gcc = pool_intern_cstr(p.pool, "__FUNCTION__"); - p.sym_pretty_func_gcc = pool_intern_cstr(p.pool, "__PRETTY_FUNCTION__"); - p.sym_b_expect = pool_intern_cstr(p.pool, "__builtin_expect"); - p.sym_b_offsetof = pool_intern_cstr(p.pool, "__builtin_offsetof"); - p.sym_b_va_list = pool_intern_cstr(p.pool, "__builtin_va_list"); - p.sym_b_va_start = pool_intern_cstr(p.pool, "__builtin_va_start"); - p.sym_b_va_arg = pool_intern_cstr(p.pool, "__builtin_va_arg"); - p.sym_b_va_end = pool_intern_cstr(p.pool, "__builtin_va_end"); - p.sym_b_va_copy = pool_intern_cstr(p.pool, "__builtin_va_copy"); - p.sym_attribute = pool_intern_cstr(p.pool, "__attribute__"); - p.sym_volatile_alias = pool_intern_cstr(p.pool, "__volatile__"); - p.sym_alignof_alias = pool_intern_cstr(p.pool, "__alignof__"); - p.sym_asm_alias = pool_intern_cstr(p.pool, "__asm"); - p.sym_inline_alias = pool_intern_cstr(p.pool, "__inline"); - p.sym_inline_alias2 = pool_intern_cstr(p.pool, "__inline__"); - p.sym_thread_alias = pool_intern_cstr(p.pool, "__thread"); - p.sym_int128 = pool_intern_cstr(p.pool, "__int128"); - p.sym_int128_t = pool_intern_cstr(p.pool, "__int128_t"); - p.sym_uint128_t = pool_intern_cstr(p.pool, "__uint128_t"); - p.sym_a_load_n = pool_intern_cstr(p.pool, "__atomic_load_n"); - p.sym_a_store_n = pool_intern_cstr(p.pool, "__atomic_store_n"); - p.sym_a_exchange_n = pool_intern_cstr(p.pool, "__atomic_exchange_n"); - p.sym_a_fetch_add = pool_intern_cstr(p.pool, "__atomic_fetch_add"); - p.sym_a_fetch_sub = pool_intern_cstr(p.pool, "__atomic_fetch_sub"); - p.sym_a_fetch_and = pool_intern_cstr(p.pool, "__atomic_fetch_and"); - p.sym_a_fetch_or = pool_intern_cstr(p.pool, "__atomic_fetch_or"); - p.sym_a_fetch_xor = pool_intern_cstr(p.pool, "__atomic_fetch_xor"); - p.sym_a_fetch_nand = pool_intern_cstr(p.pool, "__atomic_fetch_nand"); - p.sym_a_cas_n = pool_intern_cstr(p.pool, "__atomic_compare_exchange_n"); + p.kw_sym[i] = cfree_sym_intern(p.pool->c, cfree_slice_cstr(kw_names[i])); + } + + p.sym_b_alloca = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__builtin_alloca")); + p.sym_b_ctz = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__builtin_ctz")); + p.sym_b_ctzl = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__builtin_ctzl")); + p.sym_b_ctzll = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__builtin_ctzll")); + p.sym_b_clz = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__builtin_clz")); + p.sym_b_clzl = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__builtin_clzl")); + p.sym_b_clzll = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__builtin_clzll")); + p.sym_b_trap = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__builtin_trap")); + p.sym_b_unreachable = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__builtin_unreachable")); + p.sym_b_memcpy = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__builtin_memcpy")); + p.sym_b_memmove = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__builtin_memmove")); + p.sym_b_memcmp = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__builtin_memcmp")); + p.sym_b_memset = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__builtin_memset")); + p.sym_b_clear_cache = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__builtin___clear_cache")); + p.sym_b_isnan = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__builtin_isnan")); + p.sym_b_fabs = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__builtin_fabs")); + p.sym_b_fabsf = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__builtin_fabsf")); + p.sym_b_fabsl = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__builtin_fabsl")); + p.sym_b_inf = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__builtin_inf")); + p.sym_b_inff = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__builtin_inff")); + p.sym_b_infl = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__builtin_infl")); + p.sym_b_huge_val = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__builtin_huge_val")); + p.sym_b_huge_valf = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__builtin_huge_valf")); + p.sym_b_huge_vall = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__builtin_huge_vall")); + p.sym_func = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__func__")); + p.sym_func_gcc = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__FUNCTION__")); + p.sym_pretty_func_gcc = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__PRETTY_FUNCTION__")); + p.sym_b_expect = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__builtin_expect")); + p.sym_b_offsetof = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__builtin_offsetof")); + p.sym_b_va_list = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__builtin_va_list")); + p.sym_b_va_start = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__builtin_va_start")); + p.sym_b_va_arg = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__builtin_va_arg")); + p.sym_b_va_end = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__builtin_va_end")); + p.sym_b_va_copy = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__builtin_va_copy")); + p.sym_attribute = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__attribute__")); + p.sym_volatile_alias = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__volatile__")); + p.sym_alignof_alias = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__alignof__")); + p.sym_asm_alias = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__asm")); + p.sym_inline_alias = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__inline")); + p.sym_inline_alias2 = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__inline__")); + p.sym_thread_alias = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__thread")); + p.sym_int128 = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__int128")); + p.sym_int128_t = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__int128_t")); + p.sym_uint128_t = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__uint128_t")); + p.sym_a_load_n = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__atomic_load_n")); + p.sym_a_store_n = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__atomic_store_n")); + p.sym_a_exchange_n = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__atomic_exchange_n")); + p.sym_a_fetch_add = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__atomic_fetch_add")); + p.sym_a_fetch_sub = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__atomic_fetch_sub")); + p.sym_a_fetch_and = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__atomic_fetch_and")); + p.sym_a_fetch_or = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__atomic_fetch_or")); + p.sym_a_fetch_xor = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__atomic_fetch_xor")); + p.sym_a_fetch_nand = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__atomic_fetch_nand")); + p.sym_a_cas_n = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__atomic_compare_exchange_n")); p.sym_a_always_lock_free = - pool_intern_cstr(p.pool, "__atomic_always_lock_free"); - p.sym_a_is_lock_free = pool_intern_cstr(p.pool, "__atomic_is_lock_free"); - p.sym_a_thread_fence = pool_intern_cstr(p.pool, "__atomic_thread_fence"); - p.sym_a_signal_fence = pool_intern_cstr(p.pool, "__atomic_signal_fence"); + cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__atomic_always_lock_free")); + p.sym_a_is_lock_free = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__atomic_is_lock_free")); + p.sym_a_thread_fence = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__atomic_thread_fence")); + p.sym_a_signal_fence = cfree_sym_intern(p.pool->c, CFREE_SLICE_LIT("__atomic_signal_fence")); p.scope = scope_new(&p, NULL); diff --git a/lang/c/parse/parse_expr.c b/lang/c/parse/parse_expr.c @@ -71,11 +71,15 @@ static int null_pointer_constant(Parser* p, const Type* ty) { } static void require_scalar(Parser* p, const Type* ty, const char* what) { - if (!c_type_is_scalar(ty)) perr(p, "%s requires scalar operand", what); + if (!c_type_is_scalar(ty)) + perr(p, "%.*s requires scalar operand", + CFREE_SLICE_ARG(cfree_slice_cstr(what))); } static void require_arith(Parser* p, const Type* ty, const char* what) { - if (!type_is_arith(ty)) perr(p, "%s requires arithmetic operand", what); + if (!type_is_arith(ty)) + perr(p, "%.*s requires arithmetic operand", + CFREE_SLICE_ARG(cfree_slice_cstr(what))); } static const Type* conditional_pointer_type(Parser* p, const Type* then_ty, @@ -100,8 +104,9 @@ static u32 cint_bits(Parser* p, const Type* ty); static int cint_signed(Parser* p, const Type* ty); static u64 parse_int_literal_u64(Parser* p, const Tok* t, int* decimal_out) { - size_t len = 0; - const char* s = pool_str(p->pool, t->spelling, &len); + CfreeSlice spell_sl = cfree_sym_str(p->pool->c, t->spelling); + size_t len = spell_sl.len; + const char* s = spell_sl.s; size_t i = 0; u64 base = 10; u64 acc = 0; @@ -219,8 +224,9 @@ static const Type* int_literal_type(Parser* p, const Tok* t) { } double parse_float_literal(Parser* p, const Tok* t) { - size_t len = 0; - const char* s = pool_str(p->pool, t->spelling, &len); + CfreeSlice spell_sl = cfree_sym_str(p->pool->c, t->spelling); + size_t len = spell_sl.len; + const char* s = spell_sl.s; size_t i = 0; int is_hex = 0; double v = 0.0; @@ -361,8 +367,9 @@ int string_literal_initializes_array(Parser* p, const Type* elem, } i64 decode_char_literal(Parser* p, const Tok* t) { - size_t len = 0; - const char* s = pool_str(p->pool, t->spelling, &len); + CfreeSlice spell_sl = cfree_sym_str(p->pool->c, t->spelling); + size_t len = spell_sl.len; + const char* s = spell_sl.s; size_t i = 0; CLitUnit unit; const char* err = NULL; @@ -382,10 +389,12 @@ i64 decode_char_literal(Parser* p, const Tok* t) { i++; if (i >= len || s[i] == '\'') perr(p, "empty character literal"); if (!c_lit_decode_unit(s, len, &i, &unit, &err)) { - compiler_panic(p->c, t->loc, "%s", err ? err : "bad character literal"); + compiler_panic(p->c, t->loc, "%.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(err ? err : "bad character literal"))); } if (!c_lit_encode_char_unit(enc, bits, unit, &v, &err)) { - compiler_panic(p->c, t->loc, "%s", err ? err : "bad character literal"); + compiler_panic(p->c, t->loc, "%.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(err ? err : "bad character literal"))); } if (i >= len || s[i] != '\'') { perr(p, "multi-character constants are not supported"); @@ -394,8 +403,9 @@ i64 decode_char_literal(Parser* p, const Tok* t) { } u8* decode_string_literal(Parser* p, const Tok* t, size_t* nlen_out) { - size_t len = 0; - const char* s = pool_str(p->pool, t->spelling, &len); + CfreeSlice spell_sl = cfree_sym_str(p->pool->c, t->spelling); + size_t len = spell_sl.len; + const char* s = spell_sl.s; size_t i = 0; Heap* h = cfree_compiler_context(p->c)->heap; u8* buf; @@ -418,10 +428,12 @@ u8* decode_string_literal(Parser* p, const Tok* t, size_t* nlen_out) { while (i < len && s[i] != '"') { CLitUnit unit; if (!c_lit_decode_unit(s, len, &i, &unit, &err)) { - compiler_panic(p->c, t->loc, "%s", err ? err : "bad string literal"); + compiler_panic(p->c, t->loc, "%.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(err ? err : "bad string literal"))); } if (!c_lit_append_string_unit(buf, &k, enc, elem_size, unit, &err)) { - compiler_panic(p->c, t->loc, "%s", err ? err : "bad string literal"); + compiler_panic(p->c, t->loc, "%.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(err ? err : "bad string literal"))); } } c_lit_encode_uint_le(buf + k, elem_size, 0); @@ -1104,7 +1116,8 @@ static void coerce_top_to_type(Parser* p, const Type* dst) { static const Type* atomic_pointee_type(Parser* p, const Type* ptr_ty, const char* who) { if (!ptr_ty || ptr_ty->kind != TY_PTR) { - perr(p, "%s: pointer argument must have pointer type", who); + perr(p, "%.*s: pointer argument must have pointer type", + CFREE_SLICE_ARG(cfree_slice_cstr(who))); } return ptr_ty->ptr.pointee; } @@ -1142,7 +1155,7 @@ static int atomic_lock_free_for_const_size(Parser* p, i64 size) { static CfreeCgSym builtin_libcall_sym(Parser* p, const char* name, const Type* fn_ty) { CfreeCgDecl decl; - Sym source_name = pool_intern_cstr(p->pool, name); + Sym source_name = cfree_sym_intern(p->pool->c, cfree_slice_cstr(name)); memset(&decl, 0, sizeof decl); decl.kind = CFREE_CG_DECL_FUNC; decl.display_name = source_name; @@ -1360,10 +1373,8 @@ typedef struct BuiltinOverflowInfo { } BuiltinOverflowInfo; static int sym_eq_cstr(Parser* p, Sym sym, const char* want) { - size_t got_len = 0; - size_t want_len = strlen(want); - const char* got = pool_str(p->pool, sym, &got_len); - return got && got_len == want_len && memcmp(got, want, want_len) == 0; + CfreeSlice got = cfree_sym_str(p->pool->c, sym); + return got.s && cfree_slice_eq_cstr(got, want); } static int builtin_overflow_info(Parser* p, Sym name, @@ -1583,8 +1594,9 @@ static int parse_builtin_fabs_call(Parser* p, Sym name, SrcLoc loc) { } static int parse_builtin_abs_call(Parser* p, Sym name, SrcLoc loc) { - size_t nlen = 0; - const char* nm = pool_str(p->pool, name, &nlen); + CfreeSlice name_sl = cfree_sym_str(p->pool->c, name); + size_t nlen = name_sl.len; + const char* nm = name_sl.s; const char* libname = NULL; const Type* int_ty = NULL; const Type* params[1]; @@ -1991,13 +2003,15 @@ static void parse_primary(Parser* p) { if (t.v.ident == p->sym_func || t.v.ident == p->sym_func_gcc || t.v.ident == p->sym_pretty_func_gcc) { if (p->cur_func_name == 0) { - compiler_panic(p->c, t.loc, "'%s' used outside a function", - t.v.ident == p->sym_func ? "__func__" - : t.v.ident == p->sym_func_gcc ? "__FUNCTION__" - : "__PRETTY_FUNCTION__"); + compiler_panic(p->c, t.loc, "'%.*s' used outside a function", + CFREE_SLICE_ARG(cfree_slice_cstr( + t.v.ident == p->sym_func ? "__func__" + : t.v.ident == p->sym_func_gcc ? "__FUNCTION__" + : "__PRETTY_FUNCTION__"))); } - size_t nlen = 0; - const char* fn_name = pool_str(p->pool, p->cur_func_name, &nlen); + CfreeSlice fn_name_sl = cfree_sym_str(p->pool->c, p->cur_func_name); + size_t nlen = fn_name_sl.len; + const char* fn_name = fn_name_sl.s; Heap* h = cfree_compiler_context(p->c)->heap; u8* bytes = (u8*)h->alloc(h, nlen + 1u, 1u); for (size_t i = 0; i < nlen; ++i) bytes[i] = (u8)fn_name[i]; @@ -2012,8 +2026,9 @@ static void parse_primary(Parser* p) { } e = scope_lookup(p, t.v.ident); if (!e) { - size_t nlen = 0; - const char* nm = pool_str(p->pool, t.v.ident, &nlen); + CfreeSlice ident_sl = cfree_sym_str(p->pool->c, t.v.ident); + size_t nlen = ident_sl.len; + const char* nm = ident_sl.s; compiler_panic(p->c, t.loc, "undeclared identifier '%.*s'", (int)nlen, nm ? nm : "?"); } @@ -2194,7 +2209,7 @@ static void parse_postfix(Parser* p) { if (param_ty) { CSemCheck chk = c_sem_check_assignment( p->pool, param_ty, cg_top_type(p->cg), C_SEM_ASSIGN_EXPR); - if (!chk.ok) perr(p, "%s", chk.message); + if (!chk.ok) perr(p, "%.*s", CFREE_SLICE_ARG(cfree_slice_cstr(chk.message))); coerce_top_to_type(p, param_ty); } ++nargs; @@ -3347,7 +3362,7 @@ void parse_assign_expr(Parser* p) { const Type* rhs = cg_top_type(p->cg); CSemCheck chk = c_sem_check_assignment(p->pool, lhs, rhs, C_SEM_ASSIGN_EXPR); - if (!chk.ok) perr(p, "%s", chk.message); + if (!chk.ok) perr(p, "%.*s", CFREE_SLICE_ARG(cfree_slice_cstr(chk.message))); } coerce_top_to_lvalue(p); cg_store(p->cg); @@ -3408,7 +3423,7 @@ void parse_assign_expr(Parser* p) { break; } CSemCheck chk = c_sem_check_compound_assignment(p->pool, lhs, rhs, op); - if (!chk.ok) perr(p, "%s", chk.message); + if (!chk.ok) perr(p, "%.*s", CFREE_SLICE_ARG(cfree_slice_cstr(chk.message))); } if (compound == BO_IADD || compound == BO_ISUB) { emit_add_or_sub(p, compound); diff --git a/lang/c/parse/parse_init.c b/lang/c/parse/parse_init.c @@ -329,7 +329,7 @@ static void init_field_at(Parser* p, FrameSlot slot, const Type* arr_ty, const Type* rhs = cg_top_type(p->cg); CSemCheck chk = c_sem_check_assignment(p->pool, f->type, rhs, C_SEM_ASSIGN_INIT); - if (!chk.ok) perr(p, "%s", chk.message); + if (!chk.ok) perr(p, "%.*s", CFREE_SLICE_ARG(cfree_slice_cstr(chk.message))); } coerce_top_to_lvalue(p); cg_store(p->cg); @@ -750,7 +750,7 @@ void init_at(Parser* p, FrameSlot slot, const Type* arr_ty, u32 offset, { const Type* rhs = cg_top_type(p->cg); CSemCheck chk = c_sem_check_assignment(p->pool, ty, rhs, C_SEM_ASSIGN_INIT); - if (!chk.ok) perr(p, "%s", chk.message); + if (!chk.ok) perr(p, "%.*s", CFREE_SLICE_ARG(cfree_slice_cstr(chk.message))); } coerce_top_to_lvalue(p); cg_store(p->cg); @@ -1001,7 +1001,7 @@ static Sym mint_compound_literal_sym(Parser* p) { } while (dn) buf[wlen++] = digits[--dn]; } - return pool_intern(p->pool, buf, wlen); + return cfree_sym_intern(p->pool->c, (CfreeSlice){ .s = buf, .len = wlen }); } static void static_relocs_swap_empty(Parser* p, StaticRelocSave* save) { diff --git a/lang/c/parse/parse_stmt.c b/lang/c/parse/parse_stmt.c @@ -172,7 +172,7 @@ static void parse_return_stmt(Parser* p) { const Type* rhs = cg_top_type(p->cg); CSemCheck chk = c_sem_check_assignment(p->pool, p->cur_func_ret, rhs, C_SEM_ASSIGN_RETURN); - if (!chk.ok) perr(p, "%s", chk.message); + if (!chk.ok) perr(p, "%.*s", CFREE_SLICE_ARG(cfree_slice_cstr(chk.message))); } expect_punct(p, ';', "';' after return value"); cg_ret(p->cg, 1); @@ -443,8 +443,9 @@ void parse_static_assert(Parser* p) { expect_punct(p, ')', "')' after _Static_assert"); expect_punct(p, ';', "';' after _Static_assert"); if (!v) { - size_t mlen = 0; - const char* mstr = pool_str(p->pool, msg.spelling, &mlen); + CfreeSlice msg_sl = cfree_sym_str(p->pool->c, msg.spelling); + size_t mlen = msg_sl.len; + const char* mstr = msg_sl.s; compiler_panic(p->c, loc, "static assertion failed: %.*s", (int)mlen, mstr ? mstr : ""); } @@ -478,15 +479,16 @@ static const char* parse_asm_str(Parser* p, const char* what) { Sym s; Tok t; if (p->cur.kind != TOK_STR) { - perr(p, "expected string literal in %s", what); + perr(p, "expected string literal in %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(what))); } t = p->cur; advance(p); bytes = decode_string_literal(p, &t, &nlen); if (nlen > 0) nlen -= 1; - s = pool_intern(p->pool, (const char*)bytes, nlen); + s = cfree_sym_intern(p->pool->c, (CfreeSlice){ .s = (const char*)bytes, .len = nlen }); cfree_compiler_context(p->c)->heap->free(cfree_compiler_context(p->c)->heap, bytes, 0); - return pool_str(p->pool, s, NULL); + return cfree_sym_str(p->pool->c, s).s; } static void parse_asm_stmt(Parser* p) { @@ -613,7 +615,7 @@ static void parse_asm_stmt(Parser* p) { const char* cstr; Sym cs; cstr = parse_asm_str(p, "asm clobber"); - cs = pool_intern_cstr(p->pool, cstr); + cs = cfree_sym_intern(p->pool->c, cfree_slice_cstr(cstr)); if (nclob == cap_clob) { u32 nc = cap_clob * 2; Sym* nb = (Sym*)arena_array(p->pool->arena, Sym, nc); diff --git a/lang/c/parse/parse_type.c b/lang/c/parse/parse_type.c @@ -71,14 +71,14 @@ static int accept_kw(Parser* p, CKw k) { } static int attr_sym_canon_eq(Parser* p, Sym sym, const char* want) { - size_t len = 0; - const char* s = pool_str(p->pool, sym, &len); + CfreeSlice sym_sl = cfree_sym_str(p->pool->c, sym); + size_t len = sym_sl.len; + const char* s = sym_sl.s; const char* cs; size_t clen; - size_t wlen = strlen(want); if (!s) return 0; attr_canon_range(s, len, &cs, &clen); - return clen == wlen && memcmp(cs, want, wlen) == 0; + return cfree_slice_eq_cstr((CfreeSlice){ .s = cs, .len = clen }, want); } static const Type* attrs_apply_type_mode(Parser* p, const Type* base, @@ -163,8 +163,9 @@ static void attr_canon_range(const char* s, size_t len, const char** out_p, } static AttrKind classify_attr(Parser* p, Sym name, AttrArgShape* shape_out) { - size_t len = 0; - const char* s = pool_str(p->pool, name, &len); + CfreeSlice name_sl = cfree_sym_str(p->pool->c, name); + size_t len = name_sl.len; + const char* s = name_sl.s; const char* cs; size_t clen; size_t i; @@ -175,8 +176,7 @@ static AttrKind classify_attr(Parser* p, Sym name, AttrArgShape* shape_out) { attr_canon_range(s, len, &cs, &clen); for (i = 0; i < sizeof(kAttrTable) / sizeof(kAttrTable[0]); ++i) { const char* tn = kAttrTable[i].name; - size_t tlen = strlen(tn); - if (tlen == clen && memcmp(tn, cs, clen) == 0) { + if (cfree_slice_eq_cstr((CfreeSlice){ .s = cs, .len = clen }, tn)) { *shape_out = kAttrTable[i].shape; return kAttrTable[i].kind; } @@ -214,13 +214,15 @@ static void parse_attr_args(Parser* p, Attr* a, AttrArgShape shape, shape == AS_OPAQUE) { return; } - perr(p, "attribute '%s' expects '(' arguments", attr_diag_name); + perr(p, "attribute '%.*s' expects '(' arguments", + CFREE_SLICE_ARG(cfree_slice_cstr(attr_diag_name))); } switch (shape) { case AS_NONE: { advance(p); /* '(' */ if (!accept_punct(p, ')')) { - perr(p, "attribute '%s' takes no arguments", attr_diag_name); + perr(p, "attribute '%.*s' takes no arguments", + CFREE_SLICE_ARG(cfree_slice_cstr(attr_diag_name))); } return; } @@ -234,7 +236,8 @@ static void parse_attr_args(Parser* p, Attr* a, AttrArgShape shape, advance(p); /* '(' */ if (is_punct(&p->cur, ')')) { if (shape == AS_INT) { - perr(p, "attribute '%s' expects an integer argument", attr_diag_name); + perr(p, "attribute '%.*s' expects an integer argument", + CFREE_SLICE_ARG(cfree_slice_cstr(attr_diag_name))); } advance(p); return; @@ -252,14 +255,15 @@ static void parse_attr_args(Parser* p, Attr* a, AttrArgShape shape, case AS_STRING: { advance(p); /* '(' */ if (p->cur.kind != TOK_STR) { - perr(p, "attribute '%s' expects a string literal", attr_diag_name); + perr(p, "attribute '%.*s' expects a string literal", + CFREE_SLICE_ARG(cfree_slice_cstr(attr_diag_name))); } { Tok t = p->cur; size_t nlen = 0; u8* bytes = decode_string_literal(p, &t, &nlen); u32 ilen = (nlen > 0) ? (u32)(nlen - 1) : 0; - a->v.sym = pool_intern(p->pool, (const char*)bytes, ilen); + a->v.sym = cfree_sym_intern(p->pool->c, (CfreeSlice){ .s = (const char*)bytes, .len = ilen }); cfree_compiler_context(p->c)->heap->free(cfree_compiler_context(p->c)->heap, bytes, 0); } a->nargs = 1; @@ -270,7 +274,8 @@ static void parse_attr_args(Parser* p, Attr* a, AttrArgShape shape, case AS_IDENT: { advance(p); /* '(' */ if (p->cur.kind != TOK_IDENT) { - perr(p, "attribute '%s' expects an identifier", attr_diag_name); + perr(p, "attribute '%.*s' expects an identifier", + CFREE_SLICE_ARG(cfree_slice_cstr(attr_diag_name))); } a->v.sym = p->cur.v.ident; a->nargs = 1; @@ -339,7 +344,11 @@ Attr* parse_attribute_spec_list(Parser* p) { a->name = aname; a->kind = (u16)classify_attr(p, aname, &shape); advance(p); - diag_name = pool_str(p->pool, aname, &diag_len); + { + CfreeSlice aname_sl = cfree_sym_str(p->pool->c, aname); + diag_name = aname_sl.s; + diag_len = aname_sl.len; + } attr_canon_range(diag_name, diag_len, &canon, &canon_len); (void)canon; (void)canon_len; diff --git a/lang/c/sem/sem.c b/lang/c/sem/sem.c @@ -1,5 +1,3 @@ -#include <string.h> - #include "sem/sem.h" static int is_void_pointer(const Type* t) { @@ -8,13 +6,12 @@ static int is_void_pointer(const Type* t) { } static int is_builtin_va_list_record(Pool* p, const Type* t) { - size_t n = 0; - const char* s; + CfreeSlice s; if (!t || t->kind != TY_STRUCT || !t->rec.tag) return 0; - s = pool_str(p, t->rec.tag, &n); - if (!s) return 0; - return (n == 9 && memcmp(s, "__va_list", 9) == 0) || - (n == 13 && memcmp(s, "__va_list_tag", 13) == 0); + s = cfree_sym_str(p->c, t->rec.tag); + if (!s.s) return 0; + return cfree_slice_eq_cstr(s, "__va_list") || + cfree_slice_eq_cstr(s, "__va_list_tag"); } static int pointer_pointees_assignable(Pool* p, const Type* lhs, diff --git a/lang/cpp/cpp.c b/lang/cpp/cpp.c @@ -20,7 +20,8 @@ static SrcLoc cpp_no_loc(void) { } static _Noreturn void cpp_bad_options(Compiler* c, const char* msg) { - compiler_panic(c, cpp_no_loc(), "bad preprocess options: %s", msg); + compiler_panic(c, cpp_no_loc(), "bad preprocess options: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(msg))); } static void cpp_apply_options(Pp* pp, const CfreePreprocessOptions* opts) { @@ -33,17 +34,19 @@ static void cpp_apply_options(Pp* pp, const CfreePreprocessOptions* opts) { pp_add_include_dir(pp, opts->system_include_dirs[i], 1); } for (i = 0; i < opts->ndefines; ++i) { - const char* body = opts->defines[i].body ? opts->defines[i].body : "1"; - pp_define(pp, opts->defines[i].name, body); + const char* body = + opts->defines[i].body.len ? opts->defines[i].body.s : "1"; + pp_define(pp, opts->defines[i].name.s, body); } for (i = 0; i < opts->nundefines; ++i) { - pp_undef(pp, opts->undefines[i]); + pp_undef(pp, opts->undefines[i].s); } } typedef struct CppRun { const CfreePreprocessOptions* opts; - const CfreeBytes* input; + CfreeSlice name; + const CfreeSlice* input; CfreeWriter* out; } CppRun; @@ -53,18 +56,18 @@ static CfreeStatus cpp_preprocess_body(CfreeCompiler* c, void* user) { Pp* pp; const CfreePreprocessOptions* opts = r->opts; - const CfreeBytes* input = r->input; + const CfreeSlice* input = r->input; CfreeWriter* out = r->out; if (!opts || !input || !out) { cpp_bad_options(c, "preprocess args missing"); } - if (!input->name) cpp_bad_options(c, "input name is NULL"); + if (!r->name.s) cpp_bad_options(c, "input name is NULL"); if (!input->data && input->len != 0) { cpp_bad_options(c, "input data is NULL but len > 0"); } - lex = lex_open_mem(c, input->name, (const char*)input->data, input->len); + lex = lex_open_mem(c, r->name.s, input->s, input->len); pp = pp_new(c); if (!lex || !pp) compiler_panic(c, cpp_no_loc(), "C preprocessor out of memory"); @@ -77,9 +80,11 @@ static CfreeStatus cpp_preprocess_body(CfreeCompiler* c, void* user) { CfreeStatus cfree_cpp_preprocess(CfreeCompiler* c, const CfreePreprocessOptions* opts, - const CfreeBytes* input, CfreeWriter* out) { + CfreeSlice name, const CfreeSlice* input, + CfreeWriter* out) { CppRun r; r.opts = opts; + r.name = name; r.input = input; r.out = out; return cfree_frontend_run(c, cpp_preprocess_body, &r); diff --git a/lang/cpp/cpp_support.h b/lang/cpp/cpp_support.h @@ -57,23 +57,6 @@ static inline void c_pool_free(Pool* p) { if (h) h->free(h, p, sizeof(*p)); } -static inline Sym pool_intern(Pool* p, const char* s, size_t len) { - return cfree_sym_intern_len(p->c, s, len); -} - -static inline Sym pool_intern_cstr(Pool* p, const char* s) { - return cfree_sym_intern(p->c, s); -} - -static inline const char* pool_str(Pool* p, Sym sym, size_t* len_out) { - return cfree_sym_str(p->c, sym, len_out); -} - -static inline const char* compiler_sym_str(Compiler* c, Sym sym, - size_t* len_out) { - return cfree_sym_str(c, sym, len_out); -} - #define arena_alloc(a, size, align) cfree_arena_alloc((a), (size), (align)) #define arena_zalloc(a, size, align) cfree_arena_zalloc((a), (size), (align)) #define arena_strdup(a, s, len) cfree_arena_strdup((a), (s), (len)) diff --git a/lang/cpp/lex/lex.c b/lang/cpp/lex/lex.c @@ -138,7 +138,7 @@ Lexer* lex_open_mem(Compiler* c, const char* name, const char* src, l->len = src ? len : 0; l->pos = 0; l->file_id = 0; - (void)cfree_source_add_memory(c, name, &l->file_id); + (void)cfree_source_add_memory(c, cfree_slice_cstr(name), &l->file_id); l->line = 1; l->col = 1; l->at_bol = 1; @@ -175,7 +175,9 @@ static Sym intern_spliced(Lexer* l, size_t start, size_t end) { break; } } - if (!has_splice) return pool_intern(l->pool, l->src + start, end - start); + if (!has_splice) + return cfree_sym_intern( + l->pool->c, (CfreeSlice){ .s = l->src + start, .len = end - start }); buf = (char*)l->heap->alloc(l->heap, end - start, 1); k = 0; @@ -186,7 +188,7 @@ static Sym intern_spliced(Lexer* l, size_t start, size_t end) { } buf[k++] = l->src[i++]; } - sym = pool_intern(l->pool, buf, k); + sym = cfree_sym_intern(l->pool->c, (CfreeSlice){ .s = buf, .len = k }); l->heap->free(l->heap, buf, end - start); return sym; } @@ -455,9 +457,8 @@ Tok lex_next(Lexer* l) { t.spelling = intern_spliced(l, start, l->pos); t.v.ident = t.spelling; if (l->dstate == 1) { - size_t slen = 0; - const char* sstr = pool_str(l->pool, t.spelling, &slen); - l->dstate = (sstr && matches_include_kw(sstr, slen)) ? 2 : 0; + CfreeSlice s = cfree_sym_str(l->pool->c, t.spelling); + l->dstate = (s.s && matches_include_kw(s.s, s.len)) ? 2 : 0; } else { l->dstate = 0; } @@ -525,7 +526,7 @@ Tok lex_next(Lexer* l) { break; } } - t.spelling = pool_intern(l->pool, pbuf, k); + t.spelling = cfree_sym_intern(l->pool->c, (CfreeSlice){ .s = pbuf, .len = k }); l->heap->free(l->heap, pbuf, plen ? plen : 1); l->dstate = 0; return t; diff --git a/lang/cpp/pp/pp.c b/lang/cpp/pp/pp.c @@ -181,9 +181,8 @@ void pp_emit_text(Pp* pp, Writer* out) { w_str(out, " ", 1); } if (t.spelling) { - size_t slen = 0; - const char* s = pool_str(pp->pool, t.spelling, &slen); - w_str(out, s, slen); + CfreeSlice s = cfree_sym_str(pp->pool->c, t.spelling); + w_str(out, s.s, s.len); } at_bol = 0; } @@ -195,31 +194,31 @@ void pp_emit_text(Pp* pp, Writer* out) { static void pp_intern_keywords(Pp* pp) { Pool* p = pp->pool; - pp->sym_define = pool_intern_cstr(p, "define"); - pp->sym_undef = pool_intern_cstr(p, "undef"); - pp->sym_include = pool_intern_cstr(p, "include"); - pp->sym_if = pool_intern_cstr(p, "if"); - pp->sym_ifdef = pool_intern_cstr(p, "ifdef"); - pp->sym_ifndef = pool_intern_cstr(p, "ifndef"); - pp->sym_elif = pool_intern_cstr(p, "elif"); - pp->sym_else = pool_intern_cstr(p, "else"); - pp->sym_endif = pool_intern_cstr(p, "endif"); - pp->sym_line = pool_intern_cstr(p, "line"); - pp->sym_pragma = pool_intern_cstr(p, "pragma"); + pp->sym_define = cfree_sym_intern(p->c, CFREE_SLICE_LIT("define")); + pp->sym_undef = cfree_sym_intern(p->c, CFREE_SLICE_LIT("undef")); + pp->sym_include = cfree_sym_intern(p->c, CFREE_SLICE_LIT("include")); + pp->sym_if = cfree_sym_intern(p->c, CFREE_SLICE_LIT("if")); + pp->sym_ifdef = cfree_sym_intern(p->c, CFREE_SLICE_LIT("ifdef")); + pp->sym_ifndef = cfree_sym_intern(p->c, CFREE_SLICE_LIT("ifndef")); + pp->sym_elif = cfree_sym_intern(p->c, CFREE_SLICE_LIT("elif")); + pp->sym_else = cfree_sym_intern(p->c, CFREE_SLICE_LIT("else")); + pp->sym_endif = cfree_sym_intern(p->c, CFREE_SLICE_LIT("endif")); + pp->sym_line = cfree_sym_intern(p->c, CFREE_SLICE_LIT("line")); + pp->sym_pragma = cfree_sym_intern(p->c, CFREE_SLICE_LIT("pragma")); pp->sym_pragma_kw = pp->sym_pragma; - pp->sym_error = pool_intern_cstr(p, "error"); - pp->sym_warning = pool_intern_cstr(p, "warning"); - pp->sym_embed = pool_intern_cstr(p, "embed"); - pp->sym_defined = pool_intern_cstr(p, "defined"); - pp->sym_va_args = pool_intern_cstr(p, "__VA_ARGS__"); - pp->sym_line__ = pool_intern_cstr(p, "__LINE__"); - pp->sym_file__ = pool_intern_cstr(p, "__FILE__"); - pp->sym_date__ = pool_intern_cstr(p, "__DATE__"); - pp->sym_time__ = pool_intern_cstr(p, "__TIME__"); - pp->sym_stdc__ = pool_intern_cstr(p, "__STDC__"); - pp->sym_stdc_hosted__ = pool_intern_cstr(p, "__STDC_HOSTED__"); - pp->sym_stdc_version__ = pool_intern_cstr(p, "__STDC_VERSION__"); - pp->sym__pragma = pool_intern_cstr(p, "_Pragma"); + pp->sym_error = cfree_sym_intern(p->c, CFREE_SLICE_LIT("error")); + pp->sym_warning = cfree_sym_intern(p->c, CFREE_SLICE_LIT("warning")); + pp->sym_embed = cfree_sym_intern(p->c, CFREE_SLICE_LIT("embed")); + pp->sym_defined = cfree_sym_intern(p->c, CFREE_SLICE_LIT("defined")); + pp->sym_va_args = cfree_sym_intern(p->c, CFREE_SLICE_LIT("__VA_ARGS__")); + pp->sym_line__ = cfree_sym_intern(p->c, CFREE_SLICE_LIT("__LINE__")); + pp->sym_file__ = cfree_sym_intern(p->c, CFREE_SLICE_LIT("__FILE__")); + pp->sym_date__ = cfree_sym_intern(p->c, CFREE_SLICE_LIT("__DATE__")); + pp->sym_time__ = cfree_sym_intern(p->c, CFREE_SLICE_LIT("__TIME__")); + pp->sym_stdc__ = cfree_sym_intern(p->c, CFREE_SLICE_LIT("__STDC__")); + pp->sym_stdc_hosted__ = cfree_sym_intern(p->c, CFREE_SLICE_LIT("__STDC_HOSTED__")); + pp->sym_stdc_version__ = cfree_sym_intern(p->c, CFREE_SLICE_LIT("__STDC_VERSION__")); + pp->sym__pragma = cfree_sym_intern(p->c, CFREE_SLICE_LIT("_Pragma")); } /* Decompose unix seconds into UTC y/M/d/h/m/s. Algorithm: Howard Hinnant, @@ -275,8 +274,10 @@ static void compute_date_time(Pp* pp) { int64_t t = cfree_compiler_context(pp->c)->now; PpYMD ymd; if (t < 0) { - pp->val_date_str = pool_intern_cstr(pp->pool, "\"??? ?? ????\""); - pp->val_time_str = pool_intern_cstr(pp->pool, "\"??:??:??\""); + pp->val_date_str = + cfree_sym_intern(pp->pool->c, CFREE_SLICE_LIT("\"??? ?? ????\"")); + pp->val_time_str = + cfree_sym_intern(pp->pool->c, CFREE_SLICE_LIT("\"??:??:??\"")); return; } pp_break_time(t, &ymd); @@ -295,7 +296,8 @@ static void compute_date_time(Pp* pp) { date[p++] = (char)('0' + (yyyy / 10) % 10); date[p++] = (char)('0' + (yyyy) % 10); date[p++] = '"'; - pp->val_date_str = pool_intern(pp->pool, date, (size_t)p); + pp->val_date_str = + cfree_sym_intern(pp->pool->c, (CfreeSlice){ .s = date, .len = (size_t)p }); } { int hh = ymd.h, mm = ymd.m, ss = ymd.s; @@ -310,7 +312,8 @@ static void compute_date_time(Pp* pp) { tm[p++] = (char)('0' + (ss / 10) % 10); tm[p++] = (char)('0' + ss % 10); tm[p++] = '"'; - pp->val_time_str = pool_intern(pp->pool, tm, (size_t)p); + pp->val_time_str = + cfree_sym_intern(pp->pool->c, (CfreeSlice){ .s = tm, .len = (size_t)p }); } } @@ -349,7 +352,7 @@ static void pp_register_target_predefined(Pp* pp) { int wchar16 = win; for (i = 0; i < narch_defs; ++i) { - pp_define(pp, arch_defs[i].name, arch_defs[i].body); + pp_define(pp, arch_defs[i].name.s, arch_defs[i].body.s); } pp_define(pp, "__USER_LABEL_PREFIX__", @@ -770,8 +773,8 @@ void pp_define(Pp* pp, const char* name, const char* body) { /* Stage 1+2: build a synthetic source line "name body\n" and run it * through the lexer + define machinery so command-line -D matches the * normal #define path. */ - size_t nlen = name ? strlen(name) : 0; - size_t blen = body ? strlen(body) : 0; + size_t nlen = name ? cfree_slice_cstr(name).len : 0; + size_t blen = body ? cfree_slice_cstr(body).len : 0; Heap* h = pp_heap(pp); char* buf; size_t pos = 0; @@ -810,7 +813,7 @@ void pp_define(Pp* pp, const char* name, const char* body) { void pp_undef(Pp* pp, const char* name) { Sym s; if (!name || !*name) return; - s = pool_intern_cstr(pp->pool, name); + s = cfree_sym_intern(pp->pool->c, cfree_slice_cstr(name)); mt_del(pp, s); } diff --git a/lang/cpp/pp/pp_directive.c b/lang/cpp/pp/pp_directive.c @@ -120,7 +120,9 @@ static void prepass_defined(Pp* pp, const Tok* in, u32 nin, TokVec* out) { t.kind = TOK_NUM; t.flags = in[i].flags & (TF_AT_BOL | TF_HAS_SPACE); t.loc = in[i].loc; - t.spelling = pool_intern_cstr(pp->pool, mt_get(pp, ident) ? "1" : "0"); + t.spelling = cfree_sym_intern( + pp->pool->c, mt_get(pp, ident) ? CFREE_SLICE_LIT("1") + : CFREE_SLICE_LIT("0")); tv_push(pp, out, t); } i = j - 1; @@ -157,7 +159,7 @@ static void expand_for_if(Pp* pp, const Tok* in, u32 nin, TokVec* out) { * has been handled. */ static void replace_remaining_if_identifiers(Pp* pp, TokVec* toks) { u32 i; - Sym zero = pool_intern_cstr(pp->pool, "0"); + Sym zero = cfree_sym_intern(pp->pool->c, CFREE_SLICE_LIT("0")); for (i = 0; i < toks->n; ++i) { if (toks->data[i].kind == TOK_IDENT) { toks->data[i].kind = TOK_NUM; @@ -194,19 +196,17 @@ static i64 ee_primary(EE* e) { const Tok* t = ee_peek(e); if (!t) compiler_panic(e->pp->c, e->loc, "#if: missing operand"); if (t->kind == TOK_NUM) { - size_t slen; - const char* s = pool_str(e->pp->pool, t->spelling, &slen); + CfreeSlice s = cfree_sym_str(e->pp->pool->c, t->spelling); ++e->pos; - return parse_pp_int(s, slen); + return parse_pp_int(s.s, s.len); } if (t->kind == TOK_CHR) { /* Treat as the codepoint of the first character (post-decoding * not implemented; cover the common case of a single ASCII * char). */ - size_t slen; - const char* s = pool_str(e->pp->pool, t->spelling, &slen); + CfreeSlice s = cfree_sym_str(e->pp->pool->c, t->spelling); ++e->pos; - if (slen >= 3 && s[0] == '\'') return (unsigned char)s[1]; + if (s.len >= 3 && s.s[0] == '\'') return (unsigned char)s.s[1]; return 0; } if (t->kind == TOK_PUNCT && t->v.punct == '(') { @@ -629,7 +629,9 @@ static int includer_dir(Pp* pp, SrcLoc loc, char* dir_out, size_t cap) { size_t dlen; memset(&sf, 0, sizeof(sf)); if (cfree_source_file(pp->c, loc.file_id, &sf) == 0 && sf.name) { - p = pool_str(pp->pool, sf.name, &plen); + CfreeSlice s = cfree_sym_str(pp->pool->c, sf.name); + p = s.s; + plen = s.len; } if (!p || plen == 0 || p[0] == '<') { if (cap < 2) return 0; @@ -670,7 +672,7 @@ static int find_and_open_include(Pp* pp, const char* path, int system, char* resolved, size_t resolved_cap) { char buf[4096]; u32 i; - size_t plen = strlen(path); + size_t plen = cfree_slice_cstr(path).len; if (plen > 0 && path[0] == '/') { if (try_open_include(pp, path, data, size)) { @@ -684,7 +686,7 @@ static int find_and_open_include(Pp* pp, const char* path, int system, if (!system) { char dir[4096]; if (includer_dir(pp, loc, dir, sizeof(dir))) { - size_t dlen = strlen(dir); + size_t dlen = cfree_slice_cstr(dir).len; if (dlen + 1 + plen + 1 <= sizeof(buf)) { memcpy(buf, dir, dlen); buf[dlen] = '/'; @@ -700,7 +702,7 @@ static int find_and_open_include(Pp* pp, const char* path, int system, } for (i = 0; i < pp->ninc_dirs; ++i) { const char* d = pp->inc_dirs[i].path; - size_t dlen = strlen(d); + size_t dlen = cfree_slice_cstr(d).len; if (dlen + 1 + plen + 1 > sizeof(buf)) continue; memcpy(buf, d, dlen); buf[dlen] = '/'; @@ -724,8 +726,9 @@ static void parse_include_path(Pp* pp, const Tok* line, u32 n, SrcLoc loc, if (n == 0) compiler_panic(pp->c, loc, "#include: missing path"); if (line[0].kind == TOK_HEADER) { - size_t slen = 0; - const char* s = pool_str(pp->pool, line[0].spelling, &slen); + CfreeSlice sl = cfree_sym_str(pp->pool->c, line[0].spelling); + const char* s = sl.s; + size_t slen = sl.len; if (slen < 2) compiler_panic(pp->c, loc, "#include: malformed header name"); if (s[0] == '<' && s[slen - 1] == '>') *system_out = 1; @@ -751,8 +754,9 @@ static void parse_include_path(Pp* pp, const Tok* line, u32 n, SrcLoc loc, compiler_panic(pp->c, loc, "#include: empty after macro replacement"); } if (exp.data[0].kind == TOK_STR) { - size_t slen = 0; - const char* s = pool_str(pp->pool, exp.data[0].spelling, &slen); + CfreeSlice sl = cfree_sym_str(pp->pool->c, exp.data[0].spelling); + const char* s = sl.s; + size_t slen = sl.len; if (slen < 2 || s[0] != '"' || s[slen - 1] != '"') { compiler_panic(pp->c, loc, "#include: malformed string"); } @@ -774,7 +778,9 @@ static void parse_include_path(Pp* pp, const Tok* line, u32 n, SrcLoc loc, break; } if (exp.data[i].spelling) { - s = pool_str(pp->pool, exp.data[i].spelling, &slen); + CfreeSlice sl = cfree_sym_str(pp->pool->c, exp.data[i].spelling); + s = sl.s; + slen = sl.len; } if (s && pos + slen + 1 <= cap) { memcpy(path_out + pos, s, slen); @@ -806,7 +812,8 @@ static void do_include(Pp* pp, const Tok* line, u32 n, SrcLoc loc) { if (!find_and_open_include(pp, path, system_form, loc, &data, &size, resolved, sizeof(resolved))) { - compiler_panic(pp->c, loc, "#include: file not found: %s", path); + compiler_panic(pp->c, loc, "#include: file not found: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(path))); } /* Walk the source stack to find the current includer's file_id. */ @@ -861,19 +868,18 @@ static void do_line(Pp* pp, const Tok* line, u32 n, SrcLoc loc) { compiler_panic(pp->c, loc, "#line: expected line number"); } { - size_t sl = 0; - const char* s = pool_str(pp->pool, exp.data[0].spelling, &sl); - target_line = parse_pp_int(s, sl); + CfreeSlice s = cfree_sym_str(pp->pool->c, exp.data[0].spelling); + target_line = parse_pp_int(s.s, s.len); } if (exp.n >= 2) { if (exp.data[1].kind != TOK_STR) { compiler_panic(pp->c, loc, "#line: file argument must be a string"); } { - size_t sl = 0; - const char* s = pool_str(pp->pool, exp.data[1].spelling, &sl); - if (sl >= 2 && s[0] == '"' && s[sl - 1] == '"') { - target_file = pool_intern(pp->pool, s + 1, sl - 2); + CfreeSlice s = cfree_sym_str(pp->pool->c, exp.data[1].spelling); + if (s.len >= 2 && s.s[0] == '"' && s.s[s.len - 1] == '"') { + target_file = cfree_sym_intern( + pp->pool->c, (CfreeSlice){ .s = s.s + 1, .len = s.len - 2 }); } } } @@ -907,7 +913,7 @@ void emit_pragma_line(Pp* pp, const Tok* line, u32 n, SrcLoc loc) { hash.kind = TOK_PP_HASH; hash.flags = TF_AT_BOL; hash.loc = loc; - hash.spelling = pool_intern_cstr(pp->pool, "#"); + hash.spelling = cfree_sym_intern(pp->pool->c, CFREE_SLICE_LIT("#")); tv_push(pp, &out, hash); memset(&ident, 0, sizeof(ident)); @@ -939,11 +945,14 @@ void emit_pragma_line(Pp* pp, const Tok* line, u32 n, SrcLoc loc) { } static int pragma_num_u32(Pp* pp, const Tok* t, u32* out) { - size_t len = 0; const char* s; + size_t len; u32 v = 0; + CfreeSlice sl; if (!t || t->kind != TOK_NUM || !out) return 0; - s = pool_str(pp->pool, t->spelling, &len); + sl = cfree_sym_str(pp->pool->c, t->spelling); + s = sl.s; + len = sl.len; if (!s || len == 0) return 0; for (size_t i = 0; i < len; ++i) { if (s[i] < '0' || s[i] > '9') break; @@ -957,8 +966,9 @@ static void handle_pragma_pack(Pp* pp, const Tok* line, u32 n) { u32 i = 0; if (n < 3 || line[0].kind != TOK_IDENT) return; { - size_t len = 0; - const char* s = pool_str(pp->pool, line[0].v.ident, &len); + CfreeSlice sl = cfree_sym_str(pp->pool->c, line[0].v.ident); + const char* s = sl.s; + size_t len = sl.len; if (!s || len != 4 || memcmp(s, "pack", 4) != 0) return; } if (line[1].kind != TOK_PUNCT || line[1].v.punct != '(') return; @@ -968,8 +978,9 @@ static void handle_pragma_pack(Pp* pp, const Tok* line, u32 n) { return; } if (i < n && line[i].kind == TOK_IDENT) { - size_t len = 0; - const char* s = pool_str(pp->pool, line[i].v.ident, &len); + CfreeSlice sl = cfree_sym_str(pp->pool->c, line[i].v.ident); + const char* s = sl.s; + size_t len = sl.len; if (s && len == 4 && memcmp(s, "push", 4) == 0) { if (pp->pack_stack_n < (u32)(sizeof pp->pack_stack / sizeof pp->pack_stack[0])) { @@ -1007,8 +1018,9 @@ static void do_pragma(Pp* pp, const Tok* line, u32 n, SrcLoc loc) { * does its own escape handling for any string literals nested inside. */ static void destringize(Pp* pp, const Tok* str_tok, char* out, size_t cap, size_t* out_len) { - size_t slen = 0; - const char* s = pool_str(pp->pool, str_tok->spelling, &slen); + CfreeSlice sl = cfree_sym_str(pp->pool->c, str_tok->spelling); + const char* s = sl.s; + size_t slen = sl.len; size_t i, w = 0; if (slen < 2 || s[0] != '"' || s[slen - 1] != '"') { compiler_panic(pp->c, str_tok->loc, @@ -1094,9 +1106,11 @@ int try_expand_pragma_op(Pp* pp, const Tok* invoke) { static void directive_message(Pp* pp, const Tok* line, u32 n, CharBuf* cb) { u32 i; for (i = 0; i < n; ++i) { - size_t sl = 0; - const char* s = - line[i].spelling ? pool_str(pp->pool, line[i].spelling, &sl) : NULL; + CfreeSlice slc = line[i].spelling + ? cfree_sym_str(pp->pool->c, line[i].spelling) + : CFREE_SLICE_NULL; + const char* s = slc.s; + size_t sl = slc.len; if (i > 0) cb_putc(pp, cb, ' '); if (s && sl) cb_append(pp, cb, s, (u32)sl); } @@ -1117,13 +1131,15 @@ static void pp_warn(Pp* pp, SrcLoc loc, const char* fmt, ...) { static void do_error(Pp* pp, const Tok* line, u32 n, SrcLoc loc) { CharBuf cb = {0}; directive_message(pp, line, n, &cb); - compiler_panic(pp->c, loc, "#error: %s", cb.data ? cb.data : ""); + compiler_panic(pp->c, loc, "#error: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(cb.data ? cb.data : ""))); } static void do_warning(Pp* pp, const Tok* line, u32 n, SrcLoc loc) { CharBuf cb = {0}; directive_message(pp, line, n, &cb); - pp_warn(pp, loc, "#warning: %s", cb.data ? cb.data : ""); + pp_warn(pp, loc, "#warning: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(cb.data ? cb.data : ""))); } /* ============================================================ @@ -1147,8 +1163,9 @@ static void do_embed(Pp* pp, const Tok* line, u32 n, SrcLoc loc) { if (n == 0) compiler_panic(pp->c, loc, "#embed: missing path"); if (line[0].kind == TOK_HEADER) { - size_t sl = 0; - const char* s = pool_str(pp->pool, line[0].spelling, &sl); + CfreeSlice slc = cfree_sym_str(pp->pool->c, line[0].spelling); + const char* s = slc.s; + size_t sl = slc.len; if (sl < 2) compiler_panic(pp->c, loc, "#embed: malformed header name"); if (s[0] == '<' && s[sl - 1] == '>') system_form = 1; @@ -1167,8 +1184,9 @@ static void do_embed(Pp* pp, const Tok* line, u32 n, SrcLoc loc) { j = arg_start; while (j < n) { if (line[j].kind == TOK_IDENT) { - size_t sl = 0; - const char* s = pool_str(pp->pool, line[j].v.ident, &sl); + CfreeSlice slc = cfree_sym_str(pp->pool->c, line[j].v.ident); + const char* s = slc.s; + size_t sl = slc.len; if (sl == 5 && memcmp(s, "limit", 5) == 0) { if (j + 1 >= n || line[j + 1].kind != TOK_PUNCT || line[j + 1].v.punct != '(') { @@ -1179,9 +1197,8 @@ static void do_embed(Pp* pp, const Tok* line, u32 n, SrcLoc loc) { compiler_panic(pp->c, loc, "#embed: limit() expects an integer"); } { - size_t sl2 = 0; - const char* s2 = pool_str(pp->pool, line[j].spelling, &sl2); - limit_n = parse_pp_int(s2, sl2); + CfreeSlice s2 = cfree_sym_str(pp->pool->c, line[j].spelling); + limit_n = parse_pp_int(s2.s, s2.len); } ++j; if (j >= n || line[j].kind != TOK_PUNCT || line[j].v.punct != ')') { @@ -1225,7 +1242,8 @@ static void do_embed(Pp* pp, const Tok* line, u32 n, SrcLoc loc) { if (!find_and_open_include(pp, path, system_form, loc, &data, &size, resolved, sizeof(resolved))) { - compiler_panic(pp->c, loc, "#embed: file not found: %s", path); + compiler_panic(pp->c, loc, "#embed: file not found: %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(path))); } /* Apply limit(). */ @@ -1268,7 +1286,8 @@ static void do_embed(Pp* pp, const Tok* line, u32 n, SrcLoc loc) { memset(&t, 0, sizeof(t)); t.kind = TOK_NUM; t.loc = loc; - t.spelling = pool_intern(pp->pool, numbuf, (size_t)nl); + t.spelling = cfree_sym_intern( + pp->pool->c, (CfreeSlice){ .s = numbuf, .len = (size_t)nl }); if (i == 0) t.flags = TF_AT_BOL; /* Bytes after a comma get a leading space to match * clang's `, ` separator format. */ @@ -1282,7 +1301,7 @@ static void do_embed(Pp* pp, const Tok* line, u32 n, SrcLoc loc) { comma.kind = TOK_PUNCT; comma.v.punct = ','; comma.loc = loc; - comma.spelling = pool_intern_cstr(pp->pool, ","); + comma.spelling = cfree_sym_intern(pp->pool->c, CFREE_SLICE_LIT(",")); tv_push(pp, &out, comma); } } diff --git a/lang/cpp/pp/pp_expand.c b/lang/cpp/pp/pp_expand.c @@ -662,9 +662,10 @@ static Tok make_stringize(Pp* pp, const Tok* arg, u32 lo, u32 hi, SrcLoc loc) { cb_putc(pp, &b, '"'); for (i = lo; i < hi; ++i) { const Tok* at = &arg[i]; - size_t slen = 0; - const char* s = - at->spelling ? pool_str(pp->pool, at->spelling, &slen) : NULL; + CfreeSlice sl = + at->spelling ? cfree_sym_str(pp->pool->c, at->spelling) : CFREE_SLICE_NULL; + const char* s = sl.s; + size_t slen = sl.len; if (i > lo && (at->flags & TF_HAS_SPACE)) cb_putc(pp, &b, ' '); if (s && slen) { int esc = (at->kind == TOK_STR || at->kind == TOK_CHR); @@ -678,7 +679,7 @@ static Tok make_stringize(Pp* pp, const Tok* arg, u32 lo, u32 hi, SrcLoc loc) { } cb_putc(pp, &b, '"'); - sp = pool_intern(pp->pool, b.data, b.len); + sp = cfree_sym_intern(pp->pool->c, (CfreeSlice){ .s = b.data, .len = b.len }); memset(&t, 0, sizeof(t)); t.kind = TOK_STR; t.loc = loc; @@ -700,8 +701,20 @@ static Tok paste_tokens(Pp* pp, Tok lhs, Tok rhs, SrcLoc loc) { if (lhs.kind == TOK_PP_PLACEMARKER) return rhs; if (rhs.kind == TOK_PP_PLACEMARKER) return lhs; - a = lhs.spelling ? pool_str(pp->pool, lhs.spelling, &alen) : ""; - b = rhs.spelling ? pool_str(pp->pool, rhs.spelling, &blen) : ""; + if (lhs.spelling) { + CfreeSlice s = cfree_sym_str(pp->pool->c, lhs.spelling); + a = s.s; + alen = s.len; + } else { + a = ""; + } + if (rhs.spelling) { + CfreeSlice s = cfree_sym_str(pp->pool->c, rhs.spelling); + b = s.s; + blen = s.len; + } else { + b = ""; + } if (alen + blen + 2 > sizeof(buf)) { compiler_panic(pp->c, loc, "token paste: spelling too long"); } @@ -987,7 +1000,8 @@ Tok pp_next_raw(Pp* pp) { while (j > 0) buf[k++] = tmp[--j]; } t.kind = TOK_NUM; - t.spelling = pool_intern(pp->pool, buf, (size_t)k); + t.spelling = + cfree_sym_intern(pp->pool->c, (CfreeSlice){ .s = buf, .len = (size_t)k }); return t; } if (id == pp->sym_file__) { @@ -1005,13 +1019,18 @@ Tok pp_next_raw(Pp* pp) { name = sf.name; } } - if (name) nstr = pool_str(pp->pool, name, &nlen); + if (name) { + CfreeSlice s = cfree_sym_str(pp->pool->c, name); + nstr = s.s; + nlen = s.len; + } buf = (char*)arena_alloc(pp->arena, nlen + 2, 1); buf[0] = '"'; if (nlen) memcpy(buf + 1, nstr, nlen); buf[nlen + 1] = '"'; t.kind = TOK_STR; - t.spelling = pool_intern(pp->pool, buf, nlen + 2); + t.spelling = + cfree_sym_intern(pp->pool->c, (CfreeSlice){ .s = buf, .len = nlen + 2 }); t.v.str = t.spelling; return t; } diff --git a/lang/toy/asm.c b/lang/toy/asm.c @@ -61,7 +61,7 @@ static int toy_asm_is_decimal_constraint(const char* s) { static int toy_validate_asm_output_constraint(ToyParser* p, const CfreeCgAsmOperand* op) { - const char* s = cfree_sym_str(p->c, op->constraint, NULL); + const char* s = cfree_sym_str(p->c, op->constraint).s; const char* body = toy_asm_constraint_body(s); if (op->dir == CFREE_CG_ASM_OUT) { if (!s || s[0] != '=' || body[0] != 'r' || body[1] != '\0') { @@ -79,7 +79,7 @@ static int toy_validate_asm_output_constraint(ToyParser* p, static int toy_validate_asm_input_constraint(ToyParser* p, const CfreeCgAsmOperand* op) { - const char* s = cfree_sym_str(p->c, op->constraint, NULL); + const char* s = cfree_sym_str(p->c, op->constraint).s; if ((s && s[0] && !s[1] && (s[0] == 'r' || s[0] == 'i' || s[0] == 'm')) || toy_asm_is_decimal_constraint(s)) { @@ -179,7 +179,7 @@ static int toy_parse_asm_input_operand(ToyParser* p, toy_error(p, p->cur.loc, "expected asm input operand"); return 0; } - mem_constraint = cfree_sym_intern(p->c, "m"); + mem_constraint = cfree_sym_intern(p->c, CFREE_SLICE_LIT("m")); if (operand->constraint == mem_constraint && p->cur.kind == TOK_IDENT) { CfreeSym name = toy_tok_sym(p, p->cur); toy_parser_advance(p); diff --git a/lang/toy/builtins.c b/lang/toy/builtins.c @@ -112,7 +112,7 @@ static int toy_parse_memory_align_operand(ToyParser* p, int64_t* align, } static int toy_parse_access_group(ToyParser* p, CfreeCgMemAccess* access) { - CfreeSym access_name = cfree_sym_intern(p->c, "access"); + CfreeSym access_name = cfree_sym_intern(p->c, CFREE_SLICE_LIT("access")); if (p->cur.kind != TOK_IDENT || toy_tok_sym(p, p->cur) != access_name) return 0; toy_parser_advance(p); @@ -495,12 +495,13 @@ CfreeCgTypeId toy_parse_builtin_call(ToyParser* p, CfreeSym name, if (toy_sym_is(p, name, "compile_error")) { CfreeSym msg; size_t msg_len; - const char* text; + CfreeSlice text; if (!toy_parser_expect(p, TOK_LPAREN) || !toy_parse_string_sym(p, &msg, &msg_len) || !toy_parser_expect(p, TOK_RPAREN)) return CFREE_CG_TYPE_NONE; - text = cfree_sym_str(p->c, msg, NULL); - toy_error(p, p->cur.loc, "compile_error: %s", text ? text : ""); + text = cfree_sym_str(p->c, msg); + toy_error(p, p->cur.loc, "compile_error: %.*s", + CFREE_SLICE_ARG(text)); cfree_cg_push_int(p->cg, 0, p->int_type); return p->int_type; } @@ -959,9 +960,9 @@ CfreeCgTypeId toy_parse_generic_builtin(ToyParser* p, CfreeSym name, } cfree_cg_intrinsic(p->cg, intrin, 2, ty); memset(fields, 0, sizeof fields); - fields[0].name = cfree_sym_intern(p->c, "value"); + fields[0].name = cfree_sym_intern(p->c, CFREE_SLICE_LIT("value")); fields[0].type = ty; - fields[1].name = cfree_sym_intern(p->c, "overflow"); + fields[1].name = cfree_sym_intern(p->c, CFREE_SLICE_LIT("overflow")); fields[1].type = toy_builtin_type(p, CFREE_CG_BUILTIN_BOOL); rec_ty = cfree_cg_type_record(p->c, 0, fields, 2); rec_slot = cfree_cg_local(p->cg, rec_ty, toy_slot_attrs(0)); @@ -1279,9 +1280,9 @@ CfreeCgTypeId toy_parse_atomic_generic_builtin(ToyParser* p, CfreeSym name, } cfree_cg_atomic_cmpxchg(p->cg, access, success_order, failure_order, weak); memset(fields, 0, sizeof fields); - fields[0].name = cfree_sym_intern(p->c, "prior"); + fields[0].name = cfree_sym_intern(p->c, CFREE_SLICE_LIT("prior")); fields[0].type = ty; - fields[1].name = cfree_sym_intern(p->c, "ok"); + fields[1].name = cfree_sym_intern(p->c, CFREE_SLICE_LIT("ok")); fields[1].type = toy_builtin_type(p, CFREE_CG_BUILTIN_BOOL); rec_ty = cfree_cg_type_record(p->c, 0, fields, 2); rec_slot = cfree_cg_local(p->cg, rec_ty, toy_slot_attrs(0)); diff --git a/lang/toy/compile.c b/lang/toy/compile.c @@ -34,7 +34,7 @@ static int toy_build_repl_source(ToyFrontend* fe, const uint8_t** source_out, size_t* source_len_out, char** owned_out, size_t* owned_cap_out) { - const char* name = opts->repl_entry_name; + CfreeSlice name = opts->repl_entry_name; const char* body = input->bytes.data ? (const char*)input->bytes.data : ""; size_t body_len = input->bytes.data ? input->bytes.len : 0u; char* src = NULL; @@ -49,9 +49,9 @@ static int toy_build_repl_source(ToyFrontend* fe, *source_len_out = body_len; return 1; } - if (!name || !*name) return 0; + if (!name.s || !name.len) return 0; if (!toy_buf_append(fe, &src, &len, &cap, "fn ", 3) || - !toy_buf_append(fe, &src, &len, &cap, name, strlen(name)) || + !toy_buf_append(fe, &src, &len, &cap, name.s, name.len) || !toy_buf_append(fe, &src, &len, &cap, "(): i64 {\n", 10)) { goto oom; } @@ -163,11 +163,11 @@ static CfreeStatus toy_frontend_compile(CfreeFrontendState* frontend, if (st != CFREE_OK) goto done_status; if (!fe->parser_live) { - toy_parser_init(&fe->parser, c, cg, source, source_len, input->bytes.name); + toy_parser_init(&fe->parser, c, cg, source, source_len, input->name.s); fe->parser.input_kind = opts->input_kind; fe->parser_live = 1; } else { - toy_parser_reinit(&fe->parser, c, cg, source, source_len, input->bytes.name, + toy_parser_reinit(&fe->parser, c, cg, source, source_len, input->name.s, opts->input_kind); } p = fe->parser; @@ -215,11 +215,12 @@ static void toy_frontend_free(CfreeFrontendState* frontend) { h->free(h, fe, sizeof(*fe)); } -static const char* const toy_extensions[] = {"toy", NULL}; +static const CfreeSlice toy_extensions[] = {CFREE_SLICE_LIT("toy")}; const CfreeFrontendVTable cfree_toy_frontend_vtable = { toy_frontend_new, toy_frontend_compile, toy_frontend_free, toy_extensions, + (uint32_t)(sizeof toy_extensions / sizeof toy_extensions[0]), }; diff --git a/lang/toy/decls.c b/lang/toy/decls.c @@ -157,7 +157,7 @@ int toy_parse_tuple_decl(ToyParser* p) { goto done; } snprintf(field_name_buf, sizeof field_name_buf, "%u", (uint32_t)nfields); - fields[nfields].name = cfree_sym_intern(p->c, field_name_buf); + fields[nfields].name = cfree_sym_intern(p->c, cfree_slice_cstr(field_name_buf)); fields[nfields].type = toy_parse_type(p); if (fields[nfields].type == CFREE_CG_TYPE_NONE) goto done; field_infos[nfields].name = fields[nfields].name; diff --git a/lang/toy/literals.c b/lang/toy/literals.c @@ -32,7 +32,7 @@ int toy_parse_string_sym(ToyParser* p, CfreeSym* out, size_t* len_out) { } memcpy(buf, p->cur.text + 1, len); buf[len] = '\0'; - *out = cfree_sym_intern(p->c, buf); + *out = cfree_sym_intern(p->c, (CfreeSlice){ .s = buf, .len = len }); if (len_out) *len_out = len; toy_parser_advance(p); return 1; diff --git a/lang/toy/parser.c b/lang/toy/parser.c @@ -735,7 +735,7 @@ static int toy_parse_let_stmt(ToyParser* p) { } } snprintf(sym_name, sizeof sym_name, ".Ltoy_static_%u", p->static_counter++); - linkage_name = cfree_sym_intern(p->c, sym_name); + linkage_name = cfree_sym_intern(p->c, cfree_slice_cstr(sym_name)); memset(&decl, 0, sizeof decl); decl.kind = CFREE_CG_DECL_OBJECT; decl.linkage_name = linkage_name; diff --git a/lang/toy/parser_core.c b/lang/toy/parser_core.c @@ -15,12 +15,14 @@ void* toy_parser_zalloc(ToyParser* p, size_t count, size_t elem_size, size_t size = count * elem_size; void* items; if (count != 0 && size / count != elem_size) { - toy_error(p, p->cur.loc, "out of memory growing %s", what); + toy_error(p, p->cur.loc, "out of memory growing %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(what))); return NULL; } items = h->alloc(h, size ? size : 1u, 1); if (!items) { - toy_error(p, p->cur.loc, "out of memory growing %s", what); + toy_error(p, p->cur.loc, "out of memory growing %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(what))); return NULL; } memset(items, 0, size ? size : 1u); @@ -37,7 +39,7 @@ void toy_parser_free_mem(ToyParser* p, void* items, size_t size) { static uint32_t toy_source_file_id(CfreeCompiler* c, const char* name) { uint32_t file_id = 0; if (name && *name) - (void)cfree_source_add_memory(c, name, &file_id); + (void)cfree_source_add_memory(c, cfree_slice_cstr(name), &file_id); return file_id; } @@ -189,14 +191,16 @@ int toy_parser_reserve(ToyParser* p, void** items, size_t* cap, size_t want, old_size = *cap * elem_size; new_size = new_cap * elem_size; if (new_cap != 0 && new_size / new_cap != elem_size) { - toy_error(p, p->cur.loc, "out of memory growing %s", what); + toy_error(p, p->cur.loc, "out of memory growing %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(what))); return 0; } h = cfree_compiler_context(p->c)->heap; new_items = h->realloc(h, *items, old_size ? old_size : 1u, new_size ? new_size : 1u, 1); if (!new_items) { - toy_error(p, p->cur.loc, "out of memory growing %s", what); + toy_error(p, p->cur.loc, "out of memory growing %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(what))); return 0; } memset((uint8_t*)new_items + (*cap * elem_size), 0, @@ -245,11 +249,11 @@ CfreeSym toy_tok_sym(ToyParser* p, ToyToken tok) { } memcpy(buf, tok.text, tok.text_len); buf[tok.text_len] = '\0'; - return cfree_sym_intern(p->c, buf); + return cfree_sym_intern(p->c, (CfreeSlice){ .s = buf, .len = tok.text_len }); } int toy_sym_is(ToyParser* p, CfreeSym sym, const char* name) { - return sym == cfree_sym_intern(p->c, name); + return sym == cfree_sym_intern(p->c, cfree_slice_cstr(name)); } int toy_skip_attr_list_ex(ToyParser* p, int* has_static) { diff --git a/lang/toy/types.c b/lang/toy/types.c @@ -584,9 +584,9 @@ ToyTypeId toy_type_register_slice(ToyParser* p, CfreeCgTypeId elem_cg, } ptr_ty = cfree_cg_type_ptr(p->c, elem_cg, 0); memset(fields, 0, sizeof fields); - fields[0].name = cfree_sym_intern(p->c, "ptr"); + fields[0].name = cfree_sym_intern(p->c, CFREE_SLICE_LIT("ptr")); fields[0].type = ptr_ty; - fields[1].name = cfree_sym_intern(p->c, "len"); + fields[1].name = cfree_sym_intern(p->c, CFREE_SLICE_LIT("len")); fields[1].type = p->int_type; memset(&type, 0, sizeof type); type.kind = TOY_TYPE_SLICE; diff --git a/lang/wasm/cg.c b/lang/wasm/cg.c @@ -233,53 +233,53 @@ static void wasm_cg_build_runtime(CfreeCompiler* c, CfreeCgBuiltinTypes b, rt->i8_ptr_ty = cfree_cg_type_ptr(c, b.id[CFREE_CG_BUILTIN_I8], 0); rt->void_ptr_ty = rt->i8_ptr_ty; memset(memory_fields, 0, sizeof memory_fields); - memory_fields[0].name = cfree_sym_intern(c, "data"); + memory_fields[0].name = cfree_sym_intern(c, CFREE_SLICE_LIT("data")); memory_fields[0].type = rt->i8_ptr_ty; - memory_fields[1].name = cfree_sym_intern(c, "pages"); + memory_fields[1].name = cfree_sym_intern(c, CFREE_SLICE_LIT("pages")); memory_fields[1].type = b.id[CFREE_CG_BUILTIN_I64]; - memory_fields[2].name = cfree_sym_intern(c, "max_pages"); + memory_fields[2].name = cfree_sym_intern(c, CFREE_SLICE_LIT("max_pages")); memory_fields[2].type = b.id[CFREE_CG_BUILTIN_I64]; - memory_fields[3].name = cfree_sym_intern(c, "flags"); + memory_fields[3].name = cfree_sym_intern(c, CFREE_SLICE_LIT("flags")); memory_fields[3].type = b.id[CFREE_CG_BUILTIN_I32]; rt->memory_ty = cfree_cg_type_record( - c, cfree_sym_intern(c, "CfreeWasmMemory"), memory_fields, 4); + c, cfree_sym_intern(c, CFREE_SLICE_LIT("CfreeWasmMemory")), memory_fields, 4); rt->memory_data_offset = wasm_cg_field_offset(c, rt->memory_ty, 0); rt->memory_pages_offset = wasm_cg_field_offset(c, rt->memory_ty, 1); rt->memory_max_pages_offset = wasm_cg_field_offset(c, rt->memory_ty, 2); rt->memory_flags_offset = wasm_cg_field_offset(c, rt->memory_ty, 3); memset(func_import_fields, 0, sizeof func_import_fields); - func_import_fields[0].name = cfree_sym_intern(c, "fn"); + func_import_fields[0].name = cfree_sym_intern(c, CFREE_SLICE_LIT("fn")); func_import_fields[0].type = rt->void_ptr_ty; rt->func_import_ty = cfree_cg_type_record( - c, cfree_sym_intern(c, "CfreeWasmFuncImport"), func_import_fields, 1); + c, cfree_sym_intern(c, CFREE_SLICE_LIT("CfreeWasmFuncImport")), func_import_fields, 1); rt->func_import_fn_offset = wasm_cg_field_offset(c, rt->func_import_ty, 0); memset(global_import_fields, 0, sizeof global_import_fields); - global_import_fields[0].name = cfree_sym_intern(c, "addr"); + global_import_fields[0].name = cfree_sym_intern(c, CFREE_SLICE_LIT("addr")); global_import_fields[0].type = rt->void_ptr_ty; rt->global_import_ty = cfree_cg_type_record( - c, cfree_sym_intern(c, "CfreeWasmGlobalImport"), global_import_fields, 1); + c, cfree_sym_intern(c, CFREE_SLICE_LIT("CfreeWasmGlobalImport")), global_import_fields, 1); rt->global_import_addr_offset = wasm_cg_field_offset(c, rt->global_import_ty, 0); memset(table_entry_fields, 0, sizeof table_entry_fields); - table_entry_fields[0].name = cfree_sym_intern(c, "fn"); + table_entry_fields[0].name = cfree_sym_intern(c, CFREE_SLICE_LIT("fn")); table_entry_fields[0].type = rt->void_ptr_ty; - table_entry_fields[1].name = cfree_sym_intern(c, "typeidx"); + table_entry_fields[1].name = cfree_sym_intern(c, CFREE_SLICE_LIT("typeidx")); table_entry_fields[1].type = b.id[CFREE_CG_BUILTIN_I32]; rt->table_entry_ty = cfree_cg_type_record( - c, cfree_sym_intern(c, "CfreeWasmTableEntry"), table_entry_fields, 2); + c, cfree_sym_intern(c, CFREE_SLICE_LIT("CfreeWasmTableEntry")), table_entry_fields, 2); rt->table_entry_ptr_ty = cfree_cg_type_ptr(c, rt->table_entry_ty, 0); rt->table_entry_fn_offset = wasm_cg_field_offset(c, rt->table_entry_ty, 0); rt->table_entry_typeidx_offset = wasm_cg_field_offset(c, rt->table_entry_ty, 1); rt->table_entry_size = cfree_cg_type_size(c, rt->table_entry_ty); memset(table_fields, 0, sizeof table_fields); - table_fields[0].name = cfree_sym_intern(c, "entries"); + table_fields[0].name = cfree_sym_intern(c, CFREE_SLICE_LIT("entries")); table_fields[0].type = rt->table_entry_ptr_ty; - table_fields[1].name = cfree_sym_intern(c, "len"); + table_fields[1].name = cfree_sym_intern(c, CFREE_SLICE_LIT("len")); table_fields[1].type = b.id[CFREE_CG_BUILTIN_I32]; - table_fields[2].name = cfree_sym_intern(c, "max"); + table_fields[2].name = cfree_sym_intern(c, CFREE_SLICE_LIT("max")); table_fields[2].type = b.id[CFREE_CG_BUILTIN_I32]; - rt->table_ty = cfree_cg_type_record(c, cfree_sym_intern(c, "CfreeWasmTable"), + rt->table_ty = cfree_cg_type_record(c, cfree_sym_intern(c, CFREE_SLICE_LIT("CfreeWasmTable")), table_fields, 3); rt->table_entries_ptr_offset = wasm_cg_field_offset(c, rt->table_ty, 0); rt->table_len_offset = wasm_cg_field_offset(c, rt->table_ty, 1); @@ -294,7 +294,7 @@ static void wasm_cg_build_runtime(CfreeCompiler* c, CfreeCgBuiltinTypes b, else wasm_indexed_name(name, sizeof name, "memory_", i); memory_field_idx[i] = nfields; - instance_fields[nfields].name = cfree_sym_intern(c, name); + instance_fields[nfields].name = cfree_sym_intern(c, cfree_slice_cstr(name)); instance_fields[nfields].type = rt->memory_ty; nfields++; } @@ -305,7 +305,7 @@ static void wasm_cg_build_runtime(CfreeCompiler* c, CfreeCgBuiltinTypes b, wasm_error(c, wasm_loc(0, 0), "wasm: instance layout too large"); wasm_indexed_name(name, sizeof name, "import_func_", i); func_import_field_idx[i] = nfields; - instance_fields[nfields].name = cfree_sym_intern(c, name); + instance_fields[nfields].name = cfree_sym_intern(c, cfree_slice_cstr(name)); instance_fields[nfields].type = rt->func_import_ty; nfields++; } @@ -315,7 +315,7 @@ static void wasm_cg_build_runtime(CfreeCompiler* c, CfreeCgBuiltinTypes b, wasm_error(c, wasm_loc(0, 0), "wasm: instance layout too large"); wasm_indexed_name(name, sizeof name, "func_ref_", i); func_ref_entry_field_idx[i] = nfields; - instance_fields[nfields].name = cfree_sym_intern(c, name); + instance_fields[nfields].name = cfree_sym_intern(c, cfree_slice_cstr(name)); instance_fields[nfields].type = rt->table_entry_ty; nfields++; } @@ -327,7 +327,7 @@ static void wasm_cg_build_runtime(CfreeCompiler* c, CfreeCgBuiltinTypes b, m->globals[i].is_import ? "import_global_" : "global_", i); global_field_idx[i] = nfields; - instance_fields[nfields].name = cfree_sym_intern(c, name); + instance_fields[nfields].name = cfree_sym_intern(c, cfree_slice_cstr(name)); instance_fields[nfields].type = m->globals[i].is_import ? rt->global_import_ty : wasm_cg_type(c, b, m->globals[i].type); @@ -340,18 +340,18 @@ static void wasm_cg_build_runtime(CfreeCompiler* c, CfreeCgBuiltinTypes b, wasm_error(c, wasm_loc(0, 0), "wasm: instance layout too large"); wasm_indexed_name(name, sizeof name, "table_", i); table_field_idx[i] = nfields; - instance_fields[nfields].name = cfree_sym_intern(c, name); + instance_fields[nfields].name = cfree_sym_intern(c, cfree_slice_cstr(name)); instance_fields[nfields].type = rt->table_ty; nfields++; wasm_indexed_name(name, sizeof name, "table_entries_", i); table_entries_field_idx[i] = nfields; - instance_fields[nfields].name = cfree_sym_intern(c, name); + instance_fields[nfields].name = cfree_sym_intern(c, cfree_slice_cstr(name)); instance_fields[nfields].type = cfree_cg_type_array(c, rt->table_entry_ty, max ? max : 1u); nfields++; } rt->instance_ty = cfree_cg_type_record( - c, cfree_sym_intern(c, "CfreeWasmInstance"), instance_fields, nfields); + c, cfree_sym_intern(c, CFREE_SLICE_LIT("CfreeWasmInstance")), instance_fields, nfields); rt->instance_ptr_ty = cfree_cg_type_ptr(c, rt->instance_ty, 0); for (uint32_t i = 0; i < m->nmemories; ++i) rt->memory_offset[i] = @@ -902,7 +902,7 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, if (!rt.trap_func_ty) wasm_error(c, wasm_loc(0, 0), "wasm: failed to create trap type"); for (uint32_t k = 0; k < WASM_TRAP_COUNT; ++k) { - CfreeSym source_name = cfree_sym_intern(c, wasm_trap_name(k)); + CfreeSym source_name = cfree_sym_intern(c, cfree_slice_cstr(wasm_trap_name(k))); memset(&decl, 0, sizeof decl); decl.kind = CFREE_CG_DECL_FUNC; decl.linkage_name = cfree_cg_c_linkage_name(c, source_name); @@ -929,7 +929,7 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, memset(&decl, 0, sizeof decl); decl.kind = CFREE_CG_DECL_FUNC; decl.linkage_name = - cfree_cg_c_linkage_name(c, cfree_sym_intern(c, "__cfree_wasm_init")); + cfree_cg_c_linkage_name(c, cfree_sym_intern(c, CFREE_SLICE_LIT("__cfree_wasm_init"))); decl.display_name = decl.linkage_name; decl.type = cfree_cg_type_func(c, sig); decl.sym.bind = CFREE_SB_GLOBAL; @@ -962,7 +962,7 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, continue; } if (f->export_name) { - source_name = cfree_sym_intern(c, f->export_name); + source_name = f->export_name; } else { size_t pos = 0; const char prefix[] = "__cfree_wasm_func_"; @@ -975,7 +975,7 @@ void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, div /= 10u; } local_name[pos] = '\0'; - source_name = cfree_sym_intern(c, local_name); + source_name = cfree_sym_intern(c, cfree_slice_cstr(local_name)); } memset(&decl, 0, sizeof decl); decl.kind = CFREE_CG_DECL_FUNC; diff --git a/lang/wasm/decode.c b/lang/wasm/decode.c @@ -94,15 +94,15 @@ static void bin_need(BinReader* r, size_t n) { wasm_error(r->c, wasm_loc(0, 0), "wasm: section length out of bounds"); } -static char* bin_name(BinReader* r, CfreeHeap* h, uint32_t* len_out) { +static CfreeSym bin_name(BinReader* r, uint32_t* len_out) { uint32_t n = bin_uleb(r); - char* s; + CfreeSym sym; bin_need(r, n); - s = wasm_strdup(h, (const char*)(r->data + r->pos), n); - if (!s) wasm_error(r->c, wasm_loc(0, 0), "wasm: out of memory"); + sym = cfree_sym_intern( + r->c, (CfreeSlice){.s = (const char*)(r->data + r->pos), .len = n}); r->pos += n; if (len_out) *len_out = n; - return s; + return sym; } static WasmValType bin_val_type(BinReader* r, int refs_ok) { @@ -124,7 +124,7 @@ static WasmValType bin_val_type(BinReader* r, int refs_ok) { return WASM_VAL_I32; } -void wasm_decode_binary(CfreeCompiler* c, const CfreeBytes* input, +void wasm_decode_binary(CfreeCompiler* c, const CfreeSlice* input, WasmModule* out) { BinReader r; uint32_t nfunc_types = 0; @@ -154,12 +154,12 @@ void wasm_decode_binary(CfreeCompiler* c, const CfreeBytes* input, "wasm: relocatable object metadata is not frontend input"); { WasmCustom* cs = wasm_add_custom(c, out); - cs->name = - wasm_strdup(out->heap, (const char*)(r.data + r.pos), name_len); - if (!cs->name) wasm_error(c, wasm_loc(0, 0), "wasm: out of memory"); + cs->name = cfree_sym_intern( + c, + (CfreeSlice){.s = (const char*)(r.data + r.pos), .len = name_len}); r.pos += name_len; - if (strcmp(cs->name, "target_features") == 0 || - strcmp(cs->name, "target-feature") == 0) + if (cs->name == cfree_sym_intern(c, CFREE_SLICE_LIT("target_features")) || + cs->name == cfree_sym_intern(c, CFREE_SLICE_LIT("target-feature"))) out->has_target_features = 1; cs->len = (uint32_t)(end - r.pos); if (cs->len) { @@ -193,8 +193,8 @@ void wasm_decode_binary(CfreeCompiler* c, const CfreeBytes* input, } else if (id == 2) { uint32_t i, count = bin_uleb(&r); for (i = 0; i < count; ++i) { - char* mod = bin_name(&r, out->heap, NULL); - char* name = bin_name(&r, out->heap, NULL); + CfreeSym mod = bin_name(&r, NULL); + CfreeSym name = bin_name(&r, NULL); uint8_t kind = bin_u8(&r); if (kind == 0) { uint32_t typeidx = bin_uleb(&r); @@ -341,11 +341,11 @@ void wasm_decode_binary(CfreeCompiler* c, const CfreeBytes* input, } else if (id == 7) { uint32_t i, count = bin_uleb(&r); for (i = 0; i < count; ++i) { - char* name; + CfreeSym name; uint8_t kind; uint32_t idx; WasmExport* ex; - name = bin_name(&r, out->heap, NULL); + name = bin_name(&r, NULL); kind = bin_u8(&r); idx = bin_uleb(&r); if (kind > 3u) wasm_error(c, wasm_loc(0, 0), "wasm: bad export kind"); @@ -354,23 +354,13 @@ void wasm_decode_binary(CfreeCompiler* c, const CfreeBytes* input, ex->kind = kind; ex->index = idx; if (kind == 0 && idx < out->nfuncs) { - WasmFunc* f = &out->funcs[idx]; - wasm_free_str(out->heap, &f->export_name); - f->export_name = wasm_strdup(out->heap, name, strlen(name)); - if (!f->export_name) - wasm_error(c, wasm_loc(0, 0), "wasm: out of memory"); + out->funcs[idx].export_name = name; } else if (kind == 1 && idx < out->ntables) { - wasm_free_str(out->heap, &out->tables[idx].export_name); - out->tables[idx].export_name = - wasm_strdup(out->heap, name, strlen(name)); + out->tables[idx].export_name = name; } else if (kind == 2 && idx < out->nmemories) { - wasm_free_str(out->heap, &out->memories[idx].export_name); - out->memories[idx].export_name = - wasm_strdup(out->heap, name, strlen(name)); + out->memories[idx].export_name = name; } else if (kind == 3 && idx < out->nglobals) { - wasm_free_str(out->heap, &out->globals[idx].export_name); - out->globals[idx].export_name = - wasm_strdup(out->heap, name, strlen(name)); + out->globals[idx].export_name = name; } } } else if (id == 8) { @@ -1189,7 +1179,7 @@ void wasm_decode_binary(CfreeCompiler* c, const CfreeBytes* input, } } -int wasm_is_binary(const CfreeBytes* input) { +int wasm_is_binary(const CfreeSlice* input) { return input->len >= 4u && input->data[0] == 0x00 && input->data[1] == 0x61 && input->data[2] == 0x73 && input->data[3] == 0x6d; } diff --git a/lang/wasm/encode.c b/lang/wasm/encode.c @@ -38,10 +38,10 @@ static void write_f64(CfreeWriter* w, double value) { for (uint32_t i = 0; i < 8u; ++i) write_byte(w, (uint8_t)(bits >> (i * 8u))); } -static void write_name(CfreeWriter* w, const char* s) { - size_t n = strlen(s); - write_uleb(w, n); - w->write(w, s, n); +static void write_name(CfreeWriter* w, const WasmModule* m, CfreeSym sym) { + CfreeSlice s = cfree_sym_str(m->c, sym); + write_uleb(w, s.len); + if (s.len) w->write(w, s.s, s.len); } static void encode_section(CfreeHeap* h, CfreeWriter* out, uint8_t id, @@ -101,16 +101,16 @@ static void enc_import(CfreeWriter* w, const WasmModule* m) { for (i = 0; i < m->nfuncs; ++i) { const WasmFunc* f = &m->funcs[i]; if (!f->is_import) continue; - write_name(w, f->import_module ? f->import_module : ""); - write_name(w, f->import_name ? f->import_name : ""); + write_name(w, m, f->import_module); + write_name(w, m, f->import_name); write_byte(w, 0); write_uleb(w, f->typeidx); } for (i = 0; i < m->ntables; ++i) { const WasmTable* t = &m->tables[i]; if (!t->is_import) continue; - write_name(w, t->import_module ? t->import_module : ""); - write_name(w, t->import_name ? t->import_name : ""); + write_name(w, m, t->import_module); + write_name(w, m, t->import_name); write_byte(w, 1); write_byte(w, (uint8_t)t->elem_type); write_limits(w, t->min, t->max, t->has_max); @@ -118,16 +118,16 @@ static void enc_import(CfreeWriter* w, const WasmModule* m) { for (i = 0; i < m->nmemories; ++i) { const WasmMemory* mem = &m->memories[i]; if (!mem->is_import) continue; - write_name(w, mem->import_module ? mem->import_module : ""); - write_name(w, mem->import_name ? mem->import_name : ""); + write_name(w, m, mem->import_module); + write_name(w, m, mem->import_name); write_byte(w, 2); write_memory_limits(w, mem); } for (i = 0; i < m->nglobals; ++i) { const WasmGlobal* g = &m->globals[i]; if (!g->is_import) continue; - write_name(w, g->import_module ? g->import_module : ""); - write_name(w, g->import_name ? g->import_name : ""); + write_name(w, m, g->import_module); + write_name(w, m, g->import_name); write_byte(w, 3); write_byte(w, (uint8_t)g->type); write_byte(w, g->mutable_); @@ -161,7 +161,7 @@ static void enc_export(CfreeWriter* w, const WasmModule* m) { uint32_t i; write_uleb(w, m->nexports); for (i = 0; i < m->nexports; ++i) { - write_name(w, m->exports[i].name ? m->exports[i].name : ""); + write_name(w, m, m->exports[i].name); write_byte(w, m->exports[i].kind); write_uleb(w, m->exports[i].index); } @@ -731,13 +731,13 @@ static void enc_start(CfreeWriter* w, const WasmModule* m) { write_uleb(w, m->start_func); } -static void encode_custom(CfreeHeap* h, CfreeWriter* out, +static void encode_custom(CfreeHeap* h, CfreeWriter* out, const WasmModule* m, const WasmCustom* cs) { CfreeWriter* tmp = NULL; size_t len; const uint8_t* bytes; if (cfree_writer_mem(h, &tmp) != CFREE_OK) return; - write_name(tmp, cs->name ? cs->name : ""); + write_name(tmp, m, cs->name); if (cs->len) tmp->write(tmp, cs->data, cs->len); bytes = cfree_writer_mem_bytes(tmp, &len); write_byte(out, 0); @@ -753,7 +753,7 @@ void wasm_encode(CfreeCompiler* c, const WasmModule* m, CfreeHeap* h = cfree_compiler_context(c)->heap; out->write(out, magic, sizeof magic); for (uint32_t i = 0; i < m->ncustoms; ++i) - encode_custom(h, out, &m->customs[i]); + encode_custom(h, out, m, &m->customs[i]); encode_section(h, out, 1, enc_type, m); if (wasm_module_has_imports(m)) encode_section(h, out, 2, enc_import, m); encode_section(h, out, 3, enc_func, m); diff --git a/lang/wasm/insn.c b/lang/wasm/insn.c @@ -22,8 +22,9 @@ void wasm_require_feature(CfreeCompiler* c, const WasmModule* m, const char* feature_name, const char* what) { if (!wasm_feature_enabled(m, feature)) - wasm_error(c, wasm_loc(0, 0), "wasm: %s requires %s", what, - feature_name); + wasm_error(c, wasm_loc(0, 0), "wasm: %.*s requires %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(what)), + CFREE_SLICE_ARG(cfree_slice_cstr(feature_name))); } diff --git a/lang/wasm/module.c b/lang/wasm/module.c @@ -20,23 +20,9 @@ void* wasm_realloc(CfreeHeap* h, void* p, size_t old_n, size_t new_n) { _Alignof(max_align_t)); } -char* wasm_strdup(CfreeHeap* h, const char* s, size_t len) { - char* out = (char*)h->alloc(h, len + 1u, 1); - if (!out) return NULL; - if (len) memcpy(out, s, len); - out[len] = '\0'; - return out; -} - -void wasm_free_str(CfreeHeap* h, char** s) { - if (*s) { - h->free(h, *s, strlen(*s) + 1u); - *s = NULL; - } -} - -void wasm_module_init(WasmModule* m, CfreeHeap* heap) { +void wasm_module_init(WasmModule* m, CfreeCompiler* c, CfreeHeap* heap) { memset(m, 0, sizeof *m); + m->c = c; m->heap = heap; m->features = WASM_FEATURE_THREADS | WASM_FEATURE_TYPED_FUNC_REFS | WASM_FEATURE_TAIL_CALLS | WASM_FEATURE_MULTI_MEMORY | @@ -46,56 +32,33 @@ void wasm_module_init(WasmModule* m, CfreeHeap* heap) { void wasm_module_free(WasmModule* m) { uint32_t i; if (!m || !m->heap) return; - for (i = 0; i < m->ntypes; ++i) wasm_free_str(m->heap, &m->types[i].name); + /* Name fields are interned CfreeSyms owned by the compiler pool, not the + * module, so there is nothing to free for them here. */ if (m->types) m->heap->free(m->heap, m->types, sizeof(*m->types) * m->cap_types); for (i = 0; i < m->nfuncs; ++i) { WasmFunc* f = &m->funcs[i]; - wasm_free_str(m->heap, &f->name); - wasm_free_str(m->heap, &f->import_module); - wasm_free_str(m->heap, &f->import_name); - wasm_free_str(m->heap, &f->export_name); - for (uint32_t j = 0; j < f->nparams + f->nlocals; ++j) - wasm_free_str(m->heap, &f->local_names[j]); if (f->insns) m->heap->free(m->heap, f->insns, sizeof(*f->insns) * f->cap_insns); } if (m->funcs) m->heap->free(m->heap, m->funcs, sizeof(*m->funcs) * m->cap_funcs); for (i = 0; i < m->nmemories; ++i) { - wasm_free_str(m->heap, &m->memories[i].name); - wasm_free_str(m->heap, &m->memories[i].import_module); - wasm_free_str(m->heap, &m->memories[i].import_name); - wasm_free_str(m->heap, &m->memories[i].export_name); if (m->memories[i].data) m->heap->free(m->heap, m->memories[i].data, (size_t)m->memories[i].data_len); } if (m->memories) m->heap->free(m->heap, m->memories, sizeof(*m->memories) * m->cap_memories); - for (i = 0; i < m->ntables; ++i) { - wasm_free_str(m->heap, &m->tables[i].name); - wasm_free_str(m->heap, &m->tables[i].import_module); - wasm_free_str(m->heap, &m->tables[i].import_name); - wasm_free_str(m->heap, &m->tables[i].export_name); - } if (m->tables) m->heap->free(m->heap, m->tables, sizeof(*m->tables) * m->cap_tables); - for (i = 0; i < m->nglobals; ++i) { - wasm_free_str(m->heap, &m->globals[i].name); - wasm_free_str(m->heap, &m->globals[i].import_module); - wasm_free_str(m->heap, &m->globals[i].import_name); - wasm_free_str(m->heap, &m->globals[i].export_name); - } if (m->globals) m->heap->free(m->heap, m->globals, sizeof(*m->globals) * m->cap_globals); if (m->elems) m->heap->free(m->heap, m->elems, sizeof(*m->elems) * m->cap_elems); - for (i = 0; i < m->nexports; ++i) wasm_free_str(m->heap, &m->exports[i].name); if (m->exports) m->heap->free(m->heap, m->exports, sizeof(*m->exports) * m->cap_exports); for (i = 0; i < m->ncustoms; ++i) { - wasm_free_str(m->heap, &m->customs[i].name); if (m->customs[i].data) m->heap->free(m->heap, m->customs[i].data, m->customs[i].len); } diff --git a/lang/wasm/validate.c b/lang/wasm/validate.c @@ -42,7 +42,8 @@ static int wasm_stack_pop(CfreeCompiler* c, WasmValStack* s, wasm_error(c, wasm_loc(0, 0), "wasm: operand stack underflow"); } if (expected && s->vals[s->depth - 1u] != expected) - wasm_error(c, wasm_loc(0, 0), "wasm: %s type mismatch", what); + wasm_error(c, wasm_loc(0, 0), "wasm: %.*s type mismatch", + CFREE_SLICE_ARG(cfree_slice_cstr(what))); s->depth--; return 1; } @@ -57,7 +58,9 @@ static WasmValType wasm_stack_pop_any(CfreeCompiler* c, WasmValStack* s, wasm_error(c, wasm_loc(0, 0), "wasm: operand stack underflow"); } vt = s->vals[s->depth - 1u]; - if (!vt) wasm_error(c, wasm_loc(0, 0), "wasm: %s type mismatch", what); + if (!vt) + wasm_error(c, wasm_loc(0, 0), "wasm: %.*s type mismatch", + CFREE_SLICE_ARG(cfree_slice_cstr(what))); s->depth--; return vt; } @@ -67,7 +70,8 @@ static void wasm_stack_pop_ref(CfreeCompiler* c, WasmValStack* s, const char* what) { WasmValType vt = wasm_stack_pop_any(c, s, frames, nframes, what); if (!wasm_is_ref_type(vt)) - wasm_error(c, wasm_loc(0, 0), "wasm: %s type mismatch", what); + wasm_error(c, wasm_loc(0, 0), "wasm: %.*s type mismatch", + CFREE_SLICE_ARG(cfree_slice_cstr(what))); } static void wasm_mark_unreachable(WasmValStack* s, WasmControlFrame* frames, diff --git a/lang/wasm/wasm.c b/lang/wasm/wasm.c @@ -1,11 +1,11 @@ #include "wasm_internal.h" -static void wasm_parse_any(CfreeCompiler* c, const CfreeBytes* input, - WasmModule* m) { +static void wasm_parse_any(CfreeCompiler* c, CfreeSlice name, + const CfreeSlice* input, WasmModule* m) { if (wasm_is_binary(input)) wasm_decode_binary(c, input, m); else - wasm_parse_wat(c, input, m); + wasm_parse_wat(c, name, input, m); wasm_validate(m, c); } @@ -33,8 +33,8 @@ static CfreeStatus wasm_frontend_compile( if (!fe || !fe->c || !opts || !input || !out) return CFREE_INVALID; c = fe->c; (void)opts->language_options; /* wasm frontend has no per-language options */ - wasm_module_init(&m, cfree_compiler_context(c)->heap); - wasm_parse_any(c, &input->bytes, &m); + wasm_module_init(&m, c, cfree_compiler_context(c)->heap); + wasm_parse_any(c, input->name, &input->bytes, &m); wasm_emit_cg(c, &opts->code, out, &m); wasm_module_free(&m); return CFREE_OK; @@ -48,20 +48,22 @@ static void wasm_frontend_free(CfreeFrontendState* frontend) { h->free(h, fe, sizeof(*fe)); } -static const char* const wasm_extensions[] = {"wat", "wasm", NULL}; +static const CfreeSlice wasm_extensions[] = {CFREE_SLICE_LIT("wat"), + CFREE_SLICE_LIT("wasm")}; const CfreeFrontendVTable cfree_wasm_frontend_vtable = { wasm_frontend_new, wasm_frontend_compile, wasm_frontend_free, wasm_extensions, + (uint32_t)(sizeof wasm_extensions / sizeof wasm_extensions[0]), }; -int cfree_wasm_wat_to_wasm(CfreeCompiler* c, const CfreeBytes* input, +int cfree_wasm_wat_to_wasm(CfreeCompiler* c, const CfreeSlice* input, CfreeWriter* out) { WasmModule m; - wasm_module_init(&m, cfree_compiler_context(c)->heap); - wasm_parse_wat(c, input, &m); + wasm_module_init(&m, c, cfree_compiler_context(c)->heap); + wasm_parse_wat(c, CFREE_SLICE_NULL, input, &m); wasm_validate(&m, c); wasm_encode(c, &m, out); wasm_module_free(&m); diff --git a/lang/wasm/wasm.h b/lang/wasm/wasm.h @@ -11,7 +11,7 @@ extern const CfreeFrontendVTable cfree_wasm_frontend_vtable; /* Internal test/developer helper: parse accepted WAT and write equivalent * binary Wasm. This is intentionally not part of the installed public API. */ -int cfree_wasm_wat_to_wasm(CfreeCompiler*, const CfreeBytes* input, +int cfree_wasm_wat_to_wasm(CfreeCompiler*, const CfreeSlice* input, CfreeWriter* out); #endif diff --git a/lang/wasm/wasm_internal.h b/lang/wasm/wasm_internal.h @@ -231,27 +231,27 @@ typedef struct WasmInsn { } WasmInsn; typedef struct WasmFunc { - char* name; + CfreeSym name; uint32_t typeidx; int has_typeidx; int is_import; - char* import_module; - char* import_name; + CfreeSym import_module; + CfreeSym import_name; WasmValType params[16]; uint32_t nparams; WasmValType locals[32]; uint32_t nlocals; - char* local_names[48]; + CfreeSym local_names[48]; WasmValType results[1]; uint32_t nresults; - char* export_name; + CfreeSym export_name; WasmInsn* insns; uint32_t ninsns; uint32_t cap_insns; } WasmFunc; typedef struct WasmFuncType { - char* name; + CfreeSym name; WasmValType params[16]; uint32_t nparams; WasmValType results[1]; @@ -259,42 +259,42 @@ typedef struct WasmFuncType { } WasmFuncType; typedef struct WasmMemory { - char* name; + CfreeSym name; uint64_t min_pages; uint64_t max_pages; int has_max; int is64; int shared; int is_import; - char* import_module; - char* import_name; - char* export_name; + CfreeSym import_module; + CfreeSym import_name; + CfreeSym export_name; uint8_t* data; uint64_t data_len; uint64_t data_init_len; } WasmMemory; typedef struct WasmTable { - char* name; + CfreeSym name; WasmValType elem_type; uint32_t min; uint32_t max; int has_max; int is_import; - char* import_module; - char* import_name; - char* export_name; + CfreeSym import_module; + CfreeSym import_name; + CfreeSym export_name; } WasmTable; typedef struct WasmGlobal { - char* name; + CfreeSym name; WasmValType type; uint8_t mutable_; WasmInsn init; int is_import; - char* import_module; - char* import_name; - char* export_name; + CfreeSym import_module; + CfreeSym import_name; + CfreeSym export_name; } WasmGlobal; typedef struct WasmElemSegment { @@ -305,18 +305,19 @@ typedef struct WasmElemSegment { } WasmElemSegment; typedef struct WasmExport { - char* name; + CfreeSym name; uint8_t kind; uint32_t index; } WasmExport; typedef struct WasmCustom { - char* name; + CfreeSym name; uint8_t* data; uint32_t len; } WasmCustom; typedef struct WasmModule { + CfreeCompiler* c; CfreeHeap* heap; WasmFuncType* types; uint32_t ntypes; @@ -351,10 +352,8 @@ typedef struct WasmModule { CfreeSrcLoc wasm_loc(uint32_t line, uint32_t col); void wasm_error(CfreeCompiler* c, CfreeSrcLoc loc, const char* fmt, ...); void* wasm_realloc(CfreeHeap* h, void* p, size_t old_n, size_t new_n); -char* wasm_strdup(CfreeHeap* h, const char* s, size_t len); -void wasm_free_str(CfreeHeap* h, char** s); -void wasm_module_init(WasmModule* m, CfreeHeap* heap); +void wasm_module_init(WasmModule* m, CfreeCompiler* c, CfreeHeap* heap); void wasm_module_free(WasmModule* m); void wasm_memory_ensure(CfreeCompiler* c, WasmModule* m, uint32_t memidx, uint64_t needed); @@ -404,10 +403,11 @@ int wasm_fp_binop_kind(uint8_t kind, WasmValType* vt); int wasm_fp_cmp_kind(uint8_t kind, WasmValType* vt); int wasm_conversion_kind(uint8_t kind, WasmValType* src, WasmValType* dst); -void wasm_parse_wat(CfreeCompiler* c, const CfreeBytes* input, WasmModule* out); -void wasm_decode_binary(CfreeCompiler* c, const CfreeBytes* input, +void wasm_parse_wat(CfreeCompiler* c, CfreeSlice name, const CfreeSlice* input, + WasmModule* out); +void wasm_decode_binary(CfreeCompiler* c, const CfreeSlice* input, WasmModule* out); -int wasm_is_binary(const CfreeBytes* input); +int wasm_is_binary(const CfreeSlice* input); void wasm_validate(WasmModule* m, CfreeCompiler* c); void wasm_emit_cg(CfreeCompiler* c, const CfreeCodeOptions* code_opts, CfreeObjBuilder* out, const WasmModule* m); diff --git a/lang/wasm/wat.c b/lang/wasm/wat.c @@ -29,15 +29,13 @@ typedef struct WatParser { } WatParser; static int tok_is(WasmTok t, const char* s) { - size_t n = strlen(s); + size_t n = cfree_slice_cstr(s).len; return t.kind == WT_ATOM && t.len == n && memcmp(t.p, s, n) == 0; } -static int wasm_name_eq(const char* name, WasmTok t) { - size_t n; +static int wasm_name_eq(WatParser* p, CfreeSym name, WasmTok t) { if (!name || t.kind != WT_ATOM) return 0; - n = strlen(name); - return t.len == n && memcmp(name, t.p, n) == 0; + return name == cfree_sym_intern(p->c, (CfreeSlice){.s = t.p, .len = t.len}); } static int wat_hex(char ch) { @@ -96,6 +94,22 @@ static char* wat_dup_string(WatParser* p, WasmTok t, size_t* len_out) { return out; } +/* Decode a WAT string token's escapes and intern the bytes as a CfreeSym. The + * temporary decode buffer is freed; the interned bytes live in the compiler + * pool. */ +static CfreeSym wat_intern_string(WatParser* p, WasmTok t) { + size_t n = 0; + char* decoded = wat_dup_string(p, t, &n); + CfreeSym sym = cfree_sym_intern(p->c, (CfreeSlice){.s = decoded, .len = n}); + p->module->heap->free(p->module->heap, decoded, t.len + 1u); + return sym; +} + +/* Intern a raw token's bytes (e.g. a `$name` identifier) as a CfreeSym. */ +static CfreeSym wat_intern_tok(WatParser* p, WasmTok t) { + return cfree_sym_intern(p->c, (CfreeSlice){.s = t.p, .len = t.len}); +} + static void wat_next(WatParser* p) { const char* s = p->src; while (p->pos < p->len) { @@ -208,8 +222,9 @@ static void wat_next(WatParser* p) { static void wat_expect(WatParser* p, uint8_t kind, const char* what) { if (p->tok.kind != kind) - wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col), "wasm wat: expected %s", - what); + wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col), + "wasm wat: expected %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(what))); wat_next(p); } @@ -286,7 +301,9 @@ static void wat_require_feature(WatParser* p, WasmFeatureSet feature, const char* feature_name, const char* what) { if (!wasm_feature_enabled(p->module, feature)) wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col), - "wasm wat: %s requires %s", what, feature_name); + "wasm wat: %.*s requires %.*s", + CFREE_SLICE_ARG(cfree_slice_cstr(what)), + CFREE_SLICE_ARG(cfree_slice_cstr(feature_name))); } static uint8_t wasm_export_kind_from_tok(WasmTok t) { @@ -1080,7 +1097,7 @@ static void wat_parse_func_index(WatParser* p, int64_t* out) { uint32_t i; if (p->tok.kind == WT_ATOM && p->tok.len && p->tok.p[0] == '$') { for (i = 0; i < p->module->nfuncs; ++i) { - if (wasm_name_eq(p->module->funcs[i].name, p->tok)) { + if (wasm_name_eq(p, p->module->funcs[i].name, p->tok)) { *out = i; return; } @@ -1097,7 +1114,7 @@ static void wat_parse_type_index(WatParser* p, int64_t* out) { uint32_t i; if (p->tok.kind == WT_ATOM && p->tok.len && p->tok.p[0] == '$') { for (i = 0; i < p->module->ntypes; ++i) { - if (wasm_name_eq(p->module->types[i].name, p->tok)) { + if (wasm_name_eq(p, p->module->types[i].name, p->tok)) { *out = i; return; } @@ -1114,7 +1131,7 @@ static void wat_parse_local_index(WatParser* p, WasmFunc* f, int64_t* out) { uint32_t i, nlocals = f->nparams + f->nlocals; if (p->tok.kind == WT_ATOM && p->tok.len && p->tok.p[0] == '$') { for (i = 0; i < nlocals; ++i) { - if (wasm_name_eq(f->local_names[i], p->tok)) { + if (wasm_name_eq(p, f->local_names[i], p->tok)) { *out = i; return; } @@ -1131,7 +1148,7 @@ static void wat_parse_global_index(WatParser* p, int64_t* out) { uint32_t i; if (p->tok.kind == WT_ATOM && p->tok.len && p->tok.p[0] == '$') { for (i = 0; i < p->module->nglobals; ++i) { - if (wasm_name_eq(p->module->globals[i].name, p->tok)) { + if (wasm_name_eq(p, p->module->globals[i].name, p->tok)) { *out = i; return; } @@ -1170,7 +1187,7 @@ static void wat_parse_instr_imm(WatParser* p, WasmFunc* f, WasmInsnKind kind, static int wat_atom_prefix(WasmTok t, const char* prefix) { - size_t n = strlen(prefix); + size_t n = cfree_slice_cstr(prefix).len; return t.kind == WT_ATOM && t.len >= n && memcmp(t.p, prefix, n) == 0; } @@ -1225,7 +1242,7 @@ static void wat_parse_memory_index(WatParser* p, uint32_t* out) { int64_t idx; if (p->tok.kind == WT_ATOM && p->tok.len && p->tok.p[0] == '$') { for (i = 0; i < p->module->nmemories; ++i) { - if (wasm_name_eq(p->module->memories[i].name, p->tok)) { + if (wasm_name_eq(p, p->module->memories[i].name, p->tok)) { *out = i; return; } @@ -1296,7 +1313,8 @@ static void wat_reject_inline_result(WatParser* p, const char* what) { return; } wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col), - "wasm wat: %s results are unsupported", what); + "wasm wat: %.*s results are unsupported", + CFREE_SLICE_ARG(cfree_slice_cstr(what))); } static void wat_parse_instr(WatParser* p, WasmFunc* f); @@ -1687,10 +1705,7 @@ static void wat_parse_func(WatParser* p) { "wasm wat: expected func"); wat_next(p); if (p->tok.kind == WT_ATOM && p->tok.len > 0 && p->tok.p[0] == '$') { - f->name = wasm_strdup(p->module->heap, p->tok.p, p->tok.len); - if (!f->name) - wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col), - "wasm: out of memory"); + f->name = wat_intern_tok(p, p->tok); wat_next(p); } while (p->tok.kind != WT_RPAREN && p->tok.kind != WT_EOF) { @@ -1701,14 +1716,10 @@ static void wat_parse_func(WatParser* p) { if (p->tok.kind != WT_STRING) wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col), "wasm wat: expected export string"); - f->export_name = wat_dup_string(p, p->tok, NULL); + f->export_name = wat_intern_string(p, p->tok); { WasmExport* ex = wasm_add_export(p->c, p->module); - ex->name = wasm_strdup(p->module->heap, f->export_name, - strlen(f->export_name)); - if (!ex->name) - wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col), - "wasm: out of memory"); + ex->name = f->export_name; ex->kind = 0; ex->index = p->module->nfuncs - 1u; } @@ -1755,11 +1766,7 @@ static void wat_parse_func(WatParser* p) { wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col), "wasm wat: parameter does not match type"); if (have_name) { - f->local_names[checked_params] = wasm_strdup( - p->module->heap, pending_name.p, pending_name.len); - if (!f->local_names[checked_params]) - wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col), - "wasm: out of memory"); + f->local_names[checked_params] = wat_intern_tok(p, pending_name); have_name = 0; } checked_params++; @@ -1770,11 +1777,7 @@ static void wat_parse_func(WatParser* p) { wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col), "wasm wat: too many parameters"); if (have_name) { - f->local_names[f->nparams] = - wasm_strdup(p->module->heap, pending_name.p, pending_name.len); - if (!f->local_names[f->nparams]) - wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col), - "wasm: out of memory"); + f->local_names[f->nparams] = wat_intern_tok(p, pending_name); have_name = 0; } f->params[f->nparams++] = vt; @@ -1823,11 +1826,7 @@ static void wat_parse_func(WatParser* p) { "wasm wat: too many locals"); if (have_name) { uint32_t index = f->nparams + f->nlocals; - f->local_names[index] = - wasm_strdup(p->module->heap, pending_name.p, pending_name.len); - if (!f->local_names[index]) - wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col), - "wasm: out of memory"); + f->local_names[index] = wat_intern_tok(p, pending_name); have_name = 0; } f->locals[f->nlocals++] = vt; @@ -1860,10 +1859,7 @@ static void wat_parse_func(WatParser* p) { static void wat_parse_type_field(WatParser* p) { WasmFuncType* t = wasm_add_type(p->c, p->module); if (p->tok.kind == WT_ATOM && p->tok.len && p->tok.p[0] == '$') { - t->name = wasm_strdup(p->module->heap, p->tok.p, p->tok.len); - if (!t->name) - wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col), - "wasm: out of memory"); + t->name = wat_intern_tok(p, p->tok); wat_next(p); } wat_expect(p, WT_LPAREN, "'('"); @@ -1914,13 +1910,13 @@ static void wat_parse_type_field(WatParser* p) { } static void wat_parse_export_field(WatParser* p) { - char* name; + CfreeSym name; int64_t idx = 0; uint8_t kind; if (p->tok.kind != WT_STRING) wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col), "wasm wat: expected export string"); - name = wat_dup_string(p, p->tok, NULL); + name = wat_intern_string(p, p->tok); wat_next(p); wat_expect(p, WT_LPAREN, "'('"); kind = wasm_export_kind_from_tok(p->tok); @@ -1943,34 +1939,13 @@ static void wat_parse_export_field(WatParser* p) { ex->index = (uint32_t)idx; } if (kind == 0 && (uint64_t)idx < p->module->nfuncs) { - wasm_free_str(p->module->heap, &p->module->funcs[idx].export_name); - p->module->funcs[idx].export_name = - wasm_strdup(p->module->heap, name, strlen(name)); - if (!p->module->funcs[idx].export_name) - wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col), - "wasm: out of memory"); + p->module->funcs[idx].export_name = name; } else if (kind == 2 && (uint64_t)idx < p->module->nmemories) { - wasm_free_str(p->module->heap, - &p->module->memories[(uint32_t)idx].export_name); - p->module->memories[(uint32_t)idx].export_name = - wasm_strdup(p->module->heap, name, strlen(name)); - if (!p->module->memories[(uint32_t)idx].export_name) - wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col), - "wasm: out of memory"); + p->module->memories[(uint32_t)idx].export_name = name; } else if (kind == 1 && (uint64_t)idx < p->module->ntables) { - wasm_free_str(p->module->heap, &p->module->tables[idx].export_name); - p->module->tables[idx].export_name = - wasm_strdup(p->module->heap, name, strlen(name)); - if (!p->module->tables[idx].export_name) - wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col), - "wasm: out of memory"); + p->module->tables[idx].export_name = name; } else if (kind == 3 && (uint64_t)idx < p->module->nglobals) { - wasm_free_str(p->module->heap, &p->module->globals[idx].export_name); - p->module->globals[idx].export_name = - wasm_strdup(p->module->heap, name, strlen(name)); - if (!p->module->globals[idx].export_name) - wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col), - "wasm: out of memory"); + p->module->globals[idx].export_name = name; } wat_next(p); wat_expect(p, WT_RPAREN, "')'"); @@ -1981,10 +1956,7 @@ static void wat_parse_memory_field(WatParser* p) { int64_t min_pages, max_pages; WasmMemory* mem = wasm_add_memory(p->c, p->module); if (p->tok.kind == WT_ATOM && p->tok.len && p->tok.p[0] == '$') { - mem->name = wasm_strdup(p->module->heap, p->tok.p, p->tok.len); - if (!mem->name) - wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col), - "wasm: out of memory"); + mem->name = wat_intern_tok(p, p->tok); wat_next(p); } while (p->tok.kind == WT_ATOM && (tok_is(p->tok, "i64") || @@ -2095,16 +2067,16 @@ static void wat_parse_table_limits_and_type(WatParser* p, WasmTable* t) { } static void wat_parse_import_field(WatParser* p) { - char *mod, *name; + CfreeSym mod, name; if (p->tok.kind != WT_STRING) wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col), "wasm wat: expected import module string"); - mod = wat_dup_string(p, p->tok, NULL); + mod = wat_intern_string(p, p->tok); wat_next(p); if (p->tok.kind != WT_STRING) wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col), "wasm wat: expected import name string"); - name = wat_dup_string(p, p->tok, NULL); + name = wat_intern_string(p, p->tok); wat_next(p); wat_expect(p, WT_LPAREN, "'('"); if (tok_is(p->tok, "func")) { @@ -2114,10 +2086,7 @@ static void wat_parse_import_field(WatParser* p) { f->import_name = name; wat_next(p); if (p->tok.kind == WT_ATOM && p->tok.len && p->tok.p[0] == '$') { - f->name = wasm_strdup(p->module->heap, p->tok.p, p->tok.len); - if (!f->name) - wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col), - "wasm: out of memory"); + f->name = wat_intern_tok(p, p->tok); wat_next(p); } while (p->tok.kind != WT_RPAREN && p->tok.kind != WT_EOF) { @@ -2182,10 +2151,7 @@ static void wat_parse_import_field(WatParser* p) { mem->import_name = name; wat_next(p); if (p->tok.kind == WT_ATOM && p->tok.len && p->tok.p[0] == '$') { - mem->name = wasm_strdup(p->module->heap, p->tok.p, p->tok.len); - if (!mem->name) - wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col), - "wasm: out of memory"); + mem->name = wat_intern_tok(p, p->tok); wat_next(p); } wat_parse_memory_limits(p, mem); @@ -2196,10 +2162,7 @@ static void wat_parse_import_field(WatParser* p) { t->import_name = name; wat_next(p); if (p->tok.kind == WT_ATOM && p->tok.len && p->tok.p[0] == '$') { - t->name = wasm_strdup(p->module->heap, p->tok.p, p->tok.len); - if (!t->name) - wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col), - "wasm: out of memory"); + t->name = wat_intern_tok(p, p->tok); wat_next(p); } wat_parse_table_limits_and_type(p, t); @@ -2210,10 +2173,7 @@ static void wat_parse_import_field(WatParser* p) { g->import_name = name; wat_next(p); if (p->tok.kind == WT_ATOM && p->tok.len && p->tok.p[0] == '$') { - g->name = wasm_strdup(p->module->heap, p->tok.p, p->tok.len); - if (!g->name) - wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col), - "wasm: out of memory"); + g->name = wat_intern_tok(p, p->tok); wat_next(p); } if (p->tok.kind == WT_LPAREN) { @@ -2245,10 +2205,7 @@ static void wat_parse_import_field(WatParser* p) { static void wat_parse_table_field(WatParser* p) { WasmTable* t = wasm_add_table(p->c, p->module); if (p->tok.kind == WT_ATOM && p->tok.len && p->tok.p[0] == '$') { - t->name = wasm_strdup(p->module->heap, p->tok.p, p->tok.len); - if (!t->name) - wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col), - "wasm: out of memory"); + t->name = wat_intern_tok(p, p->tok); wat_next(p); } wat_parse_table_limits_and_type(p, t); @@ -2282,10 +2239,7 @@ static void wat_parse_const_expr(WatParser* p, WasmInsn* out) { static void wat_parse_global_field(WatParser* p) { WasmGlobal* g = wasm_add_global(p->c, p->module); if (p->tok.kind == WT_ATOM && p->tok.len && p->tok.p[0] == '$') { - g->name = wasm_strdup(p->module->heap, p->tok.p, p->tok.len); - if (!g->name) - wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col), - "wasm: out of memory"); + g->name = wat_intern_tok(p, p->tok); wat_next(p); } if (p->tok.kind == WT_LPAREN) { @@ -2295,14 +2249,10 @@ static void wat_parse_global_field(WatParser* p) { if (p->tok.kind != WT_STRING) wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col), "wasm wat: expected export string"); - g->export_name = wat_dup_string(p, p->tok, NULL); + g->export_name = wat_intern_string(p, p->tok); { WasmExport* ex = wasm_add_export(p->c, p->module); - ex->name = wasm_strdup(p->module->heap, g->export_name, - strlen(g->export_name)); - if (!ex->name) - wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col), - "wasm: out of memory"); + ex->name = g->export_name; ex->kind = 3; ex->index = p->module->nglobals - 1u; } @@ -2390,9 +2340,9 @@ static void wat_parse_custom_field(WatParser* p) { wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col), "wasm wat: expected custom section name"); cs = wasm_add_custom(p->c, p->module); - cs->name = wat_dup_string(p, p->tok, NULL); - if (strcmp(cs->name, "target_features") == 0 || - strcmp(cs->name, "target-feature") == 0) + cs->name = wat_intern_string(p, p->tok); + if (cs->name == cfree_sym_intern(p->c, CFREE_SLICE_LIT("target_features")) || + cs->name == cfree_sym_intern(p->c, CFREE_SLICE_LIT("target-feature"))) p->module->has_target_features = 1; wat_next(p); if (p->tok.kind == WT_STRING) { @@ -2476,13 +2426,13 @@ static void wat_parse_data_field(WatParser* p) { wat_expect(p, WT_RPAREN, "')'"); } -void wasm_parse_wat(CfreeCompiler* c, const CfreeBytes* input, +void wasm_parse_wat(CfreeCompiler* c, CfreeSlice name, const CfreeSlice* input, WasmModule* out) { WatParser p; memset(&p, 0, sizeof p); p.c = c; - p.name = input->name; - p.src = (const char*)input->data; + p.name = name.s; + p.src = input->s; p.len = input->len; p.line = 1; p.col = 1; diff --git a/scripts/check_no_cstr.sh b/scripts/check_no_cstr.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash +# Phase 6 gate: assert the NUL-terminated-string functions and printf %s have +# been eliminated from the first-party tree (src/, lang/, driver/). rt/ is the +# freestanding runtime/libc and is intentionally exempt. Test code is exempt. +# +# Allowed exceptions: +# - slice_from_cstr / cfree_slice_cstr : the sanctioned boundary scan helpers +# - driver_strlen / driver_streq / driver_strneq : driver host-shim wrappers +# - reloc_kind_name / *_name returning canonical literals (not string ops) +# - ordering compares left intentionally (marked with a nearby comment) +# +# Usage: scripts/check_no_cstr.sh (exit 1 on any disallowed hit) +set -u +cd "$(dirname "$0")/.." + +dirs="src lang driver" +# Forbidden: bare libc string functions. We match the call form `name(`. +banned='\b(strlen|strcmp|strncmp|strcpy|strncpy|strcat|strncat|strstr|strchr|strrchr|strdup)\s*\(' +# printf-family bare %s (not %.*s, not %%s, not width-padded %-Ns / %*s). +pct_s='%[^%."*0-9-]*s|"[^"]*%s' + +fail=0 + +echo "== banned string functions ==" +# src/core/slice.c is the one sanctioned home of a NUL scan (slice_from_cstr). +hits=$(rg -n --pcre2 "$banned" $dirs -g '!*/tests/*' -g '!src/core/slice.c' 2>/dev/null \ + | rg -v 'slice_from_cstr|cfree_slice_cstr|driver_strlen|driver_streq|driver_strneq|driver_strchr|driver_strdup' \ + | rg -v 'ordering|sort|/\* *TODO slice' ) +if [ -n "$hits" ]; then echo "$hits"; fail=1; else echo " clean"; fi + +echo "== bare printf %s ==" +# Heuristic: lines containing "%s" inside a string literal, excluding the +# allowed width/precision/.* forms. Manual review still recommended. +shits=$(rg -n '"[^"]*%s' $dirs 2>/dev/null | rg -v '%\.\*s|%-[0-9]+s|%\*s|%%s') +if [ -n "$shits" ]; then echo "$shits"; fail=1; else echo " clean"; fi + +exit $fail diff --git a/src/api/arch.c b/src/api/arch.c @@ -5,19 +5,24 @@ #include <cfree/arch.h> #include <stddef.h> -const char* cfree_arch_register_name(CfreeArchKind arch, uint32_t dwarf_idx) { +CfreeSlice cfree_arch_register_name(CfreeArchKind arch, uint32_t dwarf_idx) { const ArchImpl* impl = arch_lookup(arch); - if (!impl || !impl->register_name) return NULL; - return impl->register_name(dwarf_idx); + const char* nm; + if (!impl || !impl->register_name) return CFREE_SLICE_NULL; + nm = impl->register_name(dwarf_idx); + return cfree_slice_cstr(nm); } -CfreeStatus cfree_arch_register_index(CfreeArchKind arch, const char* name, +CfreeStatus cfree_arch_register_index(CfreeArchKind arch, CfreeSlice name, uint32_t* idx_out) { const ArchImpl* impl; - if (!name || !idx_out) return CFREE_INVALID; + /* Internal register tables compare NUL-terminated names; name.s comes from + * argv/interned/arena slices that carry a NUL at name.len. */ + if (!name.s || !idx_out) return CFREE_INVALID; impl = arch_lookup(arch); if (!impl || !impl->register_index) return CFREE_UNSUPPORTED; - return impl->register_index(name, idx_out) == 0 ? CFREE_OK : CFREE_NOT_FOUND; + return impl->register_index(name.s, idx_out) == 0 ? CFREE_OK + : CFREE_NOT_FOUND; } uint32_t cfree_arch_register_count(CfreeArchKind arch) { diff --git a/src/api/archive.c b/src/api/archive.c @@ -6,6 +6,7 @@ #include "core/bytes.h" #include "core/core.h" #include "core/heap.h" +#include "core/slice.h" /* ============================================================ * Write helpers @@ -46,17 +47,12 @@ static CfreeStatus wh_be32(Writer* w, u32 v) { return wh_bytes(w, b, 4); } -static void ar_name_basename(const char* in, const char** name_out, - size_t* len_out) { - const char* name = in; - const char* p; - size_t namelen = 0; - for (p = in; *p; ++p) { - if (*p == '/') name = p + 1; +static Slice ar_name_basename(Slice in) { + size_t start = 0, i; + for (i = 0; i < in.len; ++i) { + if (in.s[i] == '/') start = i + 1; } - for (p = name; *p; ++p) ++namelen; - *name_out = name; - *len_out = namelen; + return (Slice){ .s = in.s + start, .len = in.len - start }; } static int ar_name_needs_longtable(const char* name, size_t len) { @@ -67,12 +63,6 @@ static int ar_name_needs_longtable(const char* name, size_t len) { return 0; } -static size_t ar_strlen(const char* s) { - size_t n = 0; - while (s[n]) ++n; - return n; -} - static size_t ar_member_padded_size(size_t len) { return 60 + len + (len & 1); } static void ar_fill_header(char hdr[60], const char name_field[16], @@ -97,7 +87,7 @@ static void ar_fill_header(char hdr[60], const char name_field[16], hdr[59] = '\n'; } -CfreeStatus cfree_ar_write(CfreeWriter* out, const CfreeBytes* members, +CfreeStatus cfree_ar_write(CfreeWriter* out, const CfreeArInput* members, uint32_t nmembers, const CfreeArWriteOptions* opts) { static const char magic[] = "!<arch>\n"; static const CfreeArWriteOptions default_opts = {0, 0, 0, NULL}; @@ -125,17 +115,16 @@ CfreeStatus cfree_ar_write(CfreeWriter* out, const CfreeBytes* members, if (long_names) { for (i = 0; i < nmembers; ++i) { - const char* name; - size_t namelen; - if (!members[i].name) return CFREE_INVALID; - ar_name_basename(members[i].name, &name, &namelen); - if (ar_name_needs_longtable(name, namelen)) { - longtab_size += (uint64_t)namelen + 2; + Slice base; + if (!members[i].name.s) return CFREE_INVALID; + base = ar_name_basename(members[i].name); + if (ar_name_needs_longtable(base.s, base.len)) { + longtab_size += (uint64_t)base.len + 2; } } } else { for (i = 0; i < nmembers; ++i) { - if (!members[i].name) return CFREE_INVALID; + if (!members[i].name.s) return CFREE_INVALID; } } @@ -145,10 +134,10 @@ CfreeStatus cfree_ar_write(CfreeWriter* out, const CfreeBytes* members, u32 k; if (msyms[i].count && !msyms[i].names) return CFREE_INVALID; for (k = 0; k < msyms[i].count; ++k) { - const char* nm = msyms[i].names[k]; - if (!nm) return CFREE_INVALID; + Slice nm = msyms[i].names[k]; + if (!nm.s) return CFREE_INVALID; nsyms += 1; - names_size += (uint64_t)ar_strlen(nm) + 1; + names_size += (uint64_t)nm.len + 1; } } } @@ -181,7 +170,7 @@ CfreeStatus cfree_ar_write(CfreeWriter* out, const CfreeBytes* members, for (k = 0; k < msyms[i].count; ++k) { wh_be32(out, (u32)cur_offset); } - cur_offset += ar_member_padded_size(members[i].len); + cur_offset += ar_member_padded_size(members[i].bytes.len); } } @@ -189,9 +178,10 @@ CfreeStatus cfree_ar_write(CfreeWriter* out, const CfreeBytes* members, for (i = 0; i < nmembers; ++i) { u32 k; for (k = 0; k < msyms[i].count; ++k) { - const char* nm = msyms[i].names[k]; - size_t nmlen = ar_strlen(nm); - wh_bytes(out, nm, nmlen + 1); + Slice nm = msyms[i].names[k]; + static const char nul = '\0'; + wh_bytes(out, nm.s, nm.len); + wh_bytes(out, &nul, 1); } } } @@ -209,11 +199,9 @@ CfreeStatus cfree_ar_write(CfreeWriter* out, const CfreeBytes* members, ar_fill_header(hdr, name_field, 0, longtab_size); wh_bytes(out, hdr, 60); for (i = 0; i < nmembers; ++i) { - const char* name; - size_t namelen; - ar_name_basename(members[i].name, &name, &namelen); - if (ar_name_needs_longtable(name, namelen)) { - wh_bytes(out, name, namelen); + Slice base = ar_name_basename(members[i].name); + if (ar_name_needs_longtable(base.s, base.len)) { + wh_bytes(out, base.s, base.len); wh_bytes(out, "/\n", 2); } } @@ -223,30 +211,28 @@ CfreeStatus cfree_ar_write(CfreeWriter* out, const CfreeBytes* members, { uint64_t longtab_off = 0; for (i = 0; i < nmembers; ++i) { - const CfreeBytes* m = &members[i]; - const char* name; - size_t namelen; + const CfreeArInput* m = &members[i]; + Slice base = ar_name_basename(m->name); char hdr[60]; char name_field[16]; size_t j; - ar_name_basename(m->name, &name, &namelen); - for (j = 0; j < 16; ++j) name_field[j] = ' '; - if (long_names && ar_name_needs_longtable(name, namelen)) { + if (long_names && ar_name_needs_longtable(base.s, base.len)) { name_field[0] = '/'; wh_ar_num(name_field + 1, 15, longtab_off); - longtab_off += (uint64_t)namelen + 2; + longtab_off += (uint64_t)base.len + 2; } else { - size_t emit = namelen > 15 ? 15 : namelen; - for (j = 0; j < emit; ++j) name_field[j] = name[j]; + size_t emit = base.len > 15 ? 15 : base.len; + for (j = 0; j < emit; ++j) name_field[j] = base.s[j]; name_field[emit] = '/'; } - ar_fill_header(hdr, name_field, epoch, (uint64_t)m->len); + ar_fill_header(hdr, name_field, epoch, (uint64_t)m->bytes.len); wh_bytes(out, hdr, 60); - if (m->data && m->len) wh_bytes(out, m->data, m->len); - if (m->len & 1) wh_bytes(out, &pad, 1); + if (m->bytes.data && m->bytes.len) + wh_bytes(out, m->bytes.data, m->bytes.len); + if (m->bytes.len & 1) wh_bytes(out, &pad, 1); } } @@ -285,7 +271,7 @@ static size_t ar_resolve_longname(CfreeArIter* it, uint64_t off) { } CfreeStatus cfree_ar_iter_new(const CfreeContext* ctx, - const CfreeBytes* archive, CfreeArIter** out) { + const CfreeSlice* archive, CfreeArIter** out) { Heap* h; CfreeArIter* it; if (!out) return CFREE_INVALID; @@ -377,7 +363,8 @@ CfreeIterResult cfree_ar_iter_next(CfreeArIter* it, CfreeArMember* out) { it->namebuf[namelen] = '\0'; } - out->name = it->namebuf; + out->name.s = it->namebuf; + out->name.len = namelen; out->data = it->p; out->size = (size_t)size; @@ -404,12 +391,10 @@ void cfree_ar_iter_free(CfreeArIter* it) { h->free(h, it, sizeof(*it)); } -CfreeStatus cfree_ar_list(const CfreeBytes* archive, CfreeWriter* out) { +CfreeStatus cfree_ar_list(const CfreeSlice* archive, CfreeWriter* out) { /* Iter API requires a context; emulate locally without heap allocation. */ struct CfreeArIter local; CfreeArMember m; - size_t namelen; - const char* p; if (!out) return CFREE_INVALID; if (!archive) return CFREE_INVALID; @@ -425,9 +410,7 @@ CfreeStatus cfree_ar_list(const CfreeBytes* archive, CfreeWriter* out) { for (;;) { CfreeIterResult r = cfree_ar_iter_next(&local, &m); if (r != CFREE_ITER_ITEM) break; - namelen = 0; - for (p = m.name; *p; ++p) ++namelen; - wh_bytes(out, m.name, namelen); + wh_bytes(out, m.name.s, m.name.len); wh_nl(out); } diff --git a/src/api/compile.c b/src/api/compile.c @@ -11,6 +11,7 @@ #include "core/heap.h" #include "core/metrics.h" #include "core/pool.h" +#include "core/slice.h" #include "obj/obj.h" typedef struct AsmFrontend { @@ -38,13 +39,14 @@ static CfreeStatus asm_frontend_compile(CfreeFrontendState* fe, CfreeObjBuilder* out); static void asm_frontend_free(CfreeFrontendState* fe); -static const char* const asm_extensions[] = {"s", NULL}; +static const CfreeSlice asm_extensions[] = {CFREE_SLICE_LIT("s")}; const CfreeFrontendVTable cfree_asm_frontend_vtable = { asm_frontend_new, asm_frontend_compile, asm_frontend_free, asm_extensions, + (uint32_t)(sizeof asm_extensions / sizeof asm_extensions[0]), }; static SrcLoc no_loc(void) { @@ -56,26 +58,31 @@ static SrcLoc no_loc(void) { } static _Noreturn void panic_bad_options(Compiler* c, const char* msg) { - compiler_panic(c, no_loc(), "bad cfree options: %s", msg); + compiler_panic(c, no_loc(), "bad cfree options: %.*s", + SLICE_ARG(slice_from_cstr(msg))); } /* Compare `ext` to `pat` letter-for-letter, lowercasing ASCII A-Z in - * the path side so `.S` matches asm's `"s"` entry. Both inputs are - * NUL-terminated; returns nonzero on full match. */ -static int ext_eq_ci(const char* ext, const char* pat) { - while (*ext && *pat) { - char a = *ext++; - char b = *pat++; + * the path side so `.S` matches asm's `"s"` entry. `ext` is a borrowed + * slice over the path tail; `pat` is the frontend's extension slice. + * Returns nonzero on full match. */ +static int ext_eq_ci(CfreeSlice ext, CfreeSlice pat) { + size_t i; + if (ext.len != pat.len) return 0; + for (i = 0; i < ext.len; ++i) { + char a = ext.s[i]; + char b = pat.s[i]; if (a >= 'A' && a <= 'Z') a = (char)(a - 'A' + 'a'); if (a != b) return 0; } - return *ext == 0 && *pat == 0; + return 1; } CfreeLanguage cfree_language_for_path(CfreeCompiler* c, const char* path) { size_t len; size_t i; - const char* ext; + CfreeSlice ext = SLICE_NULL; + int have_ext = 0; unsigned lang; if (!c || !path) return CFREE_LANG_C; @@ -83,24 +90,25 @@ CfreeLanguage cfree_language_for_path(CfreeCompiler* c, const char* path) { } /* Strip back to the last `.` after the final `/`. No dot → no * extension → fall through to the C default. */ - ext = NULL; i = len; while (i > 0) { --i; if (path[i] == '/') break; if (path[i] == '.') { - ext = path + i + 1; + ext.s = path + i + 1; + ext.len = len - (i + 1); + have_ext = 1; break; } } - if (!ext) return CFREE_LANG_C; + if (!have_ext) return CFREE_LANG_C; for (lang = 0; lang < CFREE_LANG_COUNT; ++lang) { const CfreeFrontendVTable* v = c->frontends[lang]; - const char* const* exts; + uint32_t e; if (!v || !v->extensions) continue; - for (exts = v->extensions; *exts; ++exts) { - if (ext_eq_ci(ext, *exts)) return (CfreeLanguage)lang; + for (e = 0; e < v->nextensions; ++e) { + if (ext_eq_ci(ext, v->extensions[e])) return (CfreeLanguage)lang; } } return CFREE_LANG_C; @@ -130,9 +138,9 @@ uint32_t cfree_compiler_arch_predefines(CfreeCompiler* c, return arch->npredefined_macros; } -static void validate_bytes(Compiler* c, const CfreeBytes* in) { - if (!in->name) panic_bad_options(c, "input name is NULL"); - if (!in->data && in->len != 0) { +static void validate_bytes(Compiler* c, const CfreeSourceInput* in) { + if (!in->name.s) panic_bad_options(c, "input name is NULL"); + if (!in->bytes.data && in->bytes.len != 0) { panic_bad_options(c, "input data is NULL but len > 0"); } } @@ -143,7 +151,7 @@ static const CfreeFrontendVTable* frontend_for_language(Compiler* c, return c->frontends[lang]; } -static void validate_bytes(Compiler* c, const CfreeBytes* in); +static void validate_bytes(Compiler* c, const CfreeSourceInput* in); static void compile_frontend_state_into(Compiler* c, const CfreeFrontendVTable* vtable, CfreeFrontendState* frontend, @@ -198,7 +206,7 @@ static CfreeStatus cfree_frontend_compile( compiler_panic_restore(c, &saved); return CFREE_ERR; } - validate_bytes(c, &input->bytes); + validate_bytes(c, input); metrics_scope_begin(c, "compile.tu"); metrics_count(c, "compile.input_bytes", (u64)input->bytes.len); compile_frontend_state_into(c, frontend->vtable, frontend->state, opts, input, @@ -293,8 +301,8 @@ static void compile_frontend_state_into(Compiler* c, st = vtable->compile(frontend, opts, input, ob); metrics_scope_end(c, "compile.frontend"); if (st != CFREE_OK) { - compiler_panic(c, no_loc(), "frontend failed for input: %s", - input->bytes.name); + compiler_panic(c, no_loc(), "frontend failed for input: %.*s", + SLICE_ARG(input->name)); } metrics_scope_begin(c, "compile.obj_finalize"); @@ -331,8 +339,7 @@ static CfreeStatus asm_frontend_compile(CfreeFrontendState* frontend, if (!fe || !fe->c || !input || !out) return CFREE_INVALID; c = fe->c; metrics_scope_begin(c, "compile.asm.lex_open"); - lex = asm_lex_open_mem(c, input->bytes.name, (const char*)input->bytes.data, - input->bytes.len); + lex = asm_lex_open_mem(c, input->name.s, input->bytes.s, input->bytes.len); metrics_scope_end(c, "compile.asm.lex_open"); metrics_scope_begin(c, "compile.asm.mc_new"); mc = mc_new(c, (ObjBuilder*)out); @@ -387,9 +394,9 @@ CfreeIterResult cfree_dep_iter_next(CfreeDepIter* it, CfreeDepEdge* out) { includer = source_file(it->c->sources, edge->includer_file_id); included = source_file(it->c->sources, edge->included_file_id); out->includer_name = - includer ? pool_str(it->c->global, includer->name, NULL) : NULL; + includer ? pool_slice(it->c->global, includer->name) : CFREE_SLICE_NULL; out->included_name = - included ? pool_str(it->c->global, included->name, NULL) : NULL; + included ? pool_slice(it->c->global, included->name) : CFREE_SLICE_NULL; out->include_loc = edge->include_loc; out->from_system_path = (uint8_t)(edge->system ? 1 : 0); out->bracketed = (uint8_t)(edge->system ? 1 : 0); diff --git a/src/api/core.c b/src/api/core.c @@ -7,6 +7,7 @@ #include "core/heap.h" #include "core/pool.h" +#include "core/slice.h" CfreeStatus cfree_compiler_new(CfreeTarget target, const CfreeContext* ctx, CfreeCompiler** out) { @@ -42,30 +43,22 @@ const CfreeContext* cfree_compiler_context(CfreeCompiler* c) { return (c && c->ctx) ? c->ctx : NULL; } -const char* cfree_compiler_file_name(CfreeCompiler* c, uint32_t file_id) { +CfreeSlice cfree_compiler_file_name(CfreeCompiler* c, uint32_t file_id) { const SourceFile* f; - if (!c) return NULL; + if (!c) return SLICE_NULL; f = source_file(c->sources, file_id); - if (!f) return NULL; - return pool_str(c->global, f->name, NULL); + if (!f) return SLICE_NULL; + return pool_slice(c->global, f->name); } -CfreeSym cfree_sym_intern(CfreeCompiler* c, const char* str) { - if (!c || !str) return 0; - return pool_intern_cstr(c->global, str); +CfreeSym cfree_sym_intern(CfreeCompiler* c, CfreeSlice s) { + if (!c) return 0; + return pool_intern_slice(c->global, s); } -CfreeSym cfree_sym_intern_len(CfreeCompiler* c, const char* str, size_t len) { - if (!c || !str || len == 0) return 0; - return pool_intern(c->global, str, (u32)len); -} - -const char* cfree_sym_str(CfreeCompiler* c, CfreeSym sym, size_t* len_out) { - if (!c) { - if (len_out) *len_out = 0; - return NULL; - } - return pool_str(c->global, (Sym)sym, len_out); +CfreeSlice cfree_sym_str(CfreeCompiler* c, CfreeSym sym) { + if (!c) return SLICE_NULL; + return pool_slice(c->global, (Sym)sym); } CfreeSym cfree_cg_c_linkage_name(CfreeCompiler* c, CfreeSym source_name) { @@ -74,9 +67,12 @@ CfreeSym cfree_cg_c_linkage_name(CfreeCompiler* c, CfreeSym source_name) { char* buf; CfreeSym out; Heap* h; + Slice nslice; if (!c || !source_name) return 0; - name = pool_str(c->global, (Sym)source_name, &len); + nslice = pool_slice(c->global, (Sym)source_name); + name = nslice.s; + len = nslice.len; if (!name) return 0; if (c->target.obj != CFREE_OBJ_MACHO) return source_name; @@ -86,7 +82,7 @@ CfreeSym cfree_cg_c_linkage_name(CfreeCompiler* c, CfreeSym source_name) { buf[0] = '_'; if (len) memcpy(buf + 1, name, len); buf[len + 1u] = '\0'; - out = pool_intern(c->global, buf, (u32)(len + 1u)); + out = pool_intern_slice(c->global, (Slice){ .s = buf, .len = (u32)(len + 1u) }); h->free(h, buf, len + 2u); return out; } diff --git a/src/api/disasm.c b/src/api/disasm.c @@ -9,6 +9,7 @@ #include "core/core.h" #include "core/heap.h" #include "core/pool.h" +#include "core/slice.h" #include "core/strbuf.h" #include "obj/obj.h" @@ -34,10 +35,10 @@ struct CfreeDisasmIter { StrBuf ann; }; -static const char* dasm_overlay(CfreeDisasmIter* it, uint64_t vaddr, - uint32_t nbytes) { +static Slice dasm_overlay(CfreeDisasmIter* it, uint64_t vaddr, + uint32_t nbytes) { ObjBuilder* obj = it->annot_ob; - if (!obj) return ""; + if (!obj) return SLICE_LIT(""); strbuf_reset(&it->ann); u64 want = vaddr - it->vaddr0; @@ -55,10 +56,9 @@ static const char* dasm_overlay(CfreeDisasmIter* it, uint64_t vaddr, : NULL; if (sym && sym->name) { Compiler* oc = obj_compiler(obj); - size_t nlen = 0; - const char* nm = oc ? pool_str(oc->global, sym->name, &nlen) : NULL; - if (nm) - strbuf_putn(&it->ann, nm, nlen); + Slice nm = oc ? pool_slice(oc->global, sym->name) : SLICE_NULL; + if (nm.s) + strbuf_putn(&it->ann, nm.s, nm.len); else strbuf_puts(&it->ann, "<anon>"); } else { @@ -81,7 +81,7 @@ static const char* dasm_overlay(CfreeDisasmIter* it, uint64_t vaddr, } break; } - return strbuf_cstr(&it->ann); + return strbuf_slice(&it->ann); } static uint32_t dasm_find_section(const CfreeObjFile* f, const uint8_t* bytes, @@ -146,9 +146,9 @@ CfreeIterResult cfree_disasm_iter_next(CfreeDisasmIter* it, CfreeInsn* out) { out->vaddr = vaddr; out->bytes = it->bytes + it->off; out->nbytes = n; - out->mnemonic = "(truncated)"; - out->operands = ""; - out->annotation = ""; + out->mnemonic = SLICE_LIT("(truncated)"); + out->operands = SLICE_LIT(""); + out->annotation = SLICE_LIT(""); it->off += n; return CFREE_ITER_ITEM; } @@ -167,7 +167,11 @@ void cfree_disasm_iter_free(CfreeDisasmIter* it) { } static CfreeStatus w_str(CfreeWriter* w, const char* s) { - return cfree_writer_write(w, s, strlen(s)); + return cfree_writer_write(w, s, slice_from_cstr(s).len); +} + +static CfreeStatus w_slice(CfreeWriter* w, Slice s) { + return cfree_writer_write(w, s.s, s.len); } static CfreeStatus w_hex(CfreeWriter* w, u64 v, u32 width) { @@ -205,19 +209,19 @@ static CfreeStatus w_hex_padded(CfreeWriter* w, u64 v, u32 minwidth) { return cfree_writer_write(w, buf + i, sizeof(buf) - i); } -static const char* dasm_sym_at(const CfreeObjFile* f, uint32_t section_idx, - uint64_t offset) { +static Slice dasm_sym_at(const CfreeObjFile* f, uint32_t section_idx, + uint64_t offset) { CfreeObjSymIter* si = NULL; - const char* found = NULL; + Slice found = SLICE_NULL; CfreeObjSymInfo s; - if (cfree_obj_symiter_new((CfreeObjFile*)f, &si) != CFREE_OK) return NULL; + if (cfree_obj_symiter_new((CfreeObjFile*)f, &si) != CFREE_OK) return SLICE_NULL; for (;;) { CfreeIterResult r = cfree_obj_symiter_next(si, &s); if (r != CFREE_ITER_ITEM) break; if (s.section != section_idx) continue; if (s.value != offset) continue; - if (!s.name || !s.name[0]) continue; - if (s.name[0] == '$') continue; + if (!s.name.len) continue; + if (s.name.s[0] == '$') continue; found = s.name; if (s.kind == CFREE_SK_FUNC) break; } @@ -239,7 +243,7 @@ CfreeStatus cfree_disasm_obj(const CfreeContext* ctx, const CfreeObjFile* f, size_t n = 0; CfreeDisasmIter* it = NULL; CfreeStatus st; - const char* head; + Slice head; if (cfree_obj_section(f, i, &s) != CFREE_OK) continue; if (s.kind != CFREE_SEC_TEXT) continue; @@ -247,7 +251,7 @@ CfreeStatus cfree_disasm_obj(const CfreeContext* ctx, const CfreeObjFile* f, if (!data || !n) continue; w_str(out, "Disassembly of section "); - w_str(out, s.name ? s.name : ".text"); + w_slice(out, s.name.len ? s.name : SLICE_LIT(".text")); w_str(out, ":\n\n"); st = cfree_disasm_iter_new(&dctx, data, n, 0, f, &it); @@ -257,10 +261,10 @@ CfreeStatus cfree_disasm_obj(const CfreeContext* ctx, const CfreeObjFile* f, CfreeIterResult r = cfree_disasm_iter_next(it, &ins); if (r != CFREE_ITER_ITEM) break; head = dasm_sym_at(f, i, ins.vaddr); - if (head) { + if (head.len) { w_hex(out, ins.vaddr, 16); w_str(out, " <"); - w_str(out, head); + w_slice(out, head); w_str(out, ">:\n"); } w_hex_padded(out, ins.vaddr, 8); @@ -278,14 +282,14 @@ CfreeStatus cfree_disasm_obj(const CfreeContext* ctx, const CfreeObjFile* f, } w_str(out, " \t"); } - w_str(out, ins.mnemonic ? ins.mnemonic : ""); - if (ins.operands && ins.operands[0]) { + w_slice(out, ins.mnemonic); + if (ins.operands.len) { w_str(out, "\t"); - w_str(out, ins.operands); + w_slice(out, ins.operands); } - if (ins.annotation && ins.annotation[0]) { + if (ins.annotation.len) { w_str(out, " ; "); - w_str(out, ins.annotation); + w_slice(out, ins.annotation); } w_str(out, "\n"); } @@ -295,11 +299,11 @@ CfreeStatus cfree_disasm_obj(const CfreeContext* ctx, const CfreeObjFile* f, } CfreeStatus cfree_disasm_obj_bytes(const CfreeContext* ctx, - const CfreeBytes* bytes, CfreeWriter* out) { + const CfreeSlice* bytes, CfreeWriter* out) { CfreeObjFile* f = NULL; CfreeStatus st; if (!ctx || !bytes || !out) return CFREE_INVALID; - st = cfree_obj_open(ctx, bytes, &f); + st = cfree_obj_open(ctx, SLICE_NULL, bytes, &f); if (st != CFREE_OK) return st; st = cfree_disasm_obj(ctx, f, out); cfree_obj_free(f); diff --git a/src/api/link.c b/src/api/link.c @@ -129,7 +129,7 @@ CfreeStatus cfree_link_session_new(CfreeCompiler* c, link_set_jit_host(l, opts->jit_host); link_set_jit_mode(l, 1); link_set_gc_sections(l, opts->gc_sections); - if (!opts->entry) link_clear_entry(l); + if (!opts->entry.s || opts->entry.len == 0) link_clear_entry(l); if (opts->extern_resolver) { link_set_extern_resolver(l, opts->extern_resolver, opts->extern_resolver_user); @@ -137,11 +137,12 @@ CfreeStatus cfree_link_session_new(CfreeCompiler* c, break; } if (opts->linker_script) link_set_script(l, opts->linker_script); - if (opts->entry) { + if (opts->entry.s && opts->entry.len) { link_set_entry(l, opts->entry); } else if (opts->pe_subsystem == CFREE_PE_SUBSYSTEM_WINDOWS_GUI && - !(opts->linker_script && opts->linker_script->entry)) { - link_set_entry(l, "WinMainCRTStartup"); + !(opts->linker_script && opts->linker_script->entry.s && + opts->linker_script->entry.len)) { + link_set_entry(l, CFREE_SLICE_LIT("WinMainCRTStartup")); } (void)opts->build_id_mode; (void)opts->build_id_bytes; @@ -171,19 +172,22 @@ CfreeStatus cfree_link_session_add_obj(CfreeLinkSession* s, } typedef struct LinkAddBytesArg { - const CfreeBytes* bytes; + CfreeSlice name; + const CfreeSlice* bytes; const CfreeLinkArchiveInput* archive; } LinkAddBytesArg; static void link_session_add_obj_bytes_inner(CfreeLinkSession* s, void* arg) { - const CfreeBytes* b = ((LinkAddBytesArg*)arg)->bytes; - link_add_obj_bytes(s->linker, b->name, b->data, b->len); + LinkAddBytesArg* a = (LinkAddBytesArg*)arg; + link_add_obj_bytes(s->linker, a->name.s, a->bytes->data, a->bytes->len); } CfreeStatus cfree_link_session_add_obj_bytes(CfreeLinkSession* s, - const CfreeBytes* bytes) { + CfreeSlice name, + const CfreeSlice* bytes) { LinkAddBytesArg arg; if (!s || !bytes || s->resolved) return CFREE_INVALID; + arg.name = name; arg.bytes = bytes; arg.archive = NULL; s->non_obj_inputs++; @@ -193,7 +197,7 @@ CfreeStatus cfree_link_session_add_obj_bytes(CfreeLinkSession* s, static void link_session_add_archive_bytes_inner(CfreeLinkSession* s, void* arg) { const CfreeLinkArchiveInput* a = ((LinkAddBytesArg*)arg)->archive; - link_add_archive_bytes(s->linker, a->bytes.name, a->bytes.data, a->bytes.len, + link_add_archive_bytes(s->linker, a->name.s, a->bytes.data, a->bytes.len, a->whole_archive, a->link_mode, a->group_id); } @@ -208,14 +212,16 @@ CfreeStatus cfree_link_session_add_archive_bytes( } static void link_session_add_dso_bytes_inner(CfreeLinkSession* s, void* arg) { - const CfreeBytes* b = ((LinkAddBytesArg*)arg)->bytes; - link_add_dso_bytes(s->linker, b->name, b->data, b->len); + LinkAddBytesArg* a = (LinkAddBytesArg*)arg; + link_add_dso_bytes(s->linker, a->name.s, a->bytes->data, a->bytes->len); } CfreeStatus cfree_link_session_add_dso_bytes(CfreeLinkSession* s, - const CfreeBytes* bytes) { + CfreeSlice name, + const CfreeSlice* bytes) { LinkAddBytesArg arg; if (!s || !bytes || s->resolved) return CFREE_INVALID; + arg.name = name; arg.bytes = bytes; arg.archive = NULL; s->non_obj_inputs++; diff --git a/src/api/object_file.c b/src/api/object_file.c @@ -9,6 +9,7 @@ #include "core/core.h" #include "core/heap.h" #include "core/pool.h" +#include "core/slice.h" #include "obj/obj.h" struct CfreeObjFile { @@ -37,8 +38,8 @@ static ObjBuilder* obj_read_bytes(Compiler* c, const char* name, const u8* data, return NULL; } -CfreeStatus cfree_obj_open(const CfreeContext* ctx, const CfreeBytes* input, - CfreeObjFile** out) { +CfreeStatus cfree_obj_open(const CfreeContext* ctx, CfreeSlice name, + const CfreeSlice* input, CfreeObjFile** out) { Heap* h; CfreeObjFile* f; CfreeTarget target; @@ -67,7 +68,7 @@ CfreeStatus cfree_obj_open(const CfreeContext* ctx, const CfreeBytes* input, h->free(h, f, sizeof(*f)); return CFREE_MALFORMED; } - f->ob = obj_read_bytes(&f->compiler, input->name, input->data, input->len, + f->ob = obj_read_bytes(&f->compiler, name.s, input->data, input->len, target.obj); if (!f->ob) { compiler_fini(&f->compiler); @@ -112,7 +113,8 @@ CfreeStatus cfree_obj_section(const CfreeObjFile* f, CfreeObjSection idx, if (idx >= obj_section_count(f->ob)) return CFREE_NOT_FOUND; sec = obj_section_get(f->ob, (ObjSecId)(idx + 1)); if (!sec) return CFREE_NOT_FOUND; - out->name = sec->name ? pool_str(f->compiler.global, sec->name, NULL) : ""; + out->name = sec->name ? pool_slice(f->compiler.global, sec->name) + : SLICE_LIT(""); out->kind = (CfreeSecKind)sec->kind; out->flags = (uint32_t)sec->flags; out->size = sec->bss_size ? sec->bss_size : sec->bytes.total; @@ -193,17 +195,15 @@ CfreeStatus cfree_obj_section_format_flags(const CfreeObjFile* f, return CFREE_OK; } -CfreeStatus cfree_obj_section_by_name(const CfreeObjFile* f, const char* name, +CfreeStatus cfree_obj_section_by_name(const CfreeObjFile* f, CfreeSlice name, CfreeObjSection* out) { u32 n, i; - if (!f || !name || !out) return CFREE_INVALID; + if (!f || !out) return CFREE_INVALID; n = obj_section_count(f->ob); for (i = 0; i < n; ++i) { const Section* sec = obj_section_get(f->ob, (ObjSecId)(i + 1)); - const char* sn; if (!sec || !sec->name) continue; - sn = pool_str(f->compiler.global, sec->name, NULL); - if (sn && strcmp(sn, name) == 0) { + if (slice_eq(pool_slice(f->compiler.global, sec->name), name)) { *out = i; return CFREE_OK; } @@ -213,7 +213,8 @@ CfreeStatus cfree_obj_section_by_name(const CfreeObjFile* f, const char* name, static void fill_syminfo(const CfreeObjFile* f, ObjSymId id, const ObjSym* sym, CfreeObjSymInfo* out) { - out->name = sym->name ? pool_str(f->compiler.global, sym->name, NULL) : ""; + out->name = sym->name ? pool_slice(f->compiler.global, sym->name) + : SLICE_LIT(""); out->id = (id != OBJ_SYM_NONE) ? (CfreeObjSymbol)id : CFREE_OBJ_SYMBOL_NONE; out->bind = (CfreeSymBind)sym->bind; out->kind = (CfreeSymKind)sym->kind; @@ -224,18 +225,16 @@ static void fill_syminfo(const CfreeObjFile* f, ObjSymId id, const ObjSym* sym, out->size = sym->size; } -CfreeStatus cfree_obj_symbol_by_name(const CfreeObjFile* f, const char* name, +CfreeStatus cfree_obj_symbol_by_name(const CfreeObjFile* f, CfreeSlice name, CfreeObjSymInfo* out) { ObjSymIter* it; ObjSymEntry e; - if (!f || !name || !out) return CFREE_INVALID; + if (!f || !out) return CFREE_INVALID; it = obj_symiter_new(f->ob); if (!it) return CFREE_NOMEM; while (obj_symiter_next(it, &e)) { - const char* nm; if (!e.sym || !e.sym->name) continue; - nm = pool_str(f->compiler.global, e.sym->name, NULL); - if (nm && strcmp(nm, name) == 0) { + if (slice_eq(pool_slice(f->compiler.global, e.sym->name), name)) { fill_syminfo(f, e.id, e.sym, out); obj_symiter_free(it); return CFREE_OK; @@ -384,18 +383,24 @@ CfreeIterResult cfree_obj_reliter_next(CfreeObjRelocIter* it, out->kind.arch = it->file->target.arch; out->kind.obj_fmt = it->file->fmt; out->kind.code = (uint32_t)r->kind; - out->kind_name = cfree_obj_reloc_kind_name(it->file->target.arch, - it->file->fmt, r->kind); + { + /* Prefer the format-specific canonical spelling (e.g. "R_X86_64_PLT32"); + * fall back to the arch-neutral diagnostic spelling ("RV_CALL"). */ + const char* kn = cfree_obj_reloc_kind_name(it->file->target.arch, + it->file->fmt, r->kind); + if (!kn) kn = reloc_kind_name(r->kind); + out->kind_name = kn ? slice_from_cstr(kn) : SLICE_NULL; + } if (r->sym == OBJ_SYM_NONE) { out->sym = CFREE_OBJ_SYMBOL_NONE; - out->sym_name = ""; + out->sym_name = SLICE_LIT(""); } else { out->sym = (CfreeObjSymbol)r->sym; sym = obj_symbol_get(it->file->ob, r->sym); out->sym_name = (sym && sym->name) - ? pool_str(it->file->compiler.global, sym->name, NULL) - : ""; + ? pool_slice(it->file->compiler.global, sym->name) + : SLICE_LIT(""); } return CFREE_ITER_ITEM; } @@ -458,8 +463,8 @@ CfreeIterResult cfree_obj_groupiter_next(CfreeObjGroupIter* it, : CFREE_SECTION_NONE; } out->name = entry.group->name - ? pool_str(it->file->compiler.global, entry.group->name, NULL) - : ""; + ? pool_slice(it->file->compiler.global, entry.group->name) + : CFREE_SLICE_NULL; out->signature = (entry.group->signature != OBJ_SYM_NONE) ? (CfreeObjSymbol)entry.group->signature : CFREE_OBJ_SYMBOL_NONE; diff --git a/src/api/source.c b/src/api/source.c @@ -17,7 +17,7 @@ CfreeStatus cfree_source_add_file(CfreeCompiler* c, const char* path, return CFREE_OK; } -CfreeStatus cfree_source_add_memory(CfreeCompiler* c, const char* name, +CfreeStatus cfree_source_add_memory(CfreeCompiler* c, CfreeSlice name, uint32_t* file_id_out) { uint32_t tmp; CfreeStatus st; @@ -28,7 +28,7 @@ CfreeStatus cfree_source_add_memory(CfreeCompiler* c, const char* name, return CFREE_OK; } -CfreeStatus cfree_source_add_builtin(CfreeCompiler* c, const char* name, +CfreeStatus cfree_source_add_builtin(CfreeCompiler* c, CfreeSlice name, uint32_t* file_id_out) { uint32_t tmp; CfreeStatus st; diff --git a/src/api/stubs.c b/src/api/stubs.c @@ -1,11 +1,13 @@ /* Stub implementations for libcfree subsystems not yet implemented. */ #include "core/core.h" +#include "core/slice.h" #include "obj/obj.h" static _Noreturn void unimplemented(Compiler* c, const char* what) { SrcLoc loc = {0, 0, 0}; - compiler_panic(c, loc, "subsystem not implemented: %s", what); + compiler_panic(c, loc, "subsystem not implemented: %.*s", + SLICE_ARG(slice_from_cstr(what))); } /* WASM emit/read remain stubs until those writers/readers land. diff --git a/src/arch/aa64/alloc.c b/src/arch/aa64/alloc.c @@ -20,13 +20,12 @@ AASlot* aa64_slot_get(AAImpl* a, FrameSlot fs) { static int aa_resolve_reg_name(CGTarget* t, Sym name, Reg* out, RegClass* cls_out) { (void)t; - size_t len = 0; - const char* s = pool_str(t->c->global, name, &len); - if (!s || !len) return 1; + Slice ns = pool_slice(t->c->global, name); + if (!ns.s || !ns.len) return 1; char buf[8]; - if (len >= sizeof buf) return 1; - memcpy(buf, s, len); - buf[len] = '\0'; + if (ns.len >= sizeof buf) return 1; + memcpy(buf, ns.s, ns.len); + buf[ns.len] = '\0'; u32 dwarf; if (aa64_register_index(buf, &dwarf) != 0) return 1; if (dwarf <= 30u) { diff --git a/src/arch/aa64/arch.c b/src/arch/aa64/arch.c @@ -29,8 +29,12 @@ static const ABIVtable* aa64_abi_vtable(Compiler* c, CfreeOSKind os) { } static int aa64_register_at_public(uint32_t idx, CfreeArchReg* out) { + const char* nm = NULL; + int rc; if (!out) return 1; - return aa64_register_iter_get(idx, &out->dwarf_idx, &out->name); + rc = aa64_register_iter_get(idx, &out->dwarf_idx, &nm); + if (rc == 0) out->name = cfree_slice_cstr(nm); + return rc; } static void aa64_wr_u64_target(Compiler* c, u8* p, u64 v) { @@ -158,15 +162,15 @@ static CGTarget* aa64_backend_make(Compiler* c, ObjBuilder* o, } static const CfreePredefinedMacro aa64_predefined_macros[] = { - {"__aarch64__", "1"}, - {"__AARCH64EL__", "1"}, - {"__arm64", "1"}, - {"__arm64__", "1"}, - {"__LP64__", "1"}, - {"__ORDER_LITTLE_ENDIAN__", "1234"}, - {"__ORDER_BIG_ENDIAN__", "4321"}, - {"__BYTE_ORDER__", "__ORDER_LITTLE_ENDIAN__"}, - {"__LITTLE_ENDIAN__", "1"}, + {CFREE_SLICE_LIT("__aarch64__"), CFREE_SLICE_LIT("1")}, + {CFREE_SLICE_LIT("__AARCH64EL__"), CFREE_SLICE_LIT("1")}, + {CFREE_SLICE_LIT("__arm64"), CFREE_SLICE_LIT("1")}, + {CFREE_SLICE_LIT("__arm64__"), CFREE_SLICE_LIT("1")}, + {CFREE_SLICE_LIT("__LP64__"), CFREE_SLICE_LIT("1")}, + {CFREE_SLICE_LIT("__ORDER_LITTLE_ENDIAN__"), CFREE_SLICE_LIT("1234")}, + {CFREE_SLICE_LIT("__ORDER_BIG_ENDIAN__"), CFREE_SLICE_LIT("4321")}, + {CFREE_SLICE_LIT("__BYTE_ORDER__"), CFREE_SLICE_LIT("__ORDER_LITTLE_ENDIAN__")}, + {CFREE_SLICE_LIT("__LITTLE_ENDIAN__"), CFREE_SLICE_LIT("1")}, }; const ArchImpl arch_impl_aa64 = { diff --git a/src/arch/aa64/asm.c b/src/arch/aa64/asm.c @@ -22,6 +22,7 @@ #include "arch/arch.h" #include "core/arena.h" #include "core/pool.h" +#include "core/slice.h" #include "core/strbuf.h" #include "asm/asm_lex.h" #include "obj/obj.h" @@ -123,8 +124,9 @@ typedef struct AA64Reg { } AA64Reg; static int parse_reg_from_ident(AsmDriver* d, Sym ident, AA64Reg* out) { - size_t n = 0; - const char* p = pool_str(asm_driver_pool(d), ident, &n); + Slice sl = pool_slice(asm_driver_pool(d), ident); + const char* p = sl.s; + size_t n = sl.len; if (!p || !n) return 0; /* "sp" */ if (icase_eq(p, n, "sp")) { @@ -204,8 +206,9 @@ static int parse_reg_from_ident(AsmDriver* d, Sym ident, AA64Reg* out) { static int parse_fp_pair_reg_from_ident(AsmDriver* d, Sym ident, AA64Reg* out) { - size_t n = 0; - const char* p = pool_str(asm_driver_pool(d), ident, &n); + Slice sl = pool_slice(asm_driver_pool(d), ident); + const char* p = sl.s; + size_t n = sl.len; if (!p || n < 2 || (p[0] != 'd' && p[0] != 'D' && p[0] != 'q' && p[0] != 'Q')) return 0; @@ -246,13 +249,15 @@ static AA64Reg parse_ldstp_reg(AsmDriver* d) { } static void reject_sp_reg(AsmDriver* d, AA64Reg r, const char* what) { - if (r.is_sp) asm_driver_panic(d, "asm: %s: SP register not allowed", what); + if (r.is_sp) + asm_driver_panic(d, "asm: %.*s: SP register not allowed", + SLICE_ARG(slice_from_cstr(what))); } static void require_sp_spelling(AsmDriver* d, AA64Reg r, const char* what) { if (r.num == 31u && !r.is_sp) - asm_driver_panic(d, "asm: %s: zero register not allowed in SP operand", - what); + asm_driver_panic(d, "asm: %.*s: zero register not allowed in SP operand", + SLICE_ARG(slice_from_cstr(what))); } /* Parse "#imm" (with optional + / -) or a bare expression — GNU as is @@ -280,8 +285,9 @@ static void emit32(AsmDriver* d, u32 word) { } static int parse_cond_from_ident(AsmDriver* d, Sym ident, u32* out) { - size_t n = 0; - const char* s = pool_str(asm_driver_pool(d), ident, &n); + Slice sl = pool_slice(asm_driver_pool(d), ident); + const char* s = sl.s; + size_t n = sl.len; if (!s) return 0; if (icase_eq(s, n, "eq")) *out = 0; else if (icase_eq(s, n, "ne")) *out = 1; @@ -306,13 +312,15 @@ static u32 parse_cond(AsmDriver* d, const char* what) { AsmTok t = asm_driver_next(d); u32 cond = 0; if (t.kind != ASM_TOK_IDENT || !parse_cond_from_ident(d, t.v.ident, &cond)) - asm_driver_panic(d, "asm: %s: expected condition code", what); + asm_driver_panic(d, "asm: %.*s: expected condition code", + SLICE_ARG(slice_from_cstr(what))); return cond; } static void expect_comma(AsmDriver* d, const char* what) { if (!asm_driver_eat_comma(d)) - asm_driver_panic(d, "asm: expected ',' (%s)", what); + asm_driver_panic(d, "asm: expected ',' (%.*s)", + SLICE_ARG(slice_from_cstr(what))); } /* ---- per-mnemonic parsers ---- */ @@ -358,8 +366,9 @@ static u32 parse_barrier_option(AsmDriver* d, int allow_dmb_ld_st) { AsmTok t = asm_driver_peek(d); if (t.kind == ASM_TOK_IDENT) { (void)asm_driver_next(d); - size_t n = 0; - const char* s = pool_str(asm_driver_pool(d), t.v.ident, &n); + Slice sl = pool_slice(asm_driver_pool(d), t.v.ident); + const char* s = sl.s; + size_t n = sl.len; if (icase_eq(s, n, "sy")) return AA64_BARRIER_OPT_SY; if (icase_eq(s, n, "ish")) return AA64_BARRIER_OPT_ISH; if (icase_eq(s, n, "ishld")) return AA64_BARRIER_OPT_ISHLD; @@ -480,8 +489,9 @@ static void p_movwide(AsmDriver* d, u32 opc) { AsmTok lid = asm_driver_next(d); if (lid.kind != ASM_TOK_IDENT) asm_driver_panic(d, "asm: expected 'lsl'"); - size_t ln = 0; - const char* lp = pool_str(asm_driver_pool(d), lid.v.ident, &ln); + Slice lsl = pool_slice(asm_driver_pool(d), lid.v.ident); + const char* lp = lsl.s; + size_t ln = lsl.len; if (!lp || !icase_eq(lp, ln, "lsl")) asm_driver_panic(d, "asm: expected 'lsl'"); i64 sh = parse_imm_const(d); @@ -517,8 +527,9 @@ static void p_except(AsmDriver* d, u32 form) { static int parse_shift_mod(AsmDriver* d, u32* shift_out, u32* imm6_out) { AsmTok t = asm_driver_peek(d); if (t.kind != ASM_TOK_IDENT) return 0; - size_t n = 0; - const char* p = pool_str(asm_driver_pool(d), t.v.ident, &n); + Slice sl = pool_slice(asm_driver_pool(d), t.v.ident); + const char* p = sl.s; + size_t n = sl.len; u32 sh; if (icase_eq(p, n, "lsl")) sh = 0; else if (icase_eq(p, n, "lsr")) sh = 1; @@ -563,8 +574,9 @@ static void p_addsub(AsmDriver* d, int is_sub, int set_flags) { AsmTok lid = asm_driver_next(d); if (lid.kind != ASM_TOK_IDENT) asm_driver_panic(d, "asm: expected 'lsl #12'"); - size_t ln = 0; - const char* lp = pool_str(asm_driver_pool(d), lid.v.ident, &ln); + Slice lsl = pool_slice(asm_driver_pool(d), lid.v.ident); + const char* lp = lsl.s; + size_t ln = lsl.len; if (!lp || !icase_eq(lp, ln, "lsl")) asm_driver_panic(d, "asm: expected 'lsl'"); i64 s = parse_imm_const(d); @@ -611,11 +623,11 @@ static void p_cmp(AsmDriver* d, int is_neg /* cmn flips op */) { u32 sh = 0; if (asm_driver_eat_comma(d)) { AsmTok lid = asm_driver_next(d); - size_t ln = 0; - const char* lp = - (lid.kind == ASM_TOK_IDENT) - ? pool_str(asm_driver_pool(d), lid.v.ident, &ln) - : NULL; + Slice lsl = (lid.kind == ASM_TOK_IDENT) + ? pool_slice(asm_driver_pool(d), lid.v.ident) + : SLICE_NULL; + const char* lp = lsl.s; + size_t ln = lsl.len; if (!lp || !icase_eq(lp, ln, "lsl")) asm_driver_panic(d, "asm: cmp imm: expected 'lsl'"); i64 s = parse_imm_const(d); @@ -653,9 +665,11 @@ static void p_condsel(AsmDriver* d, u32 op, u32 op2, const char* what) { expect_comma(d, what); u32 cond = parse_cond(d, what); if (rd.is_sp || rn.is_sp || rm.is_sp) - asm_driver_panic(d, "asm: %s: SP register not allowed", what); + asm_driver_panic(d, "asm: %.*s: SP register not allowed", + SLICE_ARG(slice_from_cstr(what))); if (rd.is64 != rn.is64 || rd.is64 != rm.is64) - asm_driver_panic(d, "asm: %s: width mismatch", what); + asm_driver_panic(d, "asm: %.*s: width mismatch", + SLICE_ARG(slice_from_cstr(what))); u32 word = aa64_condsel_pack((AA64CondSel){.sf = (u32)rd.is64, .op = op, .S = 0, @@ -671,7 +685,9 @@ static void p_cset_like(AsmDriver* d, u32 op, u32 op2, const char* what) { AA64Reg rd = parse_reg(d); expect_comma(d, what); u32 cond = parse_cond(d, what); - if (rd.is_sp) asm_driver_panic(d, "asm: %s: SP register not allowed", what); + if (rd.is_sp) + asm_driver_panic(d, "asm: %.*s: SP register not allowed", + SLICE_ARG(slice_from_cstr(what))); u32 word = aa64_condsel_pack((AA64CondSel){.sf = (u32)rd.is64, .op = op, .S = 0, @@ -1119,8 +1135,9 @@ static const AA64Mn kTable[] = { void aa64_asm_insn(AA64Asm* a, AsmDriver* d, Sym mnemonic) { (void)a; - size_t mn = 0; - const char* mp = pool_str(asm_driver_pool(d), mnemonic, &mn); + Slice msl = pool_slice(asm_driver_pool(d), mnemonic); + const char* mp = msl.s; + size_t mn = msl.len; for (const AA64Mn* row = kTable; row->name; ++row) { if (icase_eq(mp, mn, row->name)) { row->fn(d); @@ -1173,7 +1190,7 @@ static void render_indirect(StrBuf* sb, Reg base, i32 ofs) { _Noreturn static void inline_panic(AA64Asm* a, const char* msg) { SrcLoc loc = {0, 0, 0}; - compiler_panic(a->c, loc, "inline asm: %s", msg); + compiler_panic(a->c, loc, "inline asm: %.*s", SLICE_ARG(slice_from_cstr(msg))); } /* Resolve operand index N → (kind=0 forced default, 1=force-w, 2=force-x, @@ -1265,16 +1282,19 @@ static void run_one_line(AA64Asm* a, MCEmitter* mc, const char* text, AsmTok rest = asm_driver_next(d); if (rest.kind != ASM_TOK_IDENT) inline_panic(a, "composite mnemonic: expected ident after '.'"); - size_t hn = 0, rn = 0; - const char* hp = pool_str(asm_driver_pool(d), mn, &hn); - const char* rp = pool_str(asm_driver_pool(d), rest.v.ident, &rn); + Slice hsl = pool_slice(asm_driver_pool(d), mn); + Slice rsl = pool_slice(asm_driver_pool(d), rest.v.ident); + size_t hn = hsl.len, rn = rsl.len; + const char* hp = hsl.s; + const char* rp = rsl.s; char buf[64]; if (hn + 1 + rn >= sizeof buf) inline_panic(a, "composite mnemonic too long"); for (size_t k = 0; k < hn; ++k) buf[k] = hp[k]; buf[hn] = '.'; for (size_t k = 0; k < rn; ++k) buf[hn + 1 + k] = rp[k]; - mn = pool_intern(asm_driver_pool(d), buf, hn + 1 + rn); + mn = pool_intern_slice(asm_driver_pool(d), + (Slice){.s = buf, .len = hn + 1 + rn}); } aa64_asm_insn(a, d, mn); asm_driver_close_inline(d); @@ -1312,7 +1332,8 @@ static void render_and_run_line(AA64Asm* a, MCEmitter* mc, StrBuf* sb, while (nend < end && *nend != ']') ++nend; if (nend == end) inline_panic(a, "unterminated %[name]"); size_t nlen = (size_t)(nend - nbeg); - Sym needle = pool_intern(a->c->global, nbeg, nlen); + Sym needle = pool_intern_slice(a->c->global, + (Slice){.s = nbeg, .len = nlen}); u32 idx = (u32)-1; for (u32 k = 0; k < a->nout; ++k) { if (a->outs[k].name == needle) { idx = k; break; } @@ -1344,7 +1365,8 @@ static void render_and_run_line(AA64Asm* a, MCEmitter* mc, StrBuf* sb, while (nend < end && *nend != ']') ++nend; if (nend == end) inline_panic(a, "unterminated %[name]"); size_t nlen = (size_t)(nend - nbeg); - Sym needle = pool_intern(a->c->global, nbeg, nlen); + Sym needle = pool_intern_slice(a->c->global, + (Slice){.s = nbeg, .len = nlen}); u32 idx = (u32)-1; for (u32 k = 0; k < a->nout; ++k) { if (a->outs[k].name == needle) { idx = k; break; } diff --git a/src/arch/aa64/disasm.c b/src/arch/aa64/disasm.c @@ -51,7 +51,7 @@ static void aa64_write_mnemonic(AA64Disasm* d, const AA64InsnDesc* desc, strbuf_puts(&d->mnem, aa64_cond_names[cond]); return; } - strbuf_puts(&d->mnem, desc->mnemonic); + strbuf_put_slice(&d->mnem, desc->mnemonic); } static void aa64_write_operands(AA64Disasm* d, const AA64InsnDesc* desc, @@ -106,9 +106,9 @@ static u32 aa64_decode(ArchDisasm* base, const u8* bytes, size_t len, u64 vaddr, out->vaddr = vaddr; out->bytes = bytes; out->nbytes = 4; - out->mnemonic = strbuf_cstr(&d->mnem); - out->operands = strbuf_cstr(&d->ops); - out->annotation = strbuf_cstr(&d->ann); + out->mnemonic = strbuf_slice(&d->mnem); + out->operands = strbuf_slice(&d->ops); + out->annotation = strbuf_slice(&d->ann); return 4; } diff --git a/src/arch/aa64/isa.c b/src/arch/aa64/isa.c @@ -22,203 +22,208 @@ #include <stddef.h> +/* Mnemonic Slice literal for a static table row (compile-time length). */ +#define MN(s) {{(s)}, sizeof(s) - 1} + const AA64InsnDesc aa64_insn_table[] = { /* ----- Move-wide immediate (MOVN / MOVZ / MOVK) ----- */ - {"movn", 0x12800000u, 0x7F800000u, AA64_FMT_MOVEWIDE, 0, {0, 0}}, - {"movz", 0x52800000u, 0x7F800000u, AA64_FMT_MOVEWIDE, 0, {0, 0}}, - {"movk", 0x72800000u, 0x7F800000u, AA64_FMT_MOVEWIDE, 0, {0, 0}}, + {MN("movn"), 0x12800000u, 0x7F800000u, AA64_FMT_MOVEWIDE, 0, {0, 0}}, + {MN("movz"), 0x52800000u, 0x7F800000u, AA64_FMT_MOVEWIDE, 0, {0, 0}}, + {MN("movk"), 0x72800000u, 0x7F800000u, AA64_FMT_MOVEWIDE, 0, {0, 0}}, /* ----- Logical, shifted register ----- * Alias MOV Rd, Rm is ORR Rd, ZR, Rm with shift=0, imm6=0. The mask * pins Rn (bits 9:5) to 11111 (ZR) and shift/imm6 to 0 so only the * MOV spelling matches; broader ORR rows below catch the rest. */ - {"mov", 0x2A0003E0u, 0x7FE0FFE0u, AA64_FMT_LOG_SR, AA64_ASMFL_ALIAS, + {MN("mov"), 0x2A0003E0u, 0x7FE0FFE0u, AA64_FMT_LOG_SR, AA64_ASMFL_ALIAS, {0, 0}}, /* MVN Rd, Rm ≡ ORN Rd, ZR, Rm (logical N=1, Rn=ZR, no shift) */ - {"mvn", 0x2A2003E0u, 0x7FE0FFE0u, AA64_FMT_LOG_SR, AA64_ASMFL_ALIAS, + {MN("mvn"), 0x2A2003E0u, 0x7FE0FFE0u, AA64_FMT_LOG_SR, AA64_ASMFL_ALIAS, {0, 0}}, - {"and", 0x0A000000u, 0x7F200000u, AA64_FMT_LOG_SR, 0, {0, 0}}, - {"bic", 0x0A200000u, 0x7F200000u, AA64_FMT_LOG_SR, 0, {0, 0}}, - {"orr", 0x2A000000u, 0x7F200000u, AA64_FMT_LOG_SR, 0, {0, 0}}, - {"orn", 0x2A200000u, 0x7F200000u, AA64_FMT_LOG_SR, 0, {0, 0}}, - {"eor", 0x4A000000u, 0x7F200000u, AA64_FMT_LOG_SR, 0, {0, 0}}, - {"eon", 0x4A200000u, 0x7F200000u, AA64_FMT_LOG_SR, 0, {0, 0}}, - {"ands", 0x6A000000u, 0x7F200000u, AA64_FMT_LOG_SR, 0, {0, 0}}, - {"bics", 0x6A200000u, 0x7F200000u, AA64_FMT_LOG_SR, 0, {0, 0}}, + {MN("and"), 0x0A000000u, 0x7F200000u, AA64_FMT_LOG_SR, 0, {0, 0}}, + {MN("bic"), 0x0A200000u, 0x7F200000u, AA64_FMT_LOG_SR, 0, {0, 0}}, + {MN("orr"), 0x2A000000u, 0x7F200000u, AA64_FMT_LOG_SR, 0, {0, 0}}, + {MN("orn"), 0x2A200000u, 0x7F200000u, AA64_FMT_LOG_SR, 0, {0, 0}}, + {MN("eor"), 0x4A000000u, 0x7F200000u, AA64_FMT_LOG_SR, 0, {0, 0}}, + {MN("eon"), 0x4A200000u, 0x7F200000u, AA64_FMT_LOG_SR, 0, {0, 0}}, + {MN("ands"), 0x6A000000u, 0x7F200000u, AA64_FMT_LOG_SR, 0, {0, 0}}, + {MN("bics"), 0x6A200000u, 0x7F200000u, AA64_FMT_LOG_SR, 0, {0, 0}}, /* ----- Add/Sub, shifted register ----- * NEG Rd, Rm ≡ SUB Rd, ZR, Rm (Rn=ZR, shift=0, imm6=0). */ - {"neg", 0x4B0003E0u, 0x7FE0FFE0u, AA64_FMT_ADDSUB_SR, AA64_ASMFL_ALIAS, + {MN("neg"), 0x4B0003E0u, 0x7FE0FFE0u, AA64_FMT_ADDSUB_SR, AA64_ASMFL_ALIAS, {0, 0}}, - {"negs", 0x6B0003E0u, 0x7FE0FFE0u, AA64_FMT_ADDSUB_SR, AA64_ASMFL_ALIAS, + {MN("negs"), 0x6B0003E0u, 0x7FE0FFE0u, AA64_FMT_ADDSUB_SR, AA64_ASMFL_ALIAS, {0, 0}}, /* CMP Rn, Rm ≡ SUBS ZR, Rn, Rm. */ - {"cmp", 0x6B00001Fu, 0x7F20001Fu, AA64_FMT_ADDSUB_SR, AA64_ASMFL_ALIAS, + {MN("cmp"), 0x6B00001Fu, 0x7F20001Fu, AA64_FMT_ADDSUB_SR, AA64_ASMFL_ALIAS, {0, 0}}, /* CMN Rn, Rm ≡ ADDS ZR, Rn, Rm. */ - {"cmn", 0x2B00001Fu, 0x7F20001Fu, AA64_FMT_ADDSUB_SR, AA64_ASMFL_ALIAS, + {MN("cmn"), 0x2B00001Fu, 0x7F20001Fu, AA64_FMT_ADDSUB_SR, AA64_ASMFL_ALIAS, {0, 0}}, - {"add", 0x0B000000u, 0x7F200000u, AA64_FMT_ADDSUB_SR, 0, {0, 0}}, - {"adds", 0x2B000000u, 0x7F200000u, AA64_FMT_ADDSUB_SR, 0, {0, 0}}, - {"sub", 0x4B000000u, 0x7F200000u, AA64_FMT_ADDSUB_SR, 0, {0, 0}}, - {"subs", 0x6B000000u, 0x7F200000u, AA64_FMT_ADDSUB_SR, 0, {0, 0}}, + {MN("add"), 0x0B000000u, 0x7F200000u, AA64_FMT_ADDSUB_SR, 0, {0, 0}}, + {MN("adds"), 0x2B000000u, 0x7F200000u, AA64_FMT_ADDSUB_SR, 0, {0, 0}}, + {MN("sub"), 0x4B000000u, 0x7F200000u, AA64_FMT_ADDSUB_SR, 0, {0, 0}}, + {MN("subs"), 0x6B000000u, 0x7F200000u, AA64_FMT_ADDSUB_SR, 0, {0, 0}}, /* ----- Data-processing 3-source ----- * MUL Rd, Rn, Rm ≡ MADD Rd, Rn, Rm, ZR (Ra=ZR, op31=0, o0=0). */ - {"mul", 0x1B007C00u, 0x7FE0FC00u, AA64_FMT_DP3, AA64_ASMFL_ALIAS, {0, 0}}, + {MN("mul"), 0x1B007C00u, 0x7FE0FC00u, AA64_FMT_DP3, AA64_ASMFL_ALIAS, {0, 0}}, /* MNEG Rd, Rn, Rm ≡ MSUB Rd, Rn, Rm, ZR. */ - {"mneg", 0x1B00FC00u, 0x7FE0FC00u, AA64_FMT_DP3, AA64_ASMFL_ALIAS, {0, 0}}, - {"madd", 0x1B000000u, 0x7FE08000u, AA64_FMT_DP3, 0, {0, 0}}, - {"msub", 0x1B008000u, 0x7FE08000u, AA64_FMT_DP3, 0, {0, 0}}, + {MN("mneg"), 0x1B00FC00u, 0x7FE0FC00u, AA64_FMT_DP3, AA64_ASMFL_ALIAS, {0, 0}}, + {MN("madd"), 0x1B000000u, 0x7FE08000u, AA64_FMT_DP3, 0, {0, 0}}, + {MN("msub"), 0x1B008000u, 0x7FE08000u, AA64_FMT_DP3, 0, {0, 0}}, /* ----- Data-processing 2-source ----- */ - {"udiv", 0x1AC00800u, 0x5FE0FC00u, AA64_FMT_DP2, 0, {0, 0}}, - {"sdiv", 0x1AC00C00u, 0x5FE0FC00u, AA64_FMT_DP2, 0, {0, 0}}, - {"lslv", 0x1AC02000u, 0x5FE0FC00u, AA64_FMT_DP2, 0, {0, 0}}, - {"lsrv", 0x1AC02400u, 0x5FE0FC00u, AA64_FMT_DP2, 0, {0, 0}}, - {"asrv", 0x1AC02800u, 0x5FE0FC00u, AA64_FMT_DP2, 0, {0, 0}}, - {"rorv", 0x1AC02C00u, 0x5FE0FC00u, AA64_FMT_DP2, 0, {0, 0}}, + {MN("udiv"), 0x1AC00800u, 0x5FE0FC00u, AA64_FMT_DP2, 0, {0, 0}}, + {MN("sdiv"), 0x1AC00C00u, 0x5FE0FC00u, AA64_FMT_DP2, 0, {0, 0}}, + {MN("lslv"), 0x1AC02000u, 0x5FE0FC00u, AA64_FMT_DP2, 0, {0, 0}}, + {MN("lsrv"), 0x1AC02400u, 0x5FE0FC00u, AA64_FMT_DP2, 0, {0, 0}}, + {MN("asrv"), 0x1AC02800u, 0x5FE0FC00u, AA64_FMT_DP2, 0, {0, 0}}, + {MN("rorv"), 0x1AC02C00u, 0x5FE0FC00u, AA64_FMT_DP2, 0, {0, 0}}, /* ----- Conditional select ----- * CSET Rd, cond ≡ CSINC Rd, ZR, ZR, invert(cond). * CSETM Rd, cond ≡ CSINV Rd, ZR, ZR, invert(cond). * These aliases are expressible as fixed Rn/Rm=ZR masks, so put them * before the canonical conditional-select rows. */ - {"cset", 0x1A9F07E0u, 0x7FE00C00u | (0x1Fu << 16) | (0x1Fu << 5), + {MN("cset"), 0x1A9F07E0u, 0x7FE00C00u | (0x1Fu << 16) | (0x1Fu << 5), AA64_FMT_CONDSEL, AA64_ASMFL_ALIAS, {0, 0}}, - {"csetm", 0x5A9F03E0u, 0x7FE00C00u | (0x1Fu << 16) | (0x1Fu << 5), + {MN("csetm"), 0x5A9F03E0u, 0x7FE00C00u | (0x1Fu << 16) | (0x1Fu << 5), AA64_FMT_CONDSEL, AA64_ASMFL_ALIAS, {0, 0}}, - {"csel", 0x1A800000u, 0x7FE00C00u, AA64_FMT_CONDSEL, 0, {0, 0}}, - {"csinc", 0x1A800400u, 0x7FE00C00u, AA64_FMT_CONDSEL, 0, {0, 0}}, - {"csinv", 0x5A800000u, 0x7FE00C00u, AA64_FMT_CONDSEL, 0, {0, 0}}, - {"csneg", 0x5A800400u, 0x7FE00C00u, AA64_FMT_CONDSEL, 0, {0, 0}}, + {MN("csel"), 0x1A800000u, 0x7FE00C00u, AA64_FMT_CONDSEL, 0, {0, 0}}, + {MN("csinc"), 0x1A800400u, 0x7FE00C00u, AA64_FMT_CONDSEL, 0, {0, 0}}, + {MN("csinv"), 0x5A800000u, 0x7FE00C00u, AA64_FMT_CONDSEL, 0, {0, 0}}, + {MN("csneg"), 0x5A800400u, 0x7FE00C00u, AA64_FMT_CONDSEL, 0, {0, 0}}, /* ----- Unconditional branch (register) ----- * RET aliases its no-operand spelling to RET X30 (Rn=11110). The * tighter row matches when Rn=30 and prints "ret" without operands; * the looser row below catches RET Xn for other Rn. */ - {"ret", 0xD65F03C0u, 0xFFFFFFFFu, AA64_FMT_BR_REG, + {MN("ret"), 0xD65F03C0u, 0xFFFFFFFFu, AA64_FMT_BR_REG, AA64_ASMFL_ALIAS | AA64_ASMFL_NORN, {0, 0}}, - {"br", 0xD61F0000u, 0xFFFFFC1Fu, AA64_FMT_BR_REG, 0, {0, 0}}, - {"blr", 0xD63F0000u, 0xFFFFFC1Fu, AA64_FMT_BR_REG, 0, {0, 0}}, - {"ret", 0xD65F0000u, 0xFFFFFC1Fu, AA64_FMT_BR_REG, 0, {0, 0}}, + {MN("br"), 0xD61F0000u, 0xFFFFFC1Fu, AA64_FMT_BR_REG, 0, {0, 0}}, + {MN("blr"), 0xD63F0000u, 0xFFFFFC1Fu, AA64_FMT_BR_REG, 0, {0, 0}}, + {MN("ret"), 0xD65F0000u, 0xFFFFFC1Fu, AA64_FMT_BR_REG, 0, {0, 0}}, /* ----- PC-relative addressing ----- */ - {"adr", 0x10000000u, 0x9F000000u, AA64_FMT_PCREL_ADR, 0, {0, 0}}, - {"adrp", 0x90000000u, 0x9F000000u, AA64_FMT_PCREL_ADR, 0, {0, 0}}, + {MN("adr"), 0x10000000u, 0x9F000000u, AA64_FMT_PCREL_ADR, 0, {0, 0}}, + {MN("adrp"), 0x90000000u, 0x9F000000u, AA64_FMT_PCREL_ADR, 0, {0, 0}}, /* ----- Add/Sub immediate ----- * CMP/CMN immediate are the Rd=ZR aliases of SUBS/ADDS immediate. */ - {"cmn", 0x3100001Fu, 0x7F00001Fu, AA64_FMT_ADDSUB_IMM, AA64_ASMFL_ALIAS, + {MN("cmn"), 0x3100001Fu, 0x7F00001Fu, AA64_FMT_ADDSUB_IMM, AA64_ASMFL_ALIAS, {0, 0}}, - {"cmp", 0x7100001Fu, 0x7F00001Fu, AA64_FMT_ADDSUB_IMM, AA64_ASMFL_ALIAS, + {MN("cmp"), 0x7100001Fu, 0x7F00001Fu, AA64_FMT_ADDSUB_IMM, AA64_ASMFL_ALIAS, {0, 0}}, - {"add", 0x11000000u, 0x7F000000u, AA64_FMT_ADDSUB_IMM, 0, {0, 0}}, - {"adds", 0x31000000u, 0x7F000000u, AA64_FMT_ADDSUB_IMM, 0, {0, 0}}, - {"sub", 0x51000000u, 0x7F000000u, AA64_FMT_ADDSUB_IMM, 0, {0, 0}}, - {"subs", 0x71000000u, 0x7F000000u, AA64_FMT_ADDSUB_IMM, 0, {0, 0}}, + {MN("add"), 0x11000000u, 0x7F000000u, AA64_FMT_ADDSUB_IMM, 0, {0, 0}}, + {MN("adds"), 0x31000000u, 0x7F000000u, AA64_FMT_ADDSUB_IMM, 0, {0, 0}}, + {MN("sub"), 0x51000000u, 0x7F000000u, AA64_FMT_ADDSUB_IMM, 0, {0, 0}}, + {MN("subs"), 0x71000000u, 0x7F000000u, AA64_FMT_ADDSUB_IMM, 0, {0, 0}}, /* ----- Load/store, unsigned 12-bit immediate (scaled) ----- * Mask: family bits 29:27 + 25:24 + size(31:30) + V(26) + opc(23:22). */ - {"strb", 0x39000000u, 0xFFC00000u, AA64_FMT_LDST_UIMM, 0, {0, 0}}, - {"ldrb", 0x39400000u, 0xFFC00000u, AA64_FMT_LDST_UIMM, 0, {0, 0}}, - {"strh", 0x79000000u, 0xFFC00000u, AA64_FMT_LDST_UIMM, 0, {0, 0}}, - {"ldrh", 0x79400000u, 0xFFC00000u, AA64_FMT_LDST_UIMM, 0, {0, 0}}, - {"str", 0xB9000000u, 0xFFC00000u, AA64_FMT_LDST_UIMM, 0, {0, 0}}, /* 32 */ - {"ldr", 0xB9400000u, 0xFFC00000u, AA64_FMT_LDST_UIMM, 0, {0, 0}}, - {"str", 0xF9000000u, 0xFFC00000u, AA64_FMT_LDST_UIMM, AA64_ASMFL_SF1, + {MN("strb"), 0x39000000u, 0xFFC00000u, AA64_FMT_LDST_UIMM, 0, {0, 0}}, + {MN("ldrb"), 0x39400000u, 0xFFC00000u, AA64_FMT_LDST_UIMM, 0, {0, 0}}, + {MN("strh"), 0x79000000u, 0xFFC00000u, AA64_FMT_LDST_UIMM, 0, {0, 0}}, + {MN("ldrh"), 0x79400000u, 0xFFC00000u, AA64_FMT_LDST_UIMM, 0, {0, 0}}, + {MN("str"), 0xB9000000u, 0xFFC00000u, AA64_FMT_LDST_UIMM, 0, {0, 0}}, /* 32 */ + {MN("ldr"), 0xB9400000u, 0xFFC00000u, AA64_FMT_LDST_UIMM, 0, {0, 0}}, + {MN("str"), 0xF9000000u, 0xFFC00000u, AA64_FMT_LDST_UIMM, AA64_ASMFL_SF1, {0, 0}}, /* 64 */ - {"ldr", 0xF9400000u, 0xFFC00000u, AA64_FMT_LDST_UIMM, AA64_ASMFL_SF1, + {MN("ldr"), 0xF9400000u, 0xFFC00000u, AA64_FMT_LDST_UIMM, AA64_ASMFL_SF1, {0, 0}}, /* SIMD/FP scaled loads/stores (V=1). size 0..2 select B/H/S; size=3 * selects D; the 128-bit Q form uses size=00 with opc bit 1 set and * is not yet emitted by codegen. */ - {"str", 0x3D000000u, 0xFFC00000u, AA64_FMT_LDST_UIMM, 0, {0, 0}}, /* B */ - {"ldr", 0x3D400000u, 0xFFC00000u, AA64_FMT_LDST_UIMM, 0, {0, 0}}, - {"str", 0x7D000000u, 0xFFC00000u, AA64_FMT_LDST_UIMM, 0, {0, 0}}, /* H */ - {"ldr", 0x7D400000u, 0xFFC00000u, AA64_FMT_LDST_UIMM, 0, {0, 0}}, - {"str", 0xBD000000u, 0xFFC00000u, AA64_FMT_LDST_UIMM, 0, {0, 0}}, /* S */ - {"ldr", 0xBD400000u, 0xFFC00000u, AA64_FMT_LDST_UIMM, 0, {0, 0}}, - {"str", 0xFD000000u, 0xFFC00000u, AA64_FMT_LDST_UIMM, AA64_ASMFL_SF1, + {MN("str"), 0x3D000000u, 0xFFC00000u, AA64_FMT_LDST_UIMM, 0, {0, 0}}, /* B */ + {MN("ldr"), 0x3D400000u, 0xFFC00000u, AA64_FMT_LDST_UIMM, 0, {0, 0}}, + {MN("str"), 0x7D000000u, 0xFFC00000u, AA64_FMT_LDST_UIMM, 0, {0, 0}}, /* H */ + {MN("ldr"), 0x7D400000u, 0xFFC00000u, AA64_FMT_LDST_UIMM, 0, {0, 0}}, + {MN("str"), 0xBD000000u, 0xFFC00000u, AA64_FMT_LDST_UIMM, 0, {0, 0}}, /* S */ + {MN("ldr"), 0xBD400000u, 0xFFC00000u, AA64_FMT_LDST_UIMM, 0, {0, 0}}, + {MN("str"), 0xFD000000u, 0xFFC00000u, AA64_FMT_LDST_UIMM, AA64_ASMFL_SF1, {0, 0}}, /* D */ - {"ldr", 0xFD400000u, 0xFFC00000u, AA64_FMT_LDST_UIMM, AA64_ASMFL_SF1, + {MN("ldr"), 0xFD400000u, 0xFFC00000u, AA64_FMT_LDST_UIMM, AA64_ASMFL_SF1, {0, 0}}, /* ----- Load/store, unscaled signed 9-bit immediate (LDUR/STUR) ----- * V=0 first, V=1 next. Per-row mask narrows size+V+opc; family mask * pins the high family bits + the SIMM9-vs-other-variant selector. */ - {"sturb", 0x38000000u, 0xFFE00C00u, AA64_FMT_LDST_SIMM9, 0, {0, 0}}, - {"ldurb", 0x38400000u, 0xFFE00C00u, AA64_FMT_LDST_SIMM9, 0, {0, 0}}, - {"sturh", 0x78000000u, 0xFFE00C00u, AA64_FMT_LDST_SIMM9, 0, {0, 0}}, - {"ldurh", 0x78400000u, 0xFFE00C00u, AA64_FMT_LDST_SIMM9, 0, {0, 0}}, - {"stur", 0xB8000000u, 0xFFE00C00u, AA64_FMT_LDST_SIMM9, 0, {0, 0}}, /* 32 */ - {"ldur", 0xB8400000u, 0xFFE00C00u, AA64_FMT_LDST_SIMM9, 0, {0, 0}}, - {"stur", 0xF8000000u, 0xFFE00C00u, AA64_FMT_LDST_SIMM9, AA64_ASMFL_SF1, + {MN("sturb"), 0x38000000u, 0xFFE00C00u, AA64_FMT_LDST_SIMM9, 0, {0, 0}}, + {MN("ldurb"), 0x38400000u, 0xFFE00C00u, AA64_FMT_LDST_SIMM9, 0, {0, 0}}, + {MN("sturh"), 0x78000000u, 0xFFE00C00u, AA64_FMT_LDST_SIMM9, 0, {0, 0}}, + {MN("ldurh"), 0x78400000u, 0xFFE00C00u, AA64_FMT_LDST_SIMM9, 0, {0, 0}}, + {MN("stur"), 0xB8000000u, 0xFFE00C00u, AA64_FMT_LDST_SIMM9, 0, {0, 0}}, /* 32 */ + {MN("ldur"), 0xB8400000u, 0xFFE00C00u, AA64_FMT_LDST_SIMM9, 0, {0, 0}}, + {MN("stur"), 0xF8000000u, 0xFFE00C00u, AA64_FMT_LDST_SIMM9, AA64_ASMFL_SF1, {0, 0}}, - {"ldur", 0xF8400000u, 0xFFE00C00u, AA64_FMT_LDST_SIMM9, AA64_ASMFL_SF1, + {MN("ldur"), 0xF8400000u, 0xFFE00C00u, AA64_FMT_LDST_SIMM9, AA64_ASMFL_SF1, {0, 0}}, - {"stur", 0x3C000000u, 0xFFE00C00u, AA64_FMT_LDST_SIMM9, 0, {0, 0}}, /* B */ - {"ldur", 0x3C400000u, 0xFFE00C00u, AA64_FMT_LDST_SIMM9, 0, {0, 0}}, - {"stur", 0x7C000000u, 0xFFE00C00u, AA64_FMT_LDST_SIMM9, 0, {0, 0}}, /* H */ - {"ldur", 0x7C400000u, 0xFFE00C00u, AA64_FMT_LDST_SIMM9, 0, {0, 0}}, - {"stur", 0xBC000000u, 0xFFE00C00u, AA64_FMT_LDST_SIMM9, 0, {0, 0}}, /* S */ - {"ldur", 0xBC400000u, 0xFFE00C00u, AA64_FMT_LDST_SIMM9, 0, {0, 0}}, - {"stur", 0xFC000000u, 0xFFE00C00u, AA64_FMT_LDST_SIMM9, AA64_ASMFL_SF1, + {MN("stur"), 0x3C000000u, 0xFFE00C00u, AA64_FMT_LDST_SIMM9, 0, {0, 0}}, /* B */ + {MN("ldur"), 0x3C400000u, 0xFFE00C00u, AA64_FMT_LDST_SIMM9, 0, {0, 0}}, + {MN("stur"), 0x7C000000u, 0xFFE00C00u, AA64_FMT_LDST_SIMM9, 0, {0, 0}}, /* H */ + {MN("ldur"), 0x7C400000u, 0xFFE00C00u, AA64_FMT_LDST_SIMM9, 0, {0, 0}}, + {MN("stur"), 0xBC000000u, 0xFFE00C00u, AA64_FMT_LDST_SIMM9, 0, {0, 0}}, /* S */ + {MN("ldur"), 0xBC400000u, 0xFFE00C00u, AA64_FMT_LDST_SIMM9, 0, {0, 0}}, + {MN("stur"), 0xFC000000u, 0xFFE00C00u, AA64_FMT_LDST_SIMM9, AA64_ASMFL_SF1, {0, 0}}, /* D */ - {"ldur", 0xFC400000u, 0xFFE00C00u, AA64_FMT_LDST_SIMM9, AA64_ASMFL_SF1, + {MN("ldur"), 0xFC400000u, 0xFFE00C00u, AA64_FMT_LDST_SIMM9, AA64_ASMFL_SF1, {0, 0}}, /* ----- Load/store pair, pre-indexed (opc=10 X / opc=01 D) ----- */ - {"stp", 0xA9800000u, 0xFFC00000u, AA64_FMT_LDSTP_PRE, AA64_ASMFL_SF1, + {MN("stp"), 0xA9800000u, 0xFFC00000u, AA64_FMT_LDSTP_PRE, AA64_ASMFL_SF1, {0, 0}}, - {"ldp", 0xA9C00000u, 0xFFC00000u, AA64_FMT_LDSTP_PRE, AA64_ASMFL_SF1, + {MN("ldp"), 0xA9C00000u, 0xFFC00000u, AA64_FMT_LDSTP_PRE, AA64_ASMFL_SF1, {0, 0}}, - {"stp", 0x6D800000u, 0xFFC00000u, AA64_FMT_LDSTP_PRE, 0, {0, 0}}, /* D */ - {"ldp", 0x6DC00000u, 0xFFC00000u, AA64_FMT_LDSTP_PRE, 0, {0, 0}}, - {"stp", 0xAD800000u, 0xFFC00000u, AA64_FMT_LDSTP_PRE, AA64_ASMFL_SF1, + {MN("stp"), 0x6D800000u, 0xFFC00000u, AA64_FMT_LDSTP_PRE, 0, {0, 0}}, /* D */ + {MN("ldp"), 0x6DC00000u, 0xFFC00000u, AA64_FMT_LDSTP_PRE, 0, {0, 0}}, + {MN("stp"), 0xAD800000u, 0xFFC00000u, AA64_FMT_LDSTP_PRE, AA64_ASMFL_SF1, {0, 0}}, /* Q */ - {"ldp", 0xADC00000u, 0xFFC00000u, AA64_FMT_LDSTP_PRE, AA64_ASMFL_SF1, + {MN("ldp"), 0xADC00000u, 0xFFC00000u, AA64_FMT_LDSTP_PRE, AA64_ASMFL_SF1, {0, 0}}, /* ----- Load/store pair, signed-offset ----- */ - {"stp", 0xA9000000u, 0xFFC00000u, AA64_FMT_LDSTP_SOFF, AA64_ASMFL_SF1, + {MN("stp"), 0xA9000000u, 0xFFC00000u, AA64_FMT_LDSTP_SOFF, AA64_ASMFL_SF1, {0, 0}}, - {"ldp", 0xA9400000u, 0xFFC00000u, AA64_FMT_LDSTP_SOFF, AA64_ASMFL_SF1, + {MN("ldp"), 0xA9400000u, 0xFFC00000u, AA64_FMT_LDSTP_SOFF, AA64_ASMFL_SF1, {0, 0}}, - {"stp", 0x6D000000u, 0xFFC00000u, AA64_FMT_LDSTP_SOFF, 0, {0, 0}}, /* D */ - {"ldp", 0x6D400000u, 0xFFC00000u, AA64_FMT_LDSTP_SOFF, 0, {0, 0}}, - {"stp", 0xAD000000u, 0xFFC00000u, AA64_FMT_LDSTP_SOFF, AA64_ASMFL_SF1, + {MN("stp"), 0x6D000000u, 0xFFC00000u, AA64_FMT_LDSTP_SOFF, 0, {0, 0}}, /* D */ + {MN("ldp"), 0x6D400000u, 0xFFC00000u, AA64_FMT_LDSTP_SOFF, 0, {0, 0}}, + {MN("stp"), 0xAD000000u, 0xFFC00000u, AA64_FMT_LDSTP_SOFF, AA64_ASMFL_SF1, {0, 0}}, /* Q */ - {"ldp", 0xAD400000u, 0xFFC00000u, AA64_FMT_LDSTP_SOFF, AA64_ASMFL_SF1, + {MN("ldp"), 0xAD400000u, 0xFFC00000u, AA64_FMT_LDSTP_SOFF, AA64_ASMFL_SF1, {0, 0}}, /* ----- Unconditional branch (immediate) ----- */ - {"b", 0x14000000u, 0xFC000000u, AA64_FMT_BR_IMM, 0, {0, 0}}, - {"bl", 0x94000000u, 0xFC000000u, AA64_FMT_BR_IMM, 0, {0, 0}}, + {MN("b"), 0x14000000u, 0xFC000000u, AA64_FMT_BR_IMM, 0, {0, 0}}, + {MN("bl"), 0x94000000u, 0xFC000000u, AA64_FMT_BR_IMM, 0, {0, 0}}, /* ----- Conditional branch (immediate) ----- */ - {"b.cond", 0x54000000u, 0xFF000010u, AA64_FMT_BR_COND, 0, {0, 0}}, + {MN("b.cond"), 0x54000000u, 0xFF000010u, AA64_FMT_BR_COND, 0, {0, 0}}, /* ----- Compare-and-branch ----- */ - {"cbz", 0x34000000u, 0x7F000000u, AA64_FMT_CB, 0, {0, 0}}, - {"cbnz", 0x35000000u, 0x7F000000u, AA64_FMT_CB, 0, {0, 0}}, + {MN("cbz"), 0x34000000u, 0x7F000000u, AA64_FMT_CB, 0, {0, 0}}, + {MN("cbnz"), 0x35000000u, 0x7F000000u, AA64_FMT_CB, 0, {0, 0}}, /* ----- Exception generation ----- */ - {"svc", 0xD4000001u, 0xFFE0001Fu, AA64_FMT_EXCEPT, 0, {0, 0}}, - {"brk", 0xD4200000u, 0xFFE0001Fu, AA64_FMT_EXCEPT, 0, {0, 0}}, - {"hlt", 0xD4400000u, 0xFFE0001Fu, AA64_FMT_EXCEPT, 0, {0, 0}}, + {MN("svc"), 0xD4000001u, 0xFFE0001Fu, AA64_FMT_EXCEPT, 0, {0, 0}}, + {MN("brk"), 0xD4200000u, 0xFFE0001Fu, AA64_FMT_EXCEPT, 0, {0, 0}}, + {MN("hlt"), 0xD4400000u, 0xFFE0001Fu, AA64_FMT_EXCEPT, 0, {0, 0}}, /* ----- Hint ----- */ - {"nop", 0xD503201Fu, 0xFFFFFFFFu, AA64_FMT_HINT, 0, {0, 0}}, + {MN("nop"), 0xD503201Fu, 0xFFFFFFFFu, AA64_FMT_HINT, 0, {0, 0}}, /* ----- Memory barriers (DMB / DSB / ISB / CLREX) ----- * Mask covers everything but CRm at bits[11:8]. */ - {"dmb", 0xD50330BFu, 0xFFFFF0FFu, AA64_FMT_BARRIER, 0, {0, 0}}, - {"dsb", 0xD503309Fu, 0xFFFFF0FFu, AA64_FMT_BARRIER, 0, {0, 0}}, - {"isb", 0xD50330DFu, 0xFFFFF0FFu, AA64_FMT_BARRIER, 0, {0, 0}}, - {"clrex", 0xD503305Fu, 0xFFFFF0FFu, AA64_FMT_BARRIER, 0, {0, 0}}, + {MN("dmb"), 0xD50330BFu, 0xFFFFF0FFu, AA64_FMT_BARRIER, 0, {0, 0}}, + {MN("dsb"), 0xD503309Fu, 0xFFFFF0FFu, AA64_FMT_BARRIER, 0, {0, 0}}, + {MN("isb"), 0xD50330DFu, 0xFFFFF0FFu, AA64_FMT_BARRIER, 0, {0, 0}}, + {MN("clrex"), 0xD503305Fu, 0xFFFFF0FFu, AA64_FMT_BARRIER, 0, {0, 0}}, }; +#undef MN + const u32 aa64_insn_table_n = (u32)(sizeof aa64_insn_table / sizeof aa64_insn_table[0]); @@ -315,7 +320,7 @@ static void print_addsubsr(StrBuf* sb, u32 w, const AA64InsnDesc* d) { AA64AddSubSR f = aa64_addsubsr_unpack(w); if (d->flags & AA64_ASMFL_ALIAS) { /* NEG / NEGS / CMP / CMN. */ - if (d->mnemonic[0] == 'c') { + if (d->mnemonic.s[0] == 'c') { /* CMP / CMN — print Rn, Rm */ emit_reg(sb, f.Rn, (int)f.sf, 0); strbuf_puts(sb, ", "); @@ -590,14 +595,14 @@ static void print_barrier(StrBuf* sb, u32 w, const AA64InsnDesc* desc) { case AA64_BARRIER_OPT_ISHLD: opt = "ishld"; break; case AA64_BARRIER_OPT_ISHST: opt = "ishst"; break; case AA64_BARRIER_OPT_ISH: opt = "ish"; break; - case AA64_BARRIER_OPT_LD: opt = (desc && desc->mnemonic && - desc->mnemonic[0] == 'd' && - desc->mnemonic[1] == 'm') + case AA64_BARRIER_OPT_LD: opt = (desc && desc->mnemonic.len >= 2 && + desc->mnemonic.s[0] == 'd' && + desc->mnemonic.s[1] == 'm') ? "ld" : NULL; break; - case AA64_BARRIER_OPT_ST: opt = (desc && desc->mnemonic && - desc->mnemonic[0] == 'd' && - desc->mnemonic[1] == 'm') + case AA64_BARRIER_OPT_ST: opt = (desc && desc->mnemonic.len >= 2 && + desc->mnemonic.s[0] == 'd' && + desc->mnemonic.s[1] == 'm') ? "st" : NULL; break; case AA64_BARRIER_OPT_SY: opt = "sy"; break; diff --git a/src/arch/aa64/isa.h b/src/arch/aa64/isa.h @@ -26,6 +26,7 @@ * inline wrapper in the relevant format section. */ #include "core/core.h" +#include "core/slice.h" #include "core/strbuf.h" /* ---- common register names ---- */ @@ -1131,7 +1132,7 @@ static inline u32 aa64_svc(u32 imm16) { * ==================================================================== */ typedef struct AA64InsnDesc { - const char* mnemonic; + Slice mnemonic; u32 match; u32 mask; u8 fmt; /* AA64Format */ diff --git a/src/arch/aa64/ops.c b/src/arch/aa64/ops.c @@ -2,6 +2,7 @@ * intrinsics, asm_block, set_loc, finalize/destroy, vtable constructor. */ #include "arch/aa64/internal.h" +#include "core/slice.h" /* ============================================================ * Data movement @@ -20,7 +21,7 @@ static void aa_load_const(CGTarget* t, Operand dst, ConstBytes cb) { compiler_panic(t->c, a->loc, "aarch64 load_const: only FP supported in v1"); } - Sym ro_name = pool_intern_cstr(t->c->global, ".rodata"); + Sym ro_name = pool_intern_slice(t->c->global, SLICE_LIT(".rodata")); ObjSecId ro = obj_section(t->obj, ro_name, SEC_RODATA, SF_ALLOC, 1u); u32 cur_section = t->mc->section_id; @@ -48,7 +49,7 @@ static void aa_load_const(CGTarget* t, Operand dst, ConstBytes cb) { for (int i = tn - 1; i >= 0; --i) namebuf[len++] = tmp[i]; namebuf[len] = 0; } - Sym sname = pool_intern_cstr(t->c->global, namebuf); + Sym sname = pool_intern_slice(t->c->global, slice_from_cstr(namebuf)); ObjSymId sym = obj_symbol(t->obj, sname, SB_LOCAL, SK_OBJ, ro, (u64)ro_off, (u64)cb.size); @@ -246,7 +247,8 @@ static inline void aa_assert_no_index(CGTarget* t, Operand addr, const char* where) { if (addr.kind == OPK_INDIRECT && addr.v.ind.index != REG_NONE) { compiler_panic(t->c, impl_of(t)->loc, - "aarch64 %s: OPK_INDIRECT with index unexpected", where); + "aarch64 %.*s: OPK_INDIRECT with index unexpected", + SLICE_ARG(slice_from_cstr(where))); } } @@ -558,7 +560,7 @@ static void aa_tls_addr_of(CGTarget* t, Operand dst, ObjSymId sym, i64 addend) { * SECREL fixups assume the merged .tls section is < 16 MiB; cfree * panics with a clear diagnostic at link time if that ever fails. */ if (t->c->target.os == CFREE_OS_WINDOWS) { - Sym idx_name = pool_intern_cstr(t->c->global, "_tls_index"); + Sym idx_name = pool_intern_slice(t->c->global, SLICE_LIT("_tls_index")); ObjSymId idx_sym = obj_symbol_find(t->obj, idx_name); if (idx_sym == 0) { idx_sym = obj_symbol(t->obj, idx_name, SB_GLOBAL, SK_UNDEF, @@ -2467,8 +2469,9 @@ static void aa_intrinsic(CGTarget* t, IntrinKind kind, Operand* dsts, u32 nd, Operand da = args[0], sa = args[1], nb = args[2]; if (da.kind != OPK_REG || sa.kind != OPK_REG || nb.kind != OPK_IMM) { compiler_panic(t->c, a->loc, - "aarch64 intrinsic: %s with non-const n or non-REG ptr", - kind == INTRIN_MEMCPY ? "memcpy" : "memmove"); + "aarch64 intrinsic: %.*s with non-const n or non-REG ptr", + SLICE_ARG(slice_from_cstr( + kind == INTRIN_MEMCPY ? "memcpy" : "memmove"))); } u32 dr = reg_num(da); u32 sr = reg_num(sa); diff --git a/src/arch/aa64/regs.c b/src/arch/aa64/regs.c @@ -16,6 +16,7 @@ #include "arch/aa64/regs.h" #include "core/core.h" +#include "core/slice.h" typedef struct AA64Reg { uint32_t dwarf_idx; @@ -52,9 +53,11 @@ const char* aa64_register_name(uint32_t dwarf_idx) { int aa64_register_index(const char* name, uint32_t* idx_out) { uint32_t i; + Slice q; if (!name) return 1; + q = slice_from_cstr(name); for (i = 0; i < AA64_REGS_N; ++i) { - if (!strcmp(AA64_REGS[i].name, name)) { + if (slice_eq_cstr(q, AA64_REGS[i].name)) { if (idx_out) *idx_out = AA64_REGS[i].dwarf_idx; return 0; } @@ -62,7 +65,7 @@ int aa64_register_index(const char* name, uint32_t* idx_out) { /* Accept Wn alias for Xn (same DWARF index). */ if (name[0] == 'w' && name[1] != '\0') { char buf[8]; - size_t n = strlen(name); + size_t n = q.len; if (n < sizeof buf) { buf[0] = 'x'; memcpy(buf + 1, name + 1, n); @@ -70,7 +73,7 @@ int aa64_register_index(const char* name, uint32_t* idx_out) { } } /* wzr / xzr aliases. */ - if (!strcmp(name, "wzr") || !strcmp(name, "xzr")) { + if (slice_eq_cstr(q, "wzr") || slice_eq_cstr(q, "xzr")) { if (idx_out) *idx_out = 31u; /* shares SP encoding slot; v1 picks SP */ return 0; } diff --git a/src/arch/c_target/emit.c b/src/arch/c_target/emit.c @@ -23,6 +23,7 @@ #include "core/core.h" #include "core/heap.h" #include "core/pool.h" +#include "core/slice.h" #include "obj/obj.h" /* Forward decls. */ @@ -113,8 +114,8 @@ static const char* c_typedef_name(CTarget* t, CfreeCgTypeId tid) { CfreeCgTypeId u = api_unalias_type(t->c, tid); char buf[32]; int n = snprintf(buf, sizeof buf, "__ty_%u", (unsigned)u); - Sym s = pool_intern(t->c->global, buf, (size_t)n); - return pool_str(t->c->global, s, NULL); + Sym s = pool_intern_slice(t->c->global, (Slice){.s = buf, .len = (size_t)n}); + return pool_slice(t->c->global, s).s; } /* Forward decl. */ @@ -472,7 +473,8 @@ static void c_assert_no_index(CTarget* t, Operand addr, const char* where) { if (addr.v.ind.index == REG_NONE) return; SrcLoc loc = t->cur_fn ? t->cur_fn->loc : (SrcLoc){0, 0, 0}; compiler_panic(t->c, loc, - "C target: %s: indexed OPK_INDIRECT not allowed here", where); + "C target: %.*s: indexed OPK_INDIRECT not allowed here", + SLICE_ARG(slice_from_cstr(where))); } void c_emit_operand(CTarget* t, Operand op) { @@ -905,8 +907,9 @@ const char* c_sym_name(CTarget* t, ObjSymId sym) { compiler_panic(t->c, (SrcLoc){0, 0, 0}, "C target: unknown ObjSymId %u", (unsigned)sym); } - size_t n = 0; - const char* s = pool_str(t->c->global, os->name, &n); + Slice nm = pool_slice(t->c->global, os->name); + const char* s = nm.s; + size_t n = nm.len; /* Mach-O linker symbols are mangled with a leading underscore; the host * C compiler will re-add it on its own, so strip when re-emitting source. */ if (t->c->target.obj == CFREE_OBJ_MACHO && s && n > 0 && s[0] == '_') { @@ -952,8 +955,8 @@ const char* c_sym_name(CTarget* t, ObjSymId sym) { buf[out++] = ok ? ch : '_'; } buf[out] = '\0'; - Sym interned = pool_intern(t->c->global, buf, out); - return pool_str(t->c->global, interned, NULL); + Sym interned = pool_intern_slice(t->c->global, (Slice){.s = buf, .len = out}); + return pool_slice(t->c->global, interned).s; } /* === Prologue / finalize === */ @@ -2913,7 +2916,7 @@ void c_asm_block(CGTarget* T, const char* tmpl, const AsmConstraint* outs, if (i > 0) cbuf_puts(&t->body, ", "); if (outs[i].name) { cbuf_puts(&t->body, "["); - cbuf_puts(&t->body, pool_str(t->c->global, outs[i].name, NULL)); + cbuf_puts(&t->body, pool_slice(t->c->global, outs[i].name).s); cbuf_puts(&t->body, "] "); } c_emit_c_string_literal(&t->body, outs[i].str ? outs[i].str : ""); @@ -2946,7 +2949,7 @@ void c_asm_block(CGTarget* T, const char* tmpl, const AsmConstraint* outs, emitted_any = 1; if (ins[i].name) { cbuf_puts(&t->body, "["); - cbuf_puts(&t->body, pool_str(t->c->global, ins[i].name, NULL)); + cbuf_puts(&t->body, pool_slice(t->c->global, ins[i].name).s); cbuf_puts(&t->body, "] "); } c_emit_c_string_literal(&t->body, cs); @@ -2959,7 +2962,7 @@ void c_asm_block(CGTarget* T, const char* tmpl, const AsmConstraint* outs, for (u32 i = 0; i < nc; ++i) { if (i > 0) cbuf_puts(&t->body, ", "); c_emit_c_string_literal(&t->body, - pool_str(t->c->global, clobs[i], NULL)); + pool_slice(t->c->global, clobs[i]).s); } cbuf_puts(&t->body, ");\n"); } @@ -3168,11 +3171,12 @@ void c_fence(CGTarget* T, MemOrder o) { /* === set_loc === */ -static void cbuf_put_line_filename(CBuf* b, const char* s) { +static void cbuf_put_line_filename(CBuf* b, CfreeSlice s) { + size_t i; cbuf_putc(b, '"'); - if (s) { - while (*s) { - unsigned char ch = (unsigned char)*s++; + for (i = 0; i < s.len; ++i) { + { + unsigned char ch = (unsigned char)s.s[i]; switch (ch) { case '\\': case '"': @@ -3199,7 +3203,7 @@ static void cbuf_put_line_filename(CBuf* b, const char* s) { void c_set_loc(CGTarget* T, SrcLoc l) { CTarget* t = (CTarget*)T; - const char* file; + CfreeSlice file; if (!t->cur_fn || l.file_id == 0 || l.line == 0) return; if (t->have_emitted_loc && t->emitted_loc.file_id == l.file_id && @@ -3208,7 +3212,7 @@ void c_set_loc(CGTarget* T, SrcLoc l) { } file = cfree_compiler_file_name(t->c, l.file_id); - if (!file) return; + if (!file.len) return; cbuf_puts(&t->body, "#line "); cbuf_put_u64(&t->body, (u64)l.line); @@ -3305,7 +3309,7 @@ static ObjSymId c_macho_tls_find_init(CTarget* t, ObjSecId desc_sec, * on Mach-O). Compared by interned Sym id. */ static int c_sec_name_is_macho_tvars(CTarget* t, const Section* sec) { if (!sec) return 0; - Sym tvars = pool_intern_cstr(t->c->global, "__DATA,__thread_vars"); + Sym tvars = pool_intern_slice(t->c->global, SLICE_LIT("__DATA,__thread_vars")); return sec->name == tvars; } diff --git a/src/arch/mc.c b/src/arch/mc.c @@ -803,9 +803,9 @@ void mc_emit_eh_frame(MCEmitter* m) { * ".eh_frame". The Mach-O emitter splits on comma; the ELF emitter * uses the literal as section name. */ if (m->c->target.obj == CFREE_OBJ_MACHO) { - sec_name = pool_intern_cstr(m->c->global, "__TEXT,__eh_frame"); + sec_name = pool_intern_slice(m->c->global, SLICE_LIT("__TEXT,__eh_frame")); } else { - sec_name = pool_intern_cstr(m->c->global, ".eh_frame"); + sec_name = pool_intern_slice(m->c->global, SLICE_LIT(".eh_frame")); } eh_sec = obj_section(m->obj, sec_name, SEC_OTHER, SF_ALLOC, 8); { diff --git a/src/arch/rv64/arch.c b/src/arch/rv64/arch.c @@ -32,8 +32,12 @@ static const ArchDwarfOps rv64_dwarf_ops = { }; static int rv64_register_at_public(uint32_t idx, CfreeArchReg* out) { + const char* nm = NULL; + int rc; if (!out) return 1; - return rv64_register_iter_get(idx, &out->dwarf_idx, &out->name); + rc = rv64_register_iter_get(idx, &out->dwarf_idx, &nm); + if (rc == 0) out->name = cfree_slice_cstr(nm); + return rc; } static int rv64_apply_label_fixup(Compiler* c, const ArchLabelFixup* fx) { @@ -112,26 +116,26 @@ static int rv64_apply_label_fixup(Compiler* c, const ArchLabelFixup* fx) { * extensions outside scope (V, B, Zve*, Zfh, …) are deliberately * absent. ABI variant is lp64d. */ static const CfreePredefinedMacro rv64_predefined_macros[] = { - {"__riscv", "1"}, - {"__riscv_xlen", "64"}, - {"__riscv_float_abi_double", "1"}, - {"__riscv_atomic", "1"}, - {"__riscv_mul", "1"}, - {"__riscv_div", "1"}, - {"__riscv_muldiv", "1"}, - {"__riscv_compressed", "1"}, - {"__riscv_flen", "64"}, - {"__riscv_fdiv", "1"}, - {"__riscv_fsqrt", "1"}, - {"__riscv_zicsr", "1"}, - {"__riscv_zifencei", "1"}, - {"__riscv_arch_test", "1"}, - {"__LP64__", "1"}, - {"_LP64", "1"}, - {"__ORDER_LITTLE_ENDIAN__", "1234"}, - {"__ORDER_BIG_ENDIAN__", "4321"}, - {"__BYTE_ORDER__", "__ORDER_LITTLE_ENDIAN__"}, - {"__LITTLE_ENDIAN__", "1"}, + {CFREE_SLICE_LIT("__riscv"), CFREE_SLICE_LIT("1")}, + {CFREE_SLICE_LIT("__riscv_xlen"), CFREE_SLICE_LIT("64")}, + {CFREE_SLICE_LIT("__riscv_float_abi_double"), CFREE_SLICE_LIT("1")}, + {CFREE_SLICE_LIT("__riscv_atomic"), CFREE_SLICE_LIT("1")}, + {CFREE_SLICE_LIT("__riscv_mul"), CFREE_SLICE_LIT("1")}, + {CFREE_SLICE_LIT("__riscv_div"), CFREE_SLICE_LIT("1")}, + {CFREE_SLICE_LIT("__riscv_muldiv"), CFREE_SLICE_LIT("1")}, + {CFREE_SLICE_LIT("__riscv_compressed"), CFREE_SLICE_LIT("1")}, + {CFREE_SLICE_LIT("__riscv_flen"), CFREE_SLICE_LIT("64")}, + {CFREE_SLICE_LIT("__riscv_fdiv"), CFREE_SLICE_LIT("1")}, + {CFREE_SLICE_LIT("__riscv_fsqrt"), CFREE_SLICE_LIT("1")}, + {CFREE_SLICE_LIT("__riscv_zicsr"), CFREE_SLICE_LIT("1")}, + {CFREE_SLICE_LIT("__riscv_zifencei"), CFREE_SLICE_LIT("1")}, + {CFREE_SLICE_LIT("__riscv_arch_test"), CFREE_SLICE_LIT("1")}, + {CFREE_SLICE_LIT("__LP64__"), CFREE_SLICE_LIT("1")}, + {CFREE_SLICE_LIT("_LP64"), CFREE_SLICE_LIT("1")}, + {CFREE_SLICE_LIT("__ORDER_LITTLE_ENDIAN__"), CFREE_SLICE_LIT("1234")}, + {CFREE_SLICE_LIT("__ORDER_BIG_ENDIAN__"), CFREE_SLICE_LIT("4321")}, + {CFREE_SLICE_LIT("__BYTE_ORDER__"), CFREE_SLICE_LIT("__ORDER_LITTLE_ENDIAN__")}, + {CFREE_SLICE_LIT("__LITTLE_ENDIAN__"), CFREE_SLICE_LIT("1")}, }; static CGTarget* rv64_backend_make(Compiler* c, ObjBuilder* o, diff --git a/src/arch/rv64/asm.c b/src/arch/rv64/asm.c @@ -21,6 +21,7 @@ #include "asm/asm_helpers.h" #include "core/arena.h" #include "core/pool.h" +#include "core/slice.h" #include "core/strbuf.h" struct Rv64Asm { @@ -49,14 +50,18 @@ typedef struct Rv64Mem { } Rv64Mem; static int sym_to_cstr(AsmDriver* d, Sym s, char* out, size_t cap) { - size_t n = 0; - const char* p = pool_str(asm_driver_pool(d), s, &n); - if (!p || n >= cap) return 0; - memcpy(out, p, n); - out[n] = '\0'; + Slice sl = pool_slice(asm_driver_pool(d), s); + if (!sl.s || sl.len >= cap) return 0; + memcpy(out, sl.s, sl.len); + out[sl.len] = '\0'; return 1; } +/* True if `s` begins with the NUL-terminated literal `pfx` (length-explicit). */ +static bool slice_has_prefix_cstr(Slice s, const char* pfx, size_t n) { + return s.len >= n && memcmp(s.s, pfx, n) == 0; +} + static int rv_reg_from_name(AsmDriver* d, Sym s, u32* reg_out, int* fp_out) { char name[16]; uint32_t dwarf = 0; @@ -305,23 +310,23 @@ static u32 assemble_one(AsmDriver* d, const Rv64InsnDesc* desc) { case RV64_FMT_I: /* Aliases first. */ if (desc->flags & RV64_ASMFL_ALIAS) { - if (!strcmp(desc->mnemonic, "li")) { + if (slice_eq_cstr(desc->mnemonic, "li")) { rd = parse_xreg(d); expect_comma(d); imm = (i32)asm_driver_parse_const(d); return enc_i(m, rd, 0u, imm); } - if (!strcmp(desc->mnemonic, "mv")) { + if (slice_eq_cstr(desc->mnemonic, "mv")) { rd = parse_xreg(d); expect_comma(d); rs1 = parse_xreg(d); return enc_i(m, rd, rs1, 0); } - if (!strcmp(desc->mnemonic, "sext.w")) { + if (slice_eq_cstr(desc->mnemonic, "sext.w")) { rd = parse_xreg(d); expect_comma(d); rs1 = parse_xreg(d); return enc_i(m, rd, rs1, 0); } - if (!strcmp(desc->mnemonic, "seqz") || - !strcmp(desc->mnemonic, "not")) { + if (slice_eq_cstr(desc->mnemonic, "seqz") || + slice_eq_cstr(desc->mnemonic, "not")) { rd = parse_xreg(d); expect_comma(d); rs1 = parse_xreg(d); /* match already has imm12 + funct3 + op pinned. */ @@ -351,7 +356,7 @@ static u32 assemble_one(AsmDriver* d, const Rv64InsnDesc* desc) { return enc_u(m, rd, (u32)imm); case RV64_FMT_J: - if ((desc->flags & RV64_ASMFL_ALIAS) && !strcmp(desc->mnemonic, "j")) { + if ((desc->flags & RV64_ASMFL_ALIAS) && slice_eq_cstr(desc->mnemonic, "j")) { imm = (i32)asm_driver_parse_const(d); return enc_j(m, 0u, imm); } @@ -394,13 +399,13 @@ static u32 assemble_one(AsmDriver* d, const Rv64InsnDesc* desc) { return enc_s(m, rs2, mem.base, mem.disp); case RV64_FMT_JALR: - if ((desc->flags & RV64_ASMFL_ALIAS) && !strcmp(desc->mnemonic, "jr")) { + if ((desc->flags & RV64_ASMFL_ALIAS) && slice_eq_cstr(desc->mnemonic, "jr")) { rs1 = parse_xreg(d); return enc_i(m, 0u, rs1, 0); } rd = parse_xreg(d); if (!asm_driver_eat_comma(d)) { - if (!strcmp(desc->mnemonic, "jalr")) + if (slice_eq_cstr(desc->mnemonic, "jalr")) return enc_i(m, RV_RA, rd, 0); asm_driver_panic(d, "rv64 asm: expected ','"); } @@ -457,14 +462,14 @@ static u32 assemble_one(AsmDriver* d, const Rv64InsnDesc* desc) { /* Source: integer reg for fcvt.s.w etc (no FP flag would * indicate); but since we have ASMFL_FP set on dest, source may * be either. Disambiguate by mnemonic. */ - if (!strncmp(desc->mnemonic, "fcvt.s.", 7) && - (desc->mnemonic[7] == 'w' || desc->mnemonic[7] == 'l')) { + if (slice_has_prefix_cstr(desc->mnemonic, "fcvt.s.", 7) && + (desc->mnemonic.s[7] == 'w' || desc->mnemonic.s[7] == 'l')) { rs1 = parse_xreg(d); - } else if (!strncmp(desc->mnemonic, "fcvt.d.", 7) && - (desc->mnemonic[7] == 'w' || desc->mnemonic[7] == 'l')) { + } else if (slice_has_prefix_cstr(desc->mnemonic, "fcvt.d.", 7) && + (desc->mnemonic.s[7] == 'w' || desc->mnemonic.s[7] == 'l')) { rs1 = parse_xreg(d); - } else if (!strcmp(desc->mnemonic, "fmv.w.x") || - !strcmp(desc->mnemonic, "fmv.d.x")) { + } else if (slice_eq_cstr(desc->mnemonic, "fmv.w.x") || + slice_eq_cstr(desc->mnemonic, "fmv.d.x")) { rs1 = parse_xreg(d); } else { rs1 = parse_freg(d); @@ -508,8 +513,8 @@ static u32 assemble_one(AsmDriver* d, const Rv64InsnDesc* desc) { } case RV64_FMT_CR: - if (!strcmp(desc->mnemonic, "c.jr") || - !strcmp(desc->mnemonic, "c.jalr")) { + if (slice_eq_cstr(desc->mnemonic, "c.jr") || + slice_eq_cstr(desc->mnemonic, "c.jalr")) { rs1 = parse_xreg(d); return enc_c_cr(m, rs1, 0u); } @@ -518,22 +523,22 @@ static u32 assemble_one(AsmDriver* d, const Rv64InsnDesc* desc) { return enc_c_cr(m, rd, rs2); case RV64_FMT_CI: - if (!strcmp(desc->mnemonic, "c.lwsp") || - !strcmp(desc->mnemonic, "c.ldsp") || - !strcmp(desc->mnemonic, "c.fldsp")) { - rd = !strcmp(desc->mnemonic, "c.fldsp") ? parse_freg(d) : parse_xreg(d); + if (slice_eq_cstr(desc->mnemonic, "c.lwsp") || + slice_eq_cstr(desc->mnemonic, "c.ldsp") || + slice_eq_cstr(desc->mnemonic, "c.fldsp")) { + rd = slice_eq_cstr(desc->mnemonic, "c.fldsp") ? parse_freg(d) : parse_xreg(d); expect_comma(d); mem = parse_mem(d); if (mem.base != RV_SP) asm_driver_panic(d, "rv64 asm: compressed stack load needs sp base"); return enc_c_lwsp(m, rd, (u32)mem.disp, - strcmp(desc->mnemonic, "c.lwsp") != 0); + !slice_eq_cstr(desc->mnemonic, "c.lwsp")); } rd = parse_xreg(d); expect_comma(d); imm = (i32)asm_driver_parse_const(d); - if (!strcmp(desc->mnemonic, "c.lui") && ((u32)imm & 0xfffu) == 0) + if (slice_eq_cstr(desc->mnemonic, "c.lui") && ((u32)imm & 0xfffu) == 0) imm >>= 12; - if (!strcmp(desc->mnemonic, "c.addi16sp")) { + if (slice_eq_cstr(desc->mnemonic, "c.addi16sp")) { if (rd != RV_SP) asm_driver_panic(d, "rv64 asm: c.addi16sp needs sp destination"); return enc_c_addi16sp(m, imm); @@ -547,7 +552,7 @@ static u32 assemble_one(AsmDriver* d, const Rv64InsnDesc* desc) { if (mem.base != RV_SP) asm_driver_panic(d, "rv64 asm: compressed stack store needs sp base"); return enc_c_swsp(m, rs2, (u32)mem.disp, - strcmp(desc->mnemonic, "c.swsp") != 0); + !slice_eq_cstr(desc->mnemonic, "c.swsp")); case RV64_FMT_CIW: rd = parse_xreg(d); expect_comma(d); @@ -562,14 +567,14 @@ static u32 assemble_one(AsmDriver* d, const Rv64InsnDesc* desc) { expect_comma(d); mem = parse_mem(d); return enc_c_lwld(m, c_reg3(d, rd), c_reg3(d, mem.base), - (u32)mem.disp, strcmp(desc->mnemonic, "c.lw") != 0); + (u32)mem.disp, !slice_eq_cstr(desc->mnemonic, "c.lw")); case RV64_FMT_CS: rs2 = (desc->flags & RV64_ASMFL_FP) ? parse_freg(d) : parse_xreg(d); expect_comma(d); mem = parse_mem(d); return enc_c_swld(m, c_reg3(d, rs2), c_reg3(d, mem.base), - (u32)mem.disp, strcmp(desc->mnemonic, "c.sw") != 0); + (u32)mem.disp, !slice_eq_cstr(desc->mnemonic, "c.sw")); case RV64_FMT_CA: rd = parse_xreg(d); expect_comma(d); @@ -579,8 +584,8 @@ static u32 assemble_one(AsmDriver* d, const Rv64InsnDesc* desc) { case RV64_FMT_CB: rs1 = parse_xreg(d); expect_comma(d); imm = (i32)asm_driver_parse_const(d); - if (!strcmp(desc->mnemonic, "c.beqz") || - !strcmp(desc->mnemonic, "c.bnez")) { + if (slice_eq_cstr(desc->mnemonic, "c.beqz") || + slice_eq_cstr(desc->mnemonic, "c.bnez")) { return enc_c_cb_imm(m, c_reg3(d, rs1), imm); } return enc_c_cb_alu_imm(m, c_reg3(d, rs1), imm); @@ -599,13 +604,10 @@ static u32 assemble_one(AsmDriver* d, const Rv64InsnDesc* desc) { static void rv64_arch_asm_insn(ArchAsm* base, AsmDriver* d, Sym mnemonic) { MCEmitter* mc = asm_driver_mc(d); - char name[24]; const Rv64InsnDesc* desc; (void)base; (void)asm_driver_cur_section(d); - if (!sym_to_cstr(d, mnemonic, name, sizeof name)) - asm_driver_panic(d, "rv64 asm: mnemonic too long"); - desc = rv64_asm_find(name); + desc = rv64_asm_find(pool_slice(asm_driver_pool(d), mnemonic)); if (!desc) asm_driver_panic(d, "rv64 asm: unsupported instruction"); if (desc->flags & RV64_ASMFL_C16) rv64_emit16(mc, assemble_one(d, desc)); @@ -665,7 +667,8 @@ void rv64_inline_bind(Rv64Asm* a, _Noreturn static void inline_panic(Rv64Asm* a, const char* msg) { SrcLoc loc = {0, 0, 0}; - compiler_panic(a->c, loc, "rv64 inline asm: %s", msg); + compiler_panic(a->c, loc, "rv64 inline asm: %.*s", + SLICE_ARG(slice_from_cstr(msg))); } /* Render a 5-bit integer register number using its canonical psABI name. */ @@ -825,16 +828,17 @@ static void run_one_line(Rv64Asm* a, MCEmitter* mc, const char* text, AsmTok rest = asm_driver_next(d); if (rest.kind != ASM_TOK_IDENT) inline_panic(a, "composite mnemonic: expected ident after '.'"); - size_t hn = 0, rn = 0; - const char* hp = pool_str(asm_driver_pool(d), mn, &hn); - const char* rp = pool_str(asm_driver_pool(d), rest.v.ident, &rn); + Slice hsl = pool_slice(asm_driver_pool(d), mn); + Slice rsl = pool_slice(asm_driver_pool(d), rest.v.ident); + size_t hn = hsl.len, rn = rsl.len; char buf[64]; if (hn + 1 + rn >= sizeof buf) inline_panic(a, "composite mnemonic too long"); - for (size_t k = 0; k < hn; ++k) buf[k] = hp[k]; + for (size_t k = 0; k < hn; ++k) buf[k] = hsl.s[k]; buf[hn] = '.'; - for (size_t k = 0; k < rn; ++k) buf[hn + 1 + k] = rp[k]; - mn = pool_intern(asm_driver_pool(d), buf, hn + 1 + rn); + for (size_t k = 0; k < rn; ++k) buf[hn + 1 + k] = rsl.s[k]; + mn = pool_intern_slice(asm_driver_pool(d), + (Slice){.s = buf, .len = hn + 1 + rn}); dot = asm_driver_peek(d); } rv64_arch_asm_insn(&a->base, d, mn); @@ -866,7 +870,8 @@ static void render_and_run_line(Rv64Asm* a, MCEmitter* mc, StrBuf* sb, while (nend < end && *nend != ']') ++nend; if (nend == end) inline_panic(a, "unterminated %[name]"); size_t nlen = (size_t)(nend - nbeg); - Sym needle = pool_intern(a->c->global, nbeg, nlen); + Sym needle = pool_intern_slice(a->c->global, + (Slice){.s = nbeg, .len = nlen}); u32 idx = lookup_named(a, needle); if (idx == (u32)-1) inline_panic(a, "%[name] does not match any constraint"); @@ -887,7 +892,8 @@ static void render_and_run_line(Rv64Asm* a, MCEmitter* mc, StrBuf* sb, while (nend < end && *nend != ']') ++nend; if (nend == end) inline_panic(a, "unterminated %[name]"); size_t nlen = (size_t)(nend - nbeg); - Sym needle = pool_intern(a->c->global, nbeg, nlen); + Sym needle = pool_intern_slice(a->c->global, + (Slice){.s = nbeg, .len = nlen}); u32 idx = lookup_named(a, needle); if (idx == (u32)-1) inline_panic(a, "%[name] does not match any constraint"); diff --git a/src/arch/rv64/disasm.c b/src/arch/rv64/disasm.c @@ -65,7 +65,7 @@ static u32 rv_decode(ArchDisasm* base, const u8* bytes, size_t len, u64 vaddr, const Rv64InsnDesc* desc = rv64_disasm_find_c(first_hw); if (desc) { strbuf_reset(&d->mnem); - strbuf_puts(&d->mnem, desc->mnemonic); + strbuf_put_slice(&d->mnem, desc->mnemonic); strbuf_reset(&d->ops); rv64_print_operands(&d->ops, desc, first_hw, vaddr); } else { @@ -78,7 +78,7 @@ static u32 rv_decode(ArchDisasm* base, const u8* bytes, size_t len, u64 vaddr, const Rv64InsnDesc* desc = rv64_disasm_find(word); if (desc) { strbuf_reset(&d->mnem); - strbuf_puts(&d->mnem, desc->mnemonic); + strbuf_put_slice(&d->mnem, desc->mnemonic); strbuf_reset(&d->ops); rv64_print_operands(&d->ops, desc, word, vaddr); } else { @@ -91,9 +91,9 @@ static u32 rv_decode(ArchDisasm* base, const u8* bytes, size_t len, u64 vaddr, out->vaddr = vaddr; out->bytes = bytes; out->nbytes = nbytes; - out->mnemonic = strbuf_cstr(&d->mnem); - out->operands = strbuf_cstr(&d->ops); - out->annotation = strbuf_cstr(&d->ann); + out->mnemonic = strbuf_slice(&d->mnem); + out->operands = strbuf_slice(&d->ops); + out->annotation = strbuf_slice(&d->ann); return nbytes; } diff --git a/src/arch/rv64/emit.c b/src/arch/rv64/emit.c @@ -2,6 +2,7 @@ */ #include "arch/rv64/internal.h" +#include "core/slice.h" static u32 collect_mask_regs(u32 mask, u32 first, u32 last, u32 *out) { u32 n = 0; @@ -62,7 +63,8 @@ void rv64_patch32(ObjBuilder *obj, u32 sec_id, u32 ofs, u32 word) { _Noreturn void rv_panic(CGTarget *t, const char *what) { SrcLoc loc = impl_of(t)->loc; - compiler_panic(t->c, loc, "rv64: %s not implemented", what); + compiler_panic(t->c, loc, "rv64: %.*s not implemented", + SLICE_ARG(slice_from_cstr(what))); } int fits_signed32(i64 v) { diff --git a/src/arch/rv64/isa.c b/src/arch/rv64/isa.c @@ -14,8 +14,14 @@ #include <string.h> +#include "core/slice.h" #include "core/strbuf.h" +/* True if `s` begins with the NUL-terminated literal `pfx` (length-explicit). */ +static bool slice_has_prefix_cstr(Slice s, const char* pfx, size_t n) { + return s.len >= n && memcmp(s.s, pfx, n) == 0; +} + /* Family-match bit patterns. The opcode (bits 6:0) plus * funct3/funct7/funct5 selectors narrow each match. For aliases we pin * specific register fields (e.g. rs1=x0 for `li`, rd=x0 for `j`). */ @@ -94,102 +100,105 @@ * path which presents the halfword in low 16 bits. */ #define MATCH_C(w16) ((u32)(w16)) +/* Mnemonic Slice literal for a static table row (compile-time length). */ +#define MN(s) {{(s)}, sizeof(s) - 1} + const Rv64InsnDesc rv64_insn_table[] = { /* ================================================================= * RV64I base — integer register ops (R-type, OP=0x33) * ================================================================= */ - {"add", MATCH_R(0x00, 0x0, RV_OP), MASK_R, RV64_FMT_R, 0, {0, 0}}, - {"sub", MATCH_R(0x20, 0x0, RV_OP), MASK_R, RV64_FMT_R, 0, {0, 0}}, - {"sll", MATCH_R(0x00, 0x1, RV_OP), MASK_R, RV64_FMT_R, 0, {0, 0}}, - {"slt", MATCH_R(0x00, 0x2, RV_OP), MASK_R, RV64_FMT_R, 0, {0, 0}}, - {"sltu", MATCH_R(0x00, 0x3, RV_OP), MASK_R, RV64_FMT_R, 0, {0, 0}}, - {"xor", MATCH_R(0x00, 0x4, RV_OP), MASK_R, RV64_FMT_R, 0, {0, 0}}, - {"srl", MATCH_R(0x00, 0x5, RV_OP), MASK_R, RV64_FMT_R, 0, {0, 0}}, - {"sra", MATCH_R(0x20, 0x5, RV_OP), MASK_R, RV64_FMT_R, 0, {0, 0}}, - {"or", MATCH_R(0x00, 0x6, RV_OP), MASK_R, RV64_FMT_R, 0, {0, 0}}, - {"and", MATCH_R(0x00, 0x7, RV_OP), MASK_R, RV64_FMT_R, 0, {0, 0}}, + {MN("add"), MATCH_R(0x00, 0x0, RV_OP), MASK_R, RV64_FMT_R, 0, {0, 0}}, + {MN("sub"), MATCH_R(0x20, 0x0, RV_OP), MASK_R, RV64_FMT_R, 0, {0, 0}}, + {MN("sll"), MATCH_R(0x00, 0x1, RV_OP), MASK_R, RV64_FMT_R, 0, {0, 0}}, + {MN("slt"), MATCH_R(0x00, 0x2, RV_OP), MASK_R, RV64_FMT_R, 0, {0, 0}}, + {MN("sltu"), MATCH_R(0x00, 0x3, RV_OP), MASK_R, RV64_FMT_R, 0, {0, 0}}, + {MN("xor"), MATCH_R(0x00, 0x4, RV_OP), MASK_R, RV64_FMT_R, 0, {0, 0}}, + {MN("srl"), MATCH_R(0x00, 0x5, RV_OP), MASK_R, RV64_FMT_R, 0, {0, 0}}, + {MN("sra"), MATCH_R(0x20, 0x5, RV_OP), MASK_R, RV64_FMT_R, 0, {0, 0}}, + {MN("or"), MATCH_R(0x00, 0x6, RV_OP), MASK_R, RV64_FMT_R, 0, {0, 0}}, + {MN("and"), MATCH_R(0x00, 0x7, RV_OP), MASK_R, RV64_FMT_R, 0, {0, 0}}, /* 32-bit (W) variants — OP_32 = 0x3b */ - {"addw", MATCH_R(0x00, 0x0, RV_OP_32), MASK_R, RV64_FMT_R, 0, {0, 0}}, - {"subw", MATCH_R(0x20, 0x0, RV_OP_32), MASK_R, RV64_FMT_R, 0, {0, 0}}, - {"sllw", MATCH_R(0x00, 0x1, RV_OP_32), MASK_R, RV64_FMT_R, 0, {0, 0}}, - {"srlw", MATCH_R(0x00, 0x5, RV_OP_32), MASK_R, RV64_FMT_R, 0, {0, 0}}, - {"sraw", MATCH_R(0x20, 0x5, RV_OP_32), MASK_R, RV64_FMT_R, 0, {0, 0}}, + {MN("addw"), MATCH_R(0x00, 0x0, RV_OP_32), MASK_R, RV64_FMT_R, 0, {0, 0}}, + {MN("subw"), MATCH_R(0x20, 0x0, RV_OP_32), MASK_R, RV64_FMT_R, 0, {0, 0}}, + {MN("sllw"), MATCH_R(0x00, 0x1, RV_OP_32), MASK_R, RV64_FMT_R, 0, {0, 0}}, + {MN("srlw"), MATCH_R(0x00, 0x5, RV_OP_32), MASK_R, RV64_FMT_R, 0, {0, 0}}, + {MN("sraw"), MATCH_R(0x20, 0x5, RV_OP_32), MASK_R, RV64_FMT_R, 0, {0, 0}}, /* ---- I-type immediate ALU (OP_IMM=0x13) ---- * Aliases: `li rd, imm` = ADDI rd, x0, imm (rs1=x0). * `mv rd, rs1` = ADDI rd, rs1, 0 (imm=0). * `nop` = ADDI x0, x0, 0 (full word fixed). */ - {"nop", 0x00000013u, 0xffffffffu, RV64_FMT_SYSTEM, RV64_ASMFL_ALIAS, + {MN("nop"), 0x00000013u, 0xffffffffu, RV64_FMT_SYSTEM, RV64_ASMFL_ALIAS, {0, 0}}, - {"li", 0x00000013u, 0x000f807fu, RV64_FMT_I, RV64_ASMFL_ALIAS, {0, 0}}, + {MN("li"), 0x00000013u, 0x000f807fu, RV64_FMT_I, RV64_ASMFL_ALIAS, {0, 0}}, /* mv: ADDI with imm=0. mask requires imm12=0 + funct3=0 + op. */ - {"mv", 0x00000013u, 0xfff0707fu, RV64_FMT_I, RV64_ASMFL_ALIAS, {0, 0}}, + {MN("mv"), 0x00000013u, 0xfff0707fu, RV64_FMT_I, RV64_ASMFL_ALIAS, {0, 0}}, /* seqz: SLTIU rd, rs, 1 — funct3=3, imm12=1, op=OP_IMM. */ - {"seqz", 0x00103013u, 0xfff0707fu, RV64_FMT_I, RV64_ASMFL_ALIAS, {0, 0}}, + {MN("seqz"), 0x00103013u, 0xfff0707fu, RV64_FMT_I, RV64_ASMFL_ALIAS, {0, 0}}, /* snez: SLTU rd, x0, rs2 — rs1=x0, funct3=3, op=OP. */ - {"snez", 0x00003033u, 0xfe0ff07fu, RV64_FMT_R, RV64_ASMFL_ALIAS, {0, 0}}, + {MN("snez"), 0x00003033u, 0xfe0ff07fu, RV64_FMT_R, RV64_ASMFL_ALIAS, {0, 0}}, /* not: XORI rd, rs, -1 — imm12=0xfff, funct3=4, op=OP_IMM. */ - {"not", 0xfff04013u, 0xfff0707fu, RV64_FMT_I, RV64_ASMFL_ALIAS, {0, 0}}, + {MN("not"), 0xfff04013u, 0xfff0707fu, RV64_FMT_I, RV64_ASMFL_ALIAS, {0, 0}}, /* neg: SUB rd, x0, rs2 — rs1=x0, funct7=0x20, funct3=0. */ - {"neg", 0x40000033u, 0xfe0ff07fu, RV64_FMT_R, RV64_ASMFL_ALIAS, {0, 0}}, + {MN("neg"), 0x40000033u, 0xfe0ff07fu, RV64_FMT_R, RV64_ASMFL_ALIAS, {0, 0}}, /* negw: SUBW rd, x0, rs2. */ - {"negw", 0x4000003bu, 0xfe0ff07fu, RV64_FMT_R, RV64_ASMFL_ALIAS, {0, 0}}, - {"addi", MATCH_I(0x0, RV_OP_IMM), MASK_I, RV64_FMT_I, 0, {0, 0}}, - {"slti", MATCH_I(0x2, RV_OP_IMM), MASK_I, RV64_FMT_I, 0, {0, 0}}, - {"sltiu", MATCH_I(0x3, RV_OP_IMM), MASK_I, RV64_FMT_I, 0, {0, 0}}, - {"xori", MATCH_I(0x4, RV_OP_IMM), MASK_I, RV64_FMT_I, 0, {0, 0}}, - {"ori", MATCH_I(0x6, RV_OP_IMM), MASK_I, RV64_FMT_I, 0, {0, 0}}, - {"andi", MATCH_I(0x7, RV_OP_IMM), MASK_I, RV64_FMT_I, 0, {0, 0}}, + {MN("negw"), 0x4000003bu, 0xfe0ff07fu, RV64_FMT_R, RV64_ASMFL_ALIAS, {0, 0}}, + {MN("addi"), MATCH_I(0x0, RV_OP_IMM), MASK_I, RV64_FMT_I, 0, {0, 0}}, + {MN("slti"), MATCH_I(0x2, RV_OP_IMM), MASK_I, RV64_FMT_I, 0, {0, 0}}, + {MN("sltiu"), MATCH_I(0x3, RV_OP_IMM), MASK_I, RV64_FMT_I, 0, {0, 0}}, + {MN("xori"), MATCH_I(0x4, RV_OP_IMM), MASK_I, RV64_FMT_I, 0, {0, 0}}, + {MN("ori"), MATCH_I(0x6, RV_OP_IMM), MASK_I, RV64_FMT_I, 0, {0, 0}}, + {MN("andi"), MATCH_I(0x7, RV_OP_IMM), MASK_I, RV64_FMT_I, 0, {0, 0}}, /* RV64I shift-imm: funct6 in bits 31:26, shamt in 25:20. */ - {"slli", MATCH_ISHIFT(0x00, 0x1, RV_OP_IMM), MASK_ISHIFT, + {MN("slli"), MATCH_ISHIFT(0x00, 0x1, RV_OP_IMM), MASK_ISHIFT, RV64_FMT_I_SHIFT, 0, {0, 0}}, - {"srli", MATCH_ISHIFT(0x00, 0x5, RV_OP_IMM), MASK_ISHIFT, + {MN("srli"), MATCH_ISHIFT(0x00, 0x5, RV_OP_IMM), MASK_ISHIFT, RV64_FMT_I_SHIFT, 0, {0, 0}}, - {"srai", MATCH_ISHIFT(0x10, 0x5, RV_OP_IMM), MASK_ISHIFT, + {MN("srai"), MATCH_ISHIFT(0x10, 0x5, RV_OP_IMM), MASK_ISHIFT, RV64_FMT_I_SHIFT, 0, {0, 0}}, /* OP_IMM_32: ADDIW + word shifts. sext.w alias = ADDIW rd, rs, 0. */ - {"sext.w", 0x0000001bu, 0xfff0707fu, RV64_FMT_I, RV64_ASMFL_ALIAS, + {MN("sext.w"), 0x0000001bu, 0xfff0707fu, RV64_FMT_I, RV64_ASMFL_ALIAS, {0, 0}}, - {"addiw", MATCH_I(0x0, RV_OP_IMM_32), MASK_I, RV64_FMT_I, 0, {0, 0}}, - {"slliw", MATCH_ISHIFTW(0x00, 0x1, RV_OP_IMM_32), MASK_ISHIFTW, + {MN("addiw"), MATCH_I(0x0, RV_OP_IMM_32), MASK_I, RV64_FMT_I, 0, {0, 0}}, + {MN("slliw"), MATCH_ISHIFTW(0x00, 0x1, RV_OP_IMM_32), MASK_ISHIFTW, RV64_FMT_I_SHIFTW, 0, {0, 0}}, - {"srliw", MATCH_ISHIFTW(0x00, 0x5, RV_OP_IMM_32), MASK_ISHIFTW, + {MN("srliw"), MATCH_ISHIFTW(0x00, 0x5, RV_OP_IMM_32), MASK_ISHIFTW, RV64_FMT_I_SHIFTW, 0, {0, 0}}, - {"sraiw", MATCH_ISHIFTW(0x20, 0x5, RV_OP_IMM_32), MASK_ISHIFTW, + {MN("sraiw"), MATCH_ISHIFTW(0x20, 0x5, RV_OP_IMM_32), MASK_ISHIFTW, RV64_FMT_I_SHIFTW, 0, {0, 0}}, /* ---- LUI / AUIPC ---- */ - {"lui", MATCH_U(RV_LUI), MASK_U, RV64_FMT_U, 0, {0, 0}}, - {"auipc", MATCH_U(RV_AUIPC), MASK_U, RV64_FMT_U, 0, {0, 0}}, + {MN("lui"), MATCH_U(RV_LUI), MASK_U, RV64_FMT_U, 0, {0, 0}}, + {MN("auipc"), MATCH_U(RV_AUIPC), MASK_U, RV64_FMT_U, 0, {0, 0}}, /* ---- Loads (I-type, op=LOAD=0x03) ---- */ - {"lb", MATCH_I(0x0, RV_LOAD), MASK_I, RV64_FMT_LOAD, 0, {0, 0}}, - {"lh", MATCH_I(0x1, RV_LOAD), MASK_I, RV64_FMT_LOAD, 0, {0, 0}}, - {"lw", MATCH_I(0x2, RV_LOAD), MASK_I, RV64_FMT_LOAD, 0, {0, 0}}, - {"ld", MATCH_I(0x3, RV_LOAD), MASK_I, RV64_FMT_LOAD, 0, {0, 0}}, - {"lbu", MATCH_I(0x4, RV_LOAD), MASK_I, RV64_FMT_LOAD, 0, {0, 0}}, - {"lhu", MATCH_I(0x5, RV_LOAD), MASK_I, RV64_FMT_LOAD, 0, {0, 0}}, - {"lwu", MATCH_I(0x6, RV_LOAD), MASK_I, RV64_FMT_LOAD, 0, {0, 0}}, + {MN("lb"), MATCH_I(0x0, RV_LOAD), MASK_I, RV64_FMT_LOAD, 0, {0, 0}}, + {MN("lh"), MATCH_I(0x1, RV_LOAD), MASK_I, RV64_FMT_LOAD, 0, {0, 0}}, + {MN("lw"), MATCH_I(0x2, RV_LOAD), MASK_I, RV64_FMT_LOAD, 0, {0, 0}}, + {MN("ld"), MATCH_I(0x3, RV_LOAD), MASK_I, RV64_FMT_LOAD, 0, {0, 0}}, + {MN("lbu"), MATCH_I(0x4, RV_LOAD), MASK_I, RV64_FMT_LOAD, 0, {0, 0}}, + {MN("lhu"), MATCH_I(0x5, RV_LOAD), MASK_I, RV64_FMT_LOAD, 0, {0, 0}}, + {MN("lwu"), MATCH_I(0x6, RV_LOAD), MASK_I, RV64_FMT_LOAD, 0, {0, 0}}, /* ---- Stores (S-type, op=STORE=0x23) ---- */ - {"sb", MATCH_S(0x0, RV_STORE), MASK_S, RV64_FMT_STORE, 0, {0, 0}}, - {"sh", MATCH_S(0x1, RV_STORE), MASK_S, RV64_FMT_STORE, 0, {0, 0}}, - {"sw", MATCH_S(0x2, RV_STORE), MASK_S, RV64_FMT_STORE, 0, {0, 0}}, - {"sd", MATCH_S(0x3, RV_STORE), MASK_S, RV64_FMT_STORE, 0, {0, 0}}, + {MN("sb"), MATCH_S(0x0, RV_STORE), MASK_S, RV64_FMT_STORE, 0, {0, 0}}, + {MN("sh"), MATCH_S(0x1, RV_STORE), MASK_S, RV64_FMT_STORE, 0, {0, 0}}, + {MN("sw"), MATCH_S(0x2, RV_STORE), MASK_S, RV64_FMT_STORE, 0, {0, 0}}, + {MN("sd"), MATCH_S(0x3, RV_STORE), MASK_S, RV64_FMT_STORE, 0, {0, 0}}, /* ---- Branches (B-type, op=BRANCH=0x63) ---- * Aliases: `beqz rs, off` = BEQ rs, x0, off; `bnez rs, off` = BNE. */ - {"beqz", 0x00000063u, 0x01f0707fu, RV64_FMT_B, RV64_ASMFL_ALIAS, {0, 0}}, - {"bnez", 0x00001063u, 0x01f0707fu, RV64_FMT_B, RV64_ASMFL_ALIAS, {0, 0}}, - {"beq", MATCH_B(0x0, RV_BRANCH), MASK_B, RV64_FMT_B, 0, {0, 0}}, - {"bne", MATCH_B(0x1, RV_BRANCH), MASK_B, RV64_FMT_B, 0, {0, 0}}, - {"blt", MATCH_B(0x4, RV_BRANCH), MASK_B, RV64_FMT_B, 0, {0, 0}}, - {"bge", MATCH_B(0x5, RV_BRANCH), MASK_B, RV64_FMT_B, 0, {0, 0}}, - {"bltu", MATCH_B(0x6, RV_BRANCH), MASK_B, RV64_FMT_B, 0, {0, 0}}, - {"bgeu", MATCH_B(0x7, RV_BRANCH), MASK_B, RV64_FMT_B, 0, {0, 0}}, + {MN("beqz"), 0x00000063u, 0x01f0707fu, RV64_FMT_B, RV64_ASMFL_ALIAS, {0, 0}}, + {MN("bnez"), 0x00001063u, 0x01f0707fu, RV64_FMT_B, RV64_ASMFL_ALIAS, {0, 0}}, + {MN("beq"), MATCH_B(0x0, RV_BRANCH), MASK_B, RV64_FMT_B, 0, {0, 0}}, + {MN("bne"), MATCH_B(0x1, RV_BRANCH), MASK_B, RV64_FMT_B, 0, {0, 0}}, + {MN("blt"), MATCH_B(0x4, RV_BRANCH), MASK_B, RV64_FMT_B, 0, {0, 0}}, + {MN("bge"), MATCH_B(0x5, RV_BRANCH), MASK_B, RV64_FMT_B, 0, {0, 0}}, + {MN("bltu"), MATCH_B(0x6, RV_BRANCH), MASK_B, RV64_FMT_B, 0, {0, 0}}, + {MN("bgeu"), MATCH_B(0x7, RV_BRANCH), MASK_B, RV64_FMT_B, 0, {0, 0}}, /* ---- JAL / JALR ---- * `j off` = JAL x0, off (rd=x0). @@ -197,200 +206,200 @@ const Rv64InsnDesc rv64_insn_table[] = { * `ret` = JALR x0, 0(ra) (rd=x0 + rs1=ra + imm=0). * `jr rs` = JALR x0, 0(rs) (rd=x0, imm=0). * `jalr rs` = JALR ra, 0(rs) (rd=ra, imm=0). */ - {"ret", 0x00008067u, 0xffffffffu, RV64_FMT_SYSTEM, RV64_ASMFL_ALIAS, + {MN("ret"), 0x00008067u, 0xffffffffu, RV64_FMT_SYSTEM, RV64_ASMFL_ALIAS, {0, 0}}, - {"jr", 0x00000067u, 0xfff07fffu, RV64_FMT_JALR, RV64_ASMFL_ALIAS, + {MN("jr"), 0x00000067u, 0xfff07fffu, RV64_FMT_JALR, RV64_ASMFL_ALIAS, {0, 0}}, - {"j", 0x0000006fu, 0x00000fffu, RV64_FMT_J, RV64_ASMFL_ALIAS, {0, 0}}, - {"jal", MATCH_J(RV_JAL), MASK_J, RV64_FMT_J, 0, {0, 0}}, - {"jalr", MATCH_I(0x0, RV_JALR), MASK_I, RV64_FMT_JALR, 0, {0, 0}}, + {MN("j"), 0x0000006fu, 0x00000fffu, RV64_FMT_J, RV64_ASMFL_ALIAS, {0, 0}}, + {MN("jal"), MATCH_J(RV_JAL), MASK_J, RV64_FMT_J, 0, {0, 0}}, + {MN("jalr"), MATCH_I(0x0, RV_JALR), MASK_I, RV64_FMT_JALR, 0, {0, 0}}, /* ---- FENCE ---- */ - {"fence", MATCH_I(0x0, RV_FENCE), MASK_I, RV64_FMT_FENCE, 0, {0, 0}}, - {"fence.i", MATCH_FULL(0x0000100fu), MASK_FULL, RV64_FMT_SYSTEM, 0, + {MN("fence"), MATCH_I(0x0, RV_FENCE), MASK_I, RV64_FMT_FENCE, 0, {0, 0}}, + {MN("fence.i"), MATCH_FULL(0x0000100fu), MASK_FULL, RV64_FMT_SYSTEM, 0, {0, 0}}, /* ---- System (ECALL/EBREAK) ---- */ - {"ecall", MATCH_FULL(0x00000073u), MASK_FULL, RV64_FMT_SYSTEM, 0, + {MN("ecall"), MATCH_FULL(0x00000073u), MASK_FULL, RV64_FMT_SYSTEM, 0, {0, 0}}, - {"ebreak", MATCH_FULL(0x00100073u), MASK_FULL, RV64_FMT_SYSTEM, 0, + {MN("ebreak"), MATCH_FULL(0x00100073u), MASK_FULL, RV64_FMT_SYSTEM, 0, {0, 0}}, /* ================================================================= * Zicsr (CSR access) — RV_SYSTEM with funct3 ∈ {1..3, 5..7}. * ================================================================= */ - {"csrrw", MATCH_CSR(0x1), MASK_CSR, RV64_FMT_CSR, 0, {0, 0}}, - {"csrrs", MATCH_CSR(0x2), MASK_CSR, RV64_FMT_CSR, 0, {0, 0}}, - {"csrrc", MATCH_CSR(0x3), MASK_CSR, RV64_FMT_CSR, 0, {0, 0}}, - {"csrrwi", MATCH_CSR(0x5), MASK_CSR, RV64_FMT_CSRI, 0, {0, 0}}, - {"csrrsi", MATCH_CSR(0x6), MASK_CSR, RV64_FMT_CSRI, 0, {0, 0}}, - {"csrrci", MATCH_CSR(0x7), MASK_CSR, RV64_FMT_CSRI, 0, {0, 0}}, + {MN("csrrw"), MATCH_CSR(0x1), MASK_CSR, RV64_FMT_CSR, 0, {0, 0}}, + {MN("csrrs"), MATCH_CSR(0x2), MASK_CSR, RV64_FMT_CSR, 0, {0, 0}}, + {MN("csrrc"), MATCH_CSR(0x3), MASK_CSR, RV64_FMT_CSR, 0, {0, 0}}, + {MN("csrrwi"), MATCH_CSR(0x5), MASK_CSR, RV64_FMT_CSRI, 0, {0, 0}}, + {MN("csrrsi"), MATCH_CSR(0x6), MASK_CSR, RV64_FMT_CSRI, 0, {0, 0}}, + {MN("csrrci"), MATCH_CSR(0x7), MASK_CSR, RV64_FMT_CSRI, 0, {0, 0}}, /* ================================================================= * RV64M (multiply / divide) — funct7 = 0x01 * ================================================================= */ - {"mul", MATCH_R(0x01, 0x0, RV_OP), MASK_R, RV64_FMT_R, 0, {0, 0}}, - {"mulh", MATCH_R(0x01, 0x1, RV_OP), MASK_R, RV64_FMT_R, 0, {0, 0}}, - {"mulhsu", MATCH_R(0x01, 0x2, RV_OP), MASK_R, RV64_FMT_R, 0, {0, 0}}, - {"mulhu", MATCH_R(0x01, 0x3, RV_OP), MASK_R, RV64_FMT_R, 0, {0, 0}}, - {"div", MATCH_R(0x01, 0x4, RV_OP), MASK_R, RV64_FMT_R, 0, {0, 0}}, - {"divu", MATCH_R(0x01, 0x5, RV_OP), MASK_R, RV64_FMT_R, 0, {0, 0}}, - {"rem", MATCH_R(0x01, 0x6, RV_OP), MASK_R, RV64_FMT_R, 0, {0, 0}}, - {"remu", MATCH_R(0x01, 0x7, RV_OP), MASK_R, RV64_FMT_R, 0, {0, 0}}, - {"mulw", MATCH_R(0x01, 0x0, RV_OP_32), MASK_R, RV64_FMT_R, 0, {0, 0}}, - {"divw", MATCH_R(0x01, 0x4, RV_OP_32), MASK_R, RV64_FMT_R, 0, {0, 0}}, - {"divuw", MATCH_R(0x01, 0x5, RV_OP_32), MASK_R, RV64_FMT_R, 0, {0, 0}}, - {"remw", MATCH_R(0x01, 0x6, RV_OP_32), MASK_R, RV64_FMT_R, 0, {0, 0}}, - {"remuw", MATCH_R(0x01, 0x7, RV_OP_32), MASK_R, RV64_FMT_R, 0, {0, 0}}, + {MN("mul"), MATCH_R(0x01, 0x0, RV_OP), MASK_R, RV64_FMT_R, 0, {0, 0}}, + {MN("mulh"), MATCH_R(0x01, 0x1, RV_OP), MASK_R, RV64_FMT_R, 0, {0, 0}}, + {MN("mulhsu"), MATCH_R(0x01, 0x2, RV_OP), MASK_R, RV64_FMT_R, 0, {0, 0}}, + {MN("mulhu"), MATCH_R(0x01, 0x3, RV_OP), MASK_R, RV64_FMT_R, 0, {0, 0}}, + {MN("div"), MATCH_R(0x01, 0x4, RV_OP), MASK_R, RV64_FMT_R, 0, {0, 0}}, + {MN("divu"), MATCH_R(0x01, 0x5, RV_OP), MASK_R, RV64_FMT_R, 0, {0, 0}}, + {MN("rem"), MATCH_R(0x01, 0x6, RV_OP), MASK_R, RV64_FMT_R, 0, {0, 0}}, + {MN("remu"), MATCH_R(0x01, 0x7, RV_OP), MASK_R, RV64_FMT_R, 0, {0, 0}}, + {MN("mulw"), MATCH_R(0x01, 0x0, RV_OP_32), MASK_R, RV64_FMT_R, 0, {0, 0}}, + {MN("divw"), MATCH_R(0x01, 0x4, RV_OP_32), MASK_R, RV64_FMT_R, 0, {0, 0}}, + {MN("divuw"), MATCH_R(0x01, 0x5, RV_OP_32), MASK_R, RV64_FMT_R, 0, {0, 0}}, + {MN("remw"), MATCH_R(0x01, 0x6, RV_OP_32), MASK_R, RV64_FMT_R, 0, {0, 0}}, + {MN("remuw"), MATCH_R(0x01, 0x7, RV_OP_32), MASK_R, RV64_FMT_R, 0, {0, 0}}, /* ================================================================= * RV32F / RV32D — single and double precision FP * ================================================================= */ /* FP fused multiply-add/subtract — rm defaults to dyn in the assembler. */ - {"fmadd.s", MATCH_R4(RV_FMT_S, RV_MADD), MASK_R4, RV64_FMT_R4, + {MN("fmadd.s"), MATCH_R4(RV_FMT_S, RV_MADD), MASK_R4, RV64_FMT_R4, RV64_ASMFL_FP, {0, 0}}, - {"fmsub.s", MATCH_R4(RV_FMT_S, RV_MSUB), MASK_R4, RV64_FMT_R4, + {MN("fmsub.s"), MATCH_R4(RV_FMT_S, RV_MSUB), MASK_R4, RV64_FMT_R4, RV64_ASMFL_FP, {0, 0}}, - {"fnmsub.s", MATCH_R4(RV_FMT_S, RV_NMSUB), MASK_R4, RV64_FMT_R4, + {MN("fnmsub.s"), MATCH_R4(RV_FMT_S, RV_NMSUB), MASK_R4, RV64_FMT_R4, RV64_ASMFL_FP, {0, 0}}, - {"fnmadd.s", MATCH_R4(RV_FMT_S, RV_NMADD), MASK_R4, RV64_FMT_R4, + {MN("fnmadd.s"), MATCH_R4(RV_FMT_S, RV_NMADD), MASK_R4, RV64_FMT_R4, RV64_ASMFL_FP, {0, 0}}, - {"fmadd.d", MATCH_R4(RV_FMT_D, RV_MADD), MASK_R4, RV64_FMT_R4, + {MN("fmadd.d"), MATCH_R4(RV_FMT_D, RV_MADD), MASK_R4, RV64_FMT_R4, RV64_ASMFL_FP, {0, 0}}, - {"fmsub.d", MATCH_R4(RV_FMT_D, RV_MSUB), MASK_R4, RV64_FMT_R4, + {MN("fmsub.d"), MATCH_R4(RV_FMT_D, RV_MSUB), MASK_R4, RV64_FMT_R4, RV64_ASMFL_FP, {0, 0}}, - {"fnmsub.d", MATCH_R4(RV_FMT_D, RV_NMSUB), MASK_R4, RV64_FMT_R4, + {MN("fnmsub.d"), MATCH_R4(RV_FMT_D, RV_NMSUB), MASK_R4, RV64_FMT_R4, RV64_ASMFL_FP, {0, 0}}, - {"fnmadd.d", MATCH_R4(RV_FMT_D, RV_NMADD), MASK_R4, RV64_FMT_R4, + {MN("fnmadd.d"), MATCH_R4(RV_FMT_D, RV_NMADD), MASK_R4, RV64_FMT_R4, RV64_ASMFL_FP, {0, 0}}, /* FP arithmetic — rm field (funct3) is the rounding mode and prints * as the DYN(=7) default suppressed. funct7 low bits select fmt. */ - {"fadd.s", MATCH_FP_RM(0x00, RV_OP_FP), MASK_FP_RM, RV64_FMT_FP_RM, + {MN("fadd.s"), MATCH_FP_RM(0x00, RV_OP_FP), MASK_FP_RM, RV64_FMT_FP_RM, RV64_ASMFL_FP, {0, 0}}, - {"fsub.s", MATCH_FP_RM(0x04, RV_OP_FP), MASK_FP_RM, RV64_FMT_FP_RM, + {MN("fsub.s"), MATCH_FP_RM(0x04, RV_OP_FP), MASK_FP_RM, RV64_FMT_FP_RM, RV64_ASMFL_FP, {0, 0}}, - {"fmul.s", MATCH_FP_RM(0x08, RV_OP_FP), MASK_FP_RM, RV64_FMT_FP_RM, + {MN("fmul.s"), MATCH_FP_RM(0x08, RV_OP_FP), MASK_FP_RM, RV64_FMT_FP_RM, RV64_ASMFL_FP, {0, 0}}, - {"fdiv.s", MATCH_FP_RM(0x0c, RV_OP_FP), MASK_FP_RM, RV64_FMT_FP_RM, + {MN("fdiv.s"), MATCH_FP_RM(0x0c, RV_OP_FP), MASK_FP_RM, RV64_FMT_FP_RM, RV64_ASMFL_FP, {0, 0}}, - {"fadd.d", MATCH_FP_RM(0x01, RV_OP_FP), MASK_FP_RM, RV64_FMT_FP_RM, + {MN("fadd.d"), MATCH_FP_RM(0x01, RV_OP_FP), MASK_FP_RM, RV64_FMT_FP_RM, RV64_ASMFL_FP, {0, 0}}, - {"fsub.d", MATCH_FP_RM(0x05, RV_OP_FP), MASK_FP_RM, RV64_FMT_FP_RM, + {MN("fsub.d"), MATCH_FP_RM(0x05, RV_OP_FP), MASK_FP_RM, RV64_FMT_FP_RM, RV64_ASMFL_FP, {0, 0}}, - {"fmul.d", MATCH_FP_RM(0x09, RV_OP_FP), MASK_FP_RM, RV64_FMT_FP_RM, + {MN("fmul.d"), MATCH_FP_RM(0x09, RV_OP_FP), MASK_FP_RM, RV64_FMT_FP_RM, RV64_ASMFL_FP, {0, 0}}, - {"fdiv.d", MATCH_FP_RM(0x0d, RV_OP_FP), MASK_FP_RM, RV64_FMT_FP_RM, + {MN("fdiv.d"), MATCH_FP_RM(0x0d, RV_OP_FP), MASK_FP_RM, RV64_FMT_FP_RM, RV64_ASMFL_FP, {0, 0}}, /* FP sqrt — funct7 = 0x2c (S) / 0x2d (D), rs2 must be 0. */ - {"fsqrt.s", MATCH_FP_CVT(0x2c, 0x0, RV_OP_FP), MASK_FP_CVT, + {MN("fsqrt.s"), MATCH_FP_CVT(0x2c, 0x0, RV_OP_FP), MASK_FP_CVT, RV64_FMT_FP_CVT, RV64_ASMFL_FP, {0, 0}}, - {"fsqrt.d", MATCH_FP_CVT(0x2d, 0x0, RV_OP_FP), MASK_FP_CVT, + {MN("fsqrt.d"), MATCH_FP_CVT(0x2d, 0x0, RV_OP_FP), MASK_FP_CVT, RV64_FMT_FP_CVT, RV64_ASMFL_FP, {0, 0}}, /* FP min/max — funct7 = 0x14/0x15, funct3 = 0 (min) / 1 (max). */ - {"fmin.s", MATCH_FP_R(0x14, 0x0, RV_OP_FP), MASK_FP_R, RV64_FMT_FP_R, + {MN("fmin.s"), MATCH_FP_R(0x14, 0x0, RV_OP_FP), MASK_FP_R, RV64_FMT_FP_R, RV64_ASMFL_FP | RV64_ASMFL_NORM, {0, 0}}, - {"fmax.s", MATCH_FP_R(0x14, 0x1, RV_OP_FP), MASK_FP_R, RV64_FMT_FP_R, + {MN("fmax.s"), MATCH_FP_R(0x14, 0x1, RV_OP_FP), MASK_FP_R, RV64_FMT_FP_R, RV64_ASMFL_FP | RV64_ASMFL_NORM, {0, 0}}, - {"fmin.d", MATCH_FP_R(0x15, 0x0, RV_OP_FP), MASK_FP_R, RV64_FMT_FP_R, + {MN("fmin.d"), MATCH_FP_R(0x15, 0x0, RV_OP_FP), MASK_FP_R, RV64_FMT_FP_R, RV64_ASMFL_FP | RV64_ASMFL_NORM, {0, 0}}, - {"fmax.d", MATCH_FP_R(0x15, 0x1, RV_OP_FP), MASK_FP_R, RV64_FMT_FP_R, + {MN("fmax.d"), MATCH_FP_R(0x15, 0x1, RV_OP_FP), MASK_FP_R, RV64_FMT_FP_R, RV64_ASMFL_FP | RV64_ASMFL_NORM, {0, 0}}, /* FP sign-injection — funct7 = 0x10/0x11, funct3 = 0/1/2 = J/JN/JX. */ - {"fsgnj.s", MATCH_FP_R(0x10, 0x0, RV_OP_FP), MASK_FP_R, RV64_FMT_FP_R, + {MN("fsgnj.s"), MATCH_FP_R(0x10, 0x0, RV_OP_FP), MASK_FP_R, RV64_FMT_FP_R, RV64_ASMFL_FP | RV64_ASMFL_NORM, {0, 0}}, - {"fsgnjn.s", MATCH_FP_R(0x10, 0x1, RV_OP_FP), MASK_FP_R, RV64_FMT_FP_R, + {MN("fsgnjn.s"), MATCH_FP_R(0x10, 0x1, RV_OP_FP), MASK_FP_R, RV64_FMT_FP_R, RV64_ASMFL_FP | RV64_ASMFL_NORM, {0, 0}}, - {"fsgnjx.s", MATCH_FP_R(0x10, 0x2, RV_OP_FP), MASK_FP_R, RV64_FMT_FP_R, + {MN("fsgnjx.s"), MATCH_FP_R(0x10, 0x2, RV_OP_FP), MASK_FP_R, RV64_FMT_FP_R, RV64_ASMFL_FP | RV64_ASMFL_NORM, {0, 0}}, - {"fsgnj.d", MATCH_FP_R(0x11, 0x0, RV_OP_FP), MASK_FP_R, RV64_FMT_FP_R, + {MN("fsgnj.d"), MATCH_FP_R(0x11, 0x0, RV_OP_FP), MASK_FP_R, RV64_FMT_FP_R, RV64_ASMFL_FP | RV64_ASMFL_NORM, {0, 0}}, - {"fsgnjn.d", MATCH_FP_R(0x11, 0x1, RV_OP_FP), MASK_FP_R, RV64_FMT_FP_R, + {MN("fsgnjn.d"), MATCH_FP_R(0x11, 0x1, RV_OP_FP), MASK_FP_R, RV64_FMT_FP_R, RV64_ASMFL_FP | RV64_ASMFL_NORM, {0, 0}}, - {"fsgnjx.d", MATCH_FP_R(0x11, 0x2, RV_OP_FP), MASK_FP_R, RV64_FMT_FP_R, + {MN("fsgnjx.d"), MATCH_FP_R(0x11, 0x2, RV_OP_FP), MASK_FP_R, RV64_FMT_FP_R, RV64_ASMFL_FP | RV64_ASMFL_NORM, {0, 0}}, /* FP compare — funct7 = 0x50 (S) / 0x51 (D), funct3 = 0/1/2 = LE/LT/EQ. * rd is integer GPR (not FP). */ - {"fle.s", MATCH_FP_R(0x50, 0x0, RV_OP_FP), MASK_FP_R, RV64_FMT_FP_R, + {MN("fle.s"), MATCH_FP_R(0x50, 0x0, RV_OP_FP), MASK_FP_R, RV64_FMT_FP_R, RV64_ASMFL_NORM, {0, 0}}, - {"flt.s", MATCH_FP_R(0x50, 0x1, RV_OP_FP), MASK_FP_R, RV64_FMT_FP_R, + {MN("flt.s"), MATCH_FP_R(0x50, 0x1, RV_OP_FP), MASK_FP_R, RV64_FMT_FP_R, RV64_ASMFL_NORM, {0, 0}}, - {"feq.s", MATCH_FP_R(0x50, 0x2, RV_OP_FP), MASK_FP_R, RV64_FMT_FP_R, + {MN("feq.s"), MATCH_FP_R(0x50, 0x2, RV_OP_FP), MASK_FP_R, RV64_FMT_FP_R, RV64_ASMFL_NORM, {0, 0}}, - {"fle.d", MATCH_FP_R(0x51, 0x0, RV_OP_FP), MASK_FP_R, RV64_FMT_FP_R, + {MN("fle.d"), MATCH_FP_R(0x51, 0x0, RV_OP_FP), MASK_FP_R, RV64_FMT_FP_R, RV64_ASMFL_NORM, {0, 0}}, - {"flt.d", MATCH_FP_R(0x51, 0x1, RV_OP_FP), MASK_FP_R, RV64_FMT_FP_R, + {MN("flt.d"), MATCH_FP_R(0x51, 0x1, RV_OP_FP), MASK_FP_R, RV64_FMT_FP_R, RV64_ASMFL_NORM, {0, 0}}, - {"feq.d", MATCH_FP_R(0x51, 0x2, RV_OP_FP), MASK_FP_R, RV64_FMT_FP_R, + {MN("feq.d"), MATCH_FP_R(0x51, 0x2, RV_OP_FP), MASK_FP_R, RV64_FMT_FP_R, RV64_ASMFL_NORM, {0, 0}}, /* FP classification — rd is GPR, rs1 is FPR, rs2=0, rm/funct3=1. */ - {"fclass.s", MATCH_FP_R(0x70, 0x1, RV_OP_FP) | (0u << 20), + {MN("fclass.s"), MATCH_FP_R(0x70, 0x1, RV_OP_FP) | (0u << 20), MASK_FP_CVT | (7u << 12), RV64_FMT_FP_CVT, 0, {0, 0}}, - {"fclass.d", MATCH_FP_R(0x71, 0x1, RV_OP_FP) | (0u << 20), + {MN("fclass.d"), MATCH_FP_R(0x71, 0x1, RV_OP_FP) | (0u << 20), MASK_FP_CVT | (7u << 12), RV64_FMT_FP_CVT, 0, {0, 0}}, /* FP conversions — funct7 selects {direction, fmt}, rs2 selects * integer width/signedness. */ - {"fcvt.w.s", MATCH_FP_CVT(0x60, 0x0, RV_OP_FP), MASK_FP_CVT, + {MN("fcvt.w.s"), MATCH_FP_CVT(0x60, 0x0, RV_OP_FP), MASK_FP_CVT, RV64_FMT_FP_CVT, 0, {0, 0}}, - {"fcvt.wu.s", MATCH_FP_CVT(0x60, 0x1, RV_OP_FP), MASK_FP_CVT, + {MN("fcvt.wu.s"), MATCH_FP_CVT(0x60, 0x1, RV_OP_FP), MASK_FP_CVT, RV64_FMT_FP_CVT, 0, {0, 0}}, - {"fcvt.l.s", MATCH_FP_CVT(0x60, 0x2, RV_OP_FP), MASK_FP_CVT, + {MN("fcvt.l.s"), MATCH_FP_CVT(0x60, 0x2, RV_OP_FP), MASK_FP_CVT, RV64_FMT_FP_CVT, 0, {0, 0}}, - {"fcvt.lu.s", MATCH_FP_CVT(0x60, 0x3, RV_OP_FP), MASK_FP_CVT, + {MN("fcvt.lu.s"), MATCH_FP_CVT(0x60, 0x3, RV_OP_FP), MASK_FP_CVT, RV64_FMT_FP_CVT, 0, {0, 0}}, - {"fcvt.w.d", MATCH_FP_CVT(0x61, 0x0, RV_OP_FP), MASK_FP_CVT, + {MN("fcvt.w.d"), MATCH_FP_CVT(0x61, 0x0, RV_OP_FP), MASK_FP_CVT, RV64_FMT_FP_CVT, 0, {0, 0}}, - {"fcvt.wu.d", MATCH_FP_CVT(0x61, 0x1, RV_OP_FP), MASK_FP_CVT, + {MN("fcvt.wu.d"), MATCH_FP_CVT(0x61, 0x1, RV_OP_FP), MASK_FP_CVT, RV64_FMT_FP_CVT, 0, {0, 0}}, - {"fcvt.l.d", MATCH_FP_CVT(0x61, 0x2, RV_OP_FP), MASK_FP_CVT, + {MN("fcvt.l.d"), MATCH_FP_CVT(0x61, 0x2, RV_OP_FP), MASK_FP_CVT, RV64_FMT_FP_CVT, 0, {0, 0}}, - {"fcvt.lu.d", MATCH_FP_CVT(0x61, 0x3, RV_OP_FP), MASK_FP_CVT, + {MN("fcvt.lu.d"), MATCH_FP_CVT(0x61, 0x3, RV_OP_FP), MASK_FP_CVT, RV64_FMT_FP_CVT, 0, {0, 0}}, - {"fcvt.s.w", MATCH_FP_CVT(0x68, 0x0, RV_OP_FP), MASK_FP_CVT, + {MN("fcvt.s.w"), MATCH_FP_CVT(0x68, 0x0, RV_OP_FP), MASK_FP_CVT, RV64_FMT_FP_CVT, RV64_ASMFL_FP, {0, 0}}, - {"fcvt.s.wu", MATCH_FP_CVT(0x68, 0x1, RV_OP_FP), MASK_FP_CVT, + {MN("fcvt.s.wu"), MATCH_FP_CVT(0x68, 0x1, RV_OP_FP), MASK_FP_CVT, RV64_FMT_FP_CVT, RV64_ASMFL_FP, {0, 0}}, - {"fcvt.s.l", MATCH_FP_CVT(0x68, 0x2, RV_OP_FP), MASK_FP_CVT, + {MN("fcvt.s.l"), MATCH_FP_CVT(0x68, 0x2, RV_OP_FP), MASK_FP_CVT, RV64_FMT_FP_CVT, RV64_ASMFL_FP, {0, 0}}, - {"fcvt.s.lu", MATCH_FP_CVT(0x68, 0x3, RV_OP_FP), MASK_FP_CVT, + {MN("fcvt.s.lu"), MATCH_FP_CVT(0x68, 0x3, RV_OP_FP), MASK_FP_CVT, RV64_FMT_FP_CVT, RV64_ASMFL_FP, {0, 0}}, - {"fcvt.d.w", MATCH_FP_CVT(0x69, 0x0, RV_OP_FP), MASK_FP_CVT, + {MN("fcvt.d.w"), MATCH_FP_CVT(0x69, 0x0, RV_OP_FP), MASK_FP_CVT, RV64_FMT_FP_CVT, RV64_ASMFL_FP, {0, 0}}, - {"fcvt.d.wu", MATCH_FP_CVT(0x69, 0x1, RV_OP_FP), MASK_FP_CVT, + {MN("fcvt.d.wu"), MATCH_FP_CVT(0x69, 0x1, RV_OP_FP), MASK_FP_CVT, RV64_FMT_FP_CVT, RV64_ASMFL_FP, {0, 0}}, - {"fcvt.d.l", MATCH_FP_CVT(0x69, 0x2, RV_OP_FP), MASK_FP_CVT, + {MN("fcvt.d.l"), MATCH_FP_CVT(0x69, 0x2, RV_OP_FP), MASK_FP_CVT, RV64_FMT_FP_CVT, RV64_ASMFL_FP, {0, 0}}, - {"fcvt.d.lu", MATCH_FP_CVT(0x69, 0x3, RV_OP_FP), MASK_FP_CVT, + {MN("fcvt.d.lu"), MATCH_FP_CVT(0x69, 0x3, RV_OP_FP), MASK_FP_CVT, RV64_FMT_FP_CVT, RV64_ASMFL_FP, {0, 0}}, - {"fcvt.s.d", MATCH_FP_CVT(0x20, 0x1, RV_OP_FP), MASK_FP_CVT, + {MN("fcvt.s.d"), MATCH_FP_CVT(0x20, 0x1, RV_OP_FP), MASK_FP_CVT, RV64_FMT_FP_CVT, RV64_ASMFL_FP, {0, 0}}, - {"fcvt.d.s", MATCH_FP_CVT(0x21, 0x0, RV_OP_FP), MASK_FP_CVT, + {MN("fcvt.d.s"), MATCH_FP_CVT(0x21, 0x0, RV_OP_FP), MASK_FP_CVT, RV64_FMT_FP_CVT, RV64_ASMFL_FP, {0, 0}}, /* FP bitcast moves — funct7 + rs2=0 + funct3=0 fixed. */ - {"fmv.x.w", MATCH_FP_CVT(0x70, 0x0, RV_OP_FP), MASK_FP_CVT, + {MN("fmv.x.w"), MATCH_FP_CVT(0x70, 0x0, RV_OP_FP), MASK_FP_CVT, RV64_FMT_FP_CVT, 0, {0, 0}}, - {"fmv.w.x", MATCH_FP_CVT(0x78, 0x0, RV_OP_FP), MASK_FP_CVT, + {MN("fmv.w.x"), MATCH_FP_CVT(0x78, 0x0, RV_OP_FP), MASK_FP_CVT, RV64_FMT_FP_CVT, RV64_ASMFL_FP, {0, 0}}, - {"fmv.x.d", MATCH_FP_CVT(0x71, 0x0, RV_OP_FP), MASK_FP_CVT, + {MN("fmv.x.d"), MATCH_FP_CVT(0x71, 0x0, RV_OP_FP), MASK_FP_CVT, RV64_FMT_FP_CVT, 0, {0, 0}}, - {"fmv.d.x", MATCH_FP_CVT(0x79, 0x0, RV_OP_FP), MASK_FP_CVT, + {MN("fmv.d.x"), MATCH_FP_CVT(0x79, 0x0, RV_OP_FP), MASK_FP_CVT, RV64_FMT_FP_CVT, RV64_ASMFL_FP, {0, 0}}, /* FP load/store */ - {"flw", MATCH_I(0x2, RV_LOAD_FP), MASK_I, RV64_FMT_FP_LOAD, + {MN("flw"), MATCH_I(0x2, RV_LOAD_FP), MASK_I, RV64_FMT_FP_LOAD, RV64_ASMFL_FP, {0, 0}}, - {"fld", MATCH_I(0x3, RV_LOAD_FP), MASK_I, RV64_FMT_FP_LOAD, + {MN("fld"), MATCH_I(0x3, RV_LOAD_FP), MASK_I, RV64_FMT_FP_LOAD, RV64_ASMFL_FP, {0, 0}}, - {"fsw", MATCH_S(0x2, RV_STORE_FP), MASK_S, RV64_FMT_FP_STORE, + {MN("fsw"), MATCH_S(0x2, RV_STORE_FP), MASK_S, RV64_FMT_FP_STORE, RV64_ASMFL_FP, {0, 0}}, - {"fsd", MATCH_S(0x3, RV_STORE_FP), MASK_S, RV64_FMT_FP_STORE, + {MN("fsd"), MATCH_S(0x3, RV_STORE_FP), MASK_S, RV64_FMT_FP_STORE, RV64_ASMFL_FP, {0, 0}}, /* ================================================================= @@ -399,36 +408,36 @@ const Rv64InsnDesc rv64_insn_table[] = { * suffixes via the disassembler's annotation, but the row mnemonic * itself is the bare form (e.g. "amoadd.w"). * ================================================================= */ - {"lr.w.aq", MATCH_AMO_ORDER(0x02, 1, 0, 0x2, RV_AMO), + {MN("lr.w.aq"), MATCH_AMO_ORDER(0x02, 1, 0, 0x2, RV_AMO), MASK_AMO_ORDER | (0x1fu << 20), RV64_FMT_LR, 0, {0, 0}}, - {"lr.w.rl", MATCH_AMO_ORDER(0x02, 0, 1, 0x2, RV_AMO), + {MN("lr.w.rl"), MATCH_AMO_ORDER(0x02, 0, 1, 0x2, RV_AMO), MASK_AMO_ORDER | (0x1fu << 20), RV64_FMT_LR, 0, {0, 0}}, - {"lr.w.aqrl", MATCH_AMO_ORDER(0x02, 1, 1, 0x2, RV_AMO), + {MN("lr.w.aqrl"), MATCH_AMO_ORDER(0x02, 1, 1, 0x2, RV_AMO), MASK_AMO_ORDER | (0x1fu << 20), RV64_FMT_LR, 0, {0, 0}}, - {"lr.d.aq", MATCH_AMO_ORDER(0x02, 1, 0, 0x3, RV_AMO), + {MN("lr.d.aq"), MATCH_AMO_ORDER(0x02, 1, 0, 0x3, RV_AMO), MASK_AMO_ORDER | (0x1fu << 20), RV64_FMT_LR, 0, {0, 0}}, - {"lr.d.rl", MATCH_AMO_ORDER(0x02, 0, 1, 0x3, RV_AMO), + {MN("lr.d.rl"), MATCH_AMO_ORDER(0x02, 0, 1, 0x3, RV_AMO), MASK_AMO_ORDER | (0x1fu << 20), RV64_FMT_LR, 0, {0, 0}}, - {"lr.d.aqrl", MATCH_AMO_ORDER(0x02, 1, 1, 0x3, RV_AMO), + {MN("lr.d.aqrl"), MATCH_AMO_ORDER(0x02, 1, 1, 0x3, RV_AMO), MASK_AMO_ORDER | (0x1fu << 20), RV64_FMT_LR, 0, {0, 0}}, - {"sc.w.aq", MATCH_AMO_ORDER(0x03, 1, 0, 0x2, RV_AMO), + {MN("sc.w.aq"), MATCH_AMO_ORDER(0x03, 1, 0, 0x2, RV_AMO), MASK_AMO_ORDER, RV64_FMT_AMO, 0, {0, 0}}, - {"sc.w.rl", MATCH_AMO_ORDER(0x03, 0, 1, 0x2, RV_AMO), + {MN("sc.w.rl"), MATCH_AMO_ORDER(0x03, 0, 1, 0x2, RV_AMO), MASK_AMO_ORDER, RV64_FMT_AMO, 0, {0, 0}}, - {"sc.w.aqrl", MATCH_AMO_ORDER(0x03, 1, 1, 0x2, RV_AMO), + {MN("sc.w.aqrl"), MATCH_AMO_ORDER(0x03, 1, 1, 0x2, RV_AMO), MASK_AMO_ORDER, RV64_FMT_AMO, 0, {0, 0}}, - {"sc.d.aq", MATCH_AMO_ORDER(0x03, 1, 0, 0x3, RV_AMO), + {MN("sc.d.aq"), MATCH_AMO_ORDER(0x03, 1, 0, 0x3, RV_AMO), MASK_AMO_ORDER, RV64_FMT_AMO, 0, {0, 0}}, - {"sc.d.rl", MATCH_AMO_ORDER(0x03, 0, 1, 0x3, RV_AMO), + {MN("sc.d.rl"), MATCH_AMO_ORDER(0x03, 0, 1, 0x3, RV_AMO), MASK_AMO_ORDER, RV64_FMT_AMO, 0, {0, 0}}, - {"sc.d.aqrl", MATCH_AMO_ORDER(0x03, 1, 1, 0x3, RV_AMO), + {MN("sc.d.aqrl"), MATCH_AMO_ORDER(0x03, 1, 1, 0x3, RV_AMO), MASK_AMO_ORDER, RV64_FMT_AMO, 0, {0, 0}}, #define RV64_AMO_ORDER_ROWS(mn, f5, f3) \ - {mn ".aq", MATCH_AMO_ORDER(f5, 1, 0, f3, RV_AMO), MASK_AMO_ORDER, \ + {MN(mn ".aq"), MATCH_AMO_ORDER(f5, 1, 0, f3, RV_AMO), MASK_AMO_ORDER, \ RV64_FMT_AMO, 0, {0, 0}}, \ - {mn ".rl", MATCH_AMO_ORDER(f5, 0, 1, f3, RV_AMO), MASK_AMO_ORDER, \ + {MN(mn ".rl"), MATCH_AMO_ORDER(f5, 0, 1, f3, RV_AMO), MASK_AMO_ORDER, \ RV64_FMT_AMO, 0, {0, 0}}, \ - {mn ".aqrl", MATCH_AMO_ORDER(f5, 1, 1, f3, RV_AMO), MASK_AMO_ORDER, \ + {MN(mn ".aqrl"), MATCH_AMO_ORDER(f5, 1, 1, f3, RV_AMO), MASK_AMO_ORDER, \ RV64_FMT_AMO, 0, {0, 0}} RV64_AMO_ORDER_ROWS("amoswap.w", RV_AMO_SWAP, 0x2), RV64_AMO_ORDER_ROWS("amoadd.w", RV_AMO_ADD, 0x2), @@ -448,101 +457,101 @@ const Rv64InsnDesc rv64_insn_table[] = { RV64_AMO_ORDER_ROWS("amomax.d", RV_AMO_MAX, 0x3), RV64_AMO_ORDER_ROWS("amominu.d", RV_AMO_MINU, 0x3), RV64_AMO_ORDER_ROWS("amomaxu.d", RV_AMO_MAXU, 0x3), - {"lr.w", MATCH_AMO(0x02, 0x2, RV_AMO), MASK_AMO | (0x1fu << 20), + {MN("lr.w"), MATCH_AMO(0x02, 0x2, RV_AMO), MASK_AMO | (0x1fu << 20), RV64_FMT_LR, 0, {0, 0}}, - {"lr.d", MATCH_AMO(0x02, 0x3, RV_AMO), MASK_AMO | (0x1fu << 20), + {MN("lr.d"), MATCH_AMO(0x02, 0x3, RV_AMO), MASK_AMO | (0x1fu << 20), RV64_FMT_LR, 0, {0, 0}}, - {"sc.w", MATCH_AMO(0x03, 0x2, RV_AMO), MASK_AMO, RV64_FMT_AMO, 0, + {MN("sc.w"), MATCH_AMO(0x03, 0x2, RV_AMO), MASK_AMO, RV64_FMT_AMO, 0, {0, 0}}, - {"sc.d", MATCH_AMO(0x03, 0x3, RV_AMO), MASK_AMO, RV64_FMT_AMO, 0, + {MN("sc.d"), MATCH_AMO(0x03, 0x3, RV_AMO), MASK_AMO, RV64_FMT_AMO, 0, {0, 0}}, - {"amoswap.w", MATCH_AMO(RV_AMO_SWAP, 0x2, RV_AMO), MASK_AMO, + {MN("amoswap.w"), MATCH_AMO(RV_AMO_SWAP, 0x2, RV_AMO), MASK_AMO, RV64_FMT_AMO, 0, {0, 0}}, - {"amoadd.w", MATCH_AMO(RV_AMO_ADD, 0x2, RV_AMO), MASK_AMO, + {MN("amoadd.w"), MATCH_AMO(RV_AMO_ADD, 0x2, RV_AMO), MASK_AMO, RV64_FMT_AMO, 0, {0, 0}}, - {"amoxor.w", MATCH_AMO(RV_AMO_XOR, 0x2, RV_AMO), MASK_AMO, + {MN("amoxor.w"), MATCH_AMO(RV_AMO_XOR, 0x2, RV_AMO), MASK_AMO, RV64_FMT_AMO, 0, {0, 0}}, - {"amoand.w", MATCH_AMO(RV_AMO_AND, 0x2, RV_AMO), MASK_AMO, + {MN("amoand.w"), MATCH_AMO(RV_AMO_AND, 0x2, RV_AMO), MASK_AMO, RV64_FMT_AMO, 0, {0, 0}}, - {"amoor.w", MATCH_AMO(RV_AMO_OR, 0x2, RV_AMO), MASK_AMO, + {MN("amoor.w"), MATCH_AMO(RV_AMO_OR, 0x2, RV_AMO), MASK_AMO, RV64_FMT_AMO, 0, {0, 0}}, - {"amomin.w", MATCH_AMO(RV_AMO_MIN, 0x2, RV_AMO), MASK_AMO, + {MN("amomin.w"), MATCH_AMO(RV_AMO_MIN, 0x2, RV_AMO), MASK_AMO, RV64_FMT_AMO, 0, {0, 0}}, - {"amomax.w", MATCH_AMO(RV_AMO_MAX, 0x2, RV_AMO), MASK_AMO, + {MN("amomax.w"), MATCH_AMO(RV_AMO_MAX, 0x2, RV_AMO), MASK_AMO, RV64_FMT_AMO, 0, {0, 0}}, - {"amominu.w", MATCH_AMO(RV_AMO_MINU, 0x2, RV_AMO), MASK_AMO, + {MN("amominu.w"), MATCH_AMO(RV_AMO_MINU, 0x2, RV_AMO), MASK_AMO, RV64_FMT_AMO, 0, {0, 0}}, - {"amomaxu.w", MATCH_AMO(RV_AMO_MAXU, 0x2, RV_AMO), MASK_AMO, + {MN("amomaxu.w"), MATCH_AMO(RV_AMO_MAXU, 0x2, RV_AMO), MASK_AMO, RV64_FMT_AMO, 0, {0, 0}}, - {"amoswap.d", MATCH_AMO(RV_AMO_SWAP, 0x3, RV_AMO), MASK_AMO, + {MN("amoswap.d"), MATCH_AMO(RV_AMO_SWAP, 0x3, RV_AMO), MASK_AMO, RV64_FMT_AMO, 0, {0, 0}}, - {"amoadd.d", MATCH_AMO(RV_AMO_ADD, 0x3, RV_AMO), MASK_AMO, + {MN("amoadd.d"), MATCH_AMO(RV_AMO_ADD, 0x3, RV_AMO), MASK_AMO, RV64_FMT_AMO, 0, {0, 0}}, - {"amoxor.d", MATCH_AMO(RV_AMO_XOR, 0x3, RV_AMO), MASK_AMO, + {MN("amoxor.d"), MATCH_AMO(RV_AMO_XOR, 0x3, RV_AMO), MASK_AMO, RV64_FMT_AMO, 0, {0, 0}}, - {"amoand.d", MATCH_AMO(RV_AMO_AND, 0x3, RV_AMO), MASK_AMO, + {MN("amoand.d"), MATCH_AMO(RV_AMO_AND, 0x3, RV_AMO), MASK_AMO, RV64_FMT_AMO, 0, {0, 0}}, - {"amoor.d", MATCH_AMO(RV_AMO_OR, 0x3, RV_AMO), MASK_AMO, + {MN("amoor.d"), MATCH_AMO(RV_AMO_OR, 0x3, RV_AMO), MASK_AMO, RV64_FMT_AMO, 0, {0, 0}}, - {"amomin.d", MATCH_AMO(RV_AMO_MIN, 0x3, RV_AMO), MASK_AMO, + {MN("amomin.d"), MATCH_AMO(RV_AMO_MIN, 0x3, RV_AMO), MASK_AMO, RV64_FMT_AMO, 0, {0, 0}}, - {"amomax.d", MATCH_AMO(RV_AMO_MAX, 0x3, RV_AMO), MASK_AMO, + {MN("amomax.d"), MATCH_AMO(RV_AMO_MAX, 0x3, RV_AMO), MASK_AMO, RV64_FMT_AMO, 0, {0, 0}}, - {"amominu.d", MATCH_AMO(RV_AMO_MINU, 0x3, RV_AMO), MASK_AMO, + {MN("amominu.d"), MATCH_AMO(RV_AMO_MINU, 0x3, RV_AMO), MASK_AMO, RV64_FMT_AMO, 0, {0, 0}}, - {"amomaxu.d", MATCH_AMO(RV_AMO_MAXU, 0x3, RV_AMO), MASK_AMO, + {MN("amomaxu.d"), MATCH_AMO(RV_AMO_MAXU, 0x3, RV_AMO), MASK_AMO, RV64_FMT_AMO, 0, {0, 0}}, /* ================================================================= * RV64C compressed — assembler rows. The disassembler uses the * dynamic C decoder below, so 32-bit decode skips these rows. * ================================================================= */ - {"c.nop", 0x0001u, 0xffffu, RV64_FMT_C_NONE, RV64_ASMFL_C16, + {MN("c.nop"), 0x0001u, 0xffffu, RV64_FMT_C_NONE, RV64_ASMFL_C16, {0, 0}}, - {"c.ebreak", 0x9002u, 0xffffu, RV64_FMT_C_NONE, RV64_ASMFL_C16, + {MN("c.ebreak"), 0x9002u, 0xffffu, RV64_FMT_C_NONE, RV64_ASMFL_C16, {0, 0}}, - {"c.jr", 0x8002u, 0xf07fu, RV64_FMT_CR, RV64_ASMFL_C16, {0, 0}}, - {"c.jalr", 0x9002u, 0xf07fu, RV64_FMT_CR, RV64_ASMFL_C16, {0, 0}}, - {"c.mv", 0x8002u, 0xf003u, RV64_FMT_CR, RV64_ASMFL_C16, {0, 0}}, - {"c.add", 0x9002u, 0xf003u, RV64_FMT_CR, RV64_ASMFL_C16, {0, 0}}, - {"c.li", 0x4001u, 0xe003u, RV64_FMT_CI, RV64_ASMFL_C16, {0, 0}}, - {"c.addi", 0x0001u, 0xe003u, RV64_FMT_CI, RV64_ASMFL_C16, {0, 0}}, - {"c.addiw", 0x2001u, 0xe003u, RV64_FMT_CI, RV64_ASMFL_C16, {0, 0}}, - {"c.slli", 0x0002u, 0xe003u, RV64_FMT_CI, RV64_ASMFL_C16, {0, 0}}, - {"c.lui", 0x6001u, 0xe003u, RV64_FMT_CI, RV64_ASMFL_C16, {0, 0}}, - {"c.addi16sp", 0x6101u, 0xef83u, RV64_FMT_CI, RV64_ASMFL_C16, {0, 0}}, - {"c.lwsp", 0x4002u, 0xe003u, RV64_FMT_CI, RV64_ASMFL_C16, {0, 0}}, - {"c.ldsp", 0x6002u, 0xe003u, RV64_FMT_CI, RV64_ASMFL_C16, {0, 0}}, - {"c.fldsp", 0x2002u, 0xe003u, RV64_FMT_CI, + {MN("c.jr"), 0x8002u, 0xf07fu, RV64_FMT_CR, RV64_ASMFL_C16, {0, 0}}, + {MN("c.jalr"), 0x9002u, 0xf07fu, RV64_FMT_CR, RV64_ASMFL_C16, {0, 0}}, + {MN("c.mv"), 0x8002u, 0xf003u, RV64_FMT_CR, RV64_ASMFL_C16, {0, 0}}, + {MN("c.add"), 0x9002u, 0xf003u, RV64_FMT_CR, RV64_ASMFL_C16, {0, 0}}, + {MN("c.li"), 0x4001u, 0xe003u, RV64_FMT_CI, RV64_ASMFL_C16, {0, 0}}, + {MN("c.addi"), 0x0001u, 0xe003u, RV64_FMT_CI, RV64_ASMFL_C16, {0, 0}}, + {MN("c.addiw"), 0x2001u, 0xe003u, RV64_FMT_CI, RV64_ASMFL_C16, {0, 0}}, + {MN("c.slli"), 0x0002u, 0xe003u, RV64_FMT_CI, RV64_ASMFL_C16, {0, 0}}, + {MN("c.lui"), 0x6001u, 0xe003u, RV64_FMT_CI, RV64_ASMFL_C16, {0, 0}}, + {MN("c.addi16sp"), 0x6101u, 0xef83u, RV64_FMT_CI, RV64_ASMFL_C16, {0, 0}}, + {MN("c.lwsp"), 0x4002u, 0xe003u, RV64_FMT_CI, RV64_ASMFL_C16, {0, 0}}, + {MN("c.ldsp"), 0x6002u, 0xe003u, RV64_FMT_CI, RV64_ASMFL_C16, {0, 0}}, + {MN("c.fldsp"), 0x2002u, 0xe003u, RV64_FMT_CI, RV64_ASMFL_C16 | RV64_ASMFL_FP, {0, 0}}, - {"c.swsp", 0xc002u, 0xe003u, RV64_FMT_CSS, RV64_ASMFL_C16, + {MN("c.swsp"), 0xc002u, 0xe003u, RV64_FMT_CSS, RV64_ASMFL_C16, {0, 0}}, - {"c.sdsp", 0xe002u, 0xe003u, RV64_FMT_CSS, RV64_ASMFL_C16, + {MN("c.sdsp"), 0xe002u, 0xe003u, RV64_FMT_CSS, RV64_ASMFL_C16, {0, 0}}, - {"c.fsdsp", 0xa002u, 0xe003u, RV64_FMT_CSS, + {MN("c.fsdsp"), 0xa002u, 0xe003u, RV64_FMT_CSS, RV64_ASMFL_C16 | RV64_ASMFL_FP, {0, 0}}, - {"c.addi4spn", 0x0000u, 0xe003u, RV64_FMT_CIW, RV64_ASMFL_C16, + {MN("c.addi4spn"), 0x0000u, 0xe003u, RV64_FMT_CIW, RV64_ASMFL_C16, {0, 0}}, - {"c.lw", 0x4000u, 0xe003u, RV64_FMT_CL, RV64_ASMFL_C16, {0, 0}}, - {"c.ld", 0x6000u, 0xe003u, RV64_FMT_CL, RV64_ASMFL_C16, {0, 0}}, - {"c.fld", 0x2000u, 0xe003u, RV64_FMT_CL, + {MN("c.lw"), 0x4000u, 0xe003u, RV64_FMT_CL, RV64_ASMFL_C16, {0, 0}}, + {MN("c.ld"), 0x6000u, 0xe003u, RV64_FMT_CL, RV64_ASMFL_C16, {0, 0}}, + {MN("c.fld"), 0x2000u, 0xe003u, RV64_FMT_CL, RV64_ASMFL_C16 | RV64_ASMFL_FP, {0, 0}}, - {"c.sw", 0xc000u, 0xe003u, RV64_FMT_CS, RV64_ASMFL_C16, {0, 0}}, - {"c.sd", 0xe000u, 0xe003u, RV64_FMT_CS, RV64_ASMFL_C16, {0, 0}}, - {"c.fsd", 0xa000u, 0xe003u, RV64_FMT_CS, + {MN("c.sw"), 0xc000u, 0xe003u, RV64_FMT_CS, RV64_ASMFL_C16, {0, 0}}, + {MN("c.sd"), 0xe000u, 0xe003u, RV64_FMT_CS, RV64_ASMFL_C16, {0, 0}}, + {MN("c.fsd"), 0xa000u, 0xe003u, RV64_FMT_CS, RV64_ASMFL_C16 | RV64_ASMFL_FP, {0, 0}}, - {"c.srli", 0x8001u, 0xec03u, RV64_FMT_CB, RV64_ASMFL_C16, {0, 0}}, - {"c.srai", 0x8401u, 0xec03u, RV64_FMT_CB, RV64_ASMFL_C16, {0, 0}}, - {"c.andi", 0x8801u, 0xec03u, RV64_FMT_CB, RV64_ASMFL_C16, {0, 0}}, - {"c.sub", 0x8c01u, 0xfc63u, RV64_FMT_CA, RV64_ASMFL_C16, {0, 0}}, - {"c.xor", 0x8c21u, 0xfc63u, RV64_FMT_CA, RV64_ASMFL_C16, {0, 0}}, - {"c.or", 0x8c41u, 0xfc63u, RV64_FMT_CA, RV64_ASMFL_C16, {0, 0}}, - {"c.and", 0x8c61u, 0xfc63u, RV64_FMT_CA, RV64_ASMFL_C16, {0, 0}}, - {"c.subw", 0x9c01u, 0xfc63u, RV64_FMT_CA, RV64_ASMFL_C16, {0, 0}}, - {"c.addw", 0x9c21u, 0xfc63u, RV64_FMT_CA, RV64_ASMFL_C16, {0, 0}}, - {"c.j", 0xa001u, 0xe003u, RV64_FMT_CJ, RV64_ASMFL_C16, {0, 0}}, - {"c.beqz", 0xc001u, 0xe003u, RV64_FMT_CB, RV64_ASMFL_C16, {0, 0}}, - {"c.bnez", 0xe001u, 0xe003u, RV64_FMT_CB, RV64_ASMFL_C16, {0, 0}}, + {MN("c.srli"), 0x8001u, 0xec03u, RV64_FMT_CB, RV64_ASMFL_C16, {0, 0}}, + {MN("c.srai"), 0x8401u, 0xec03u, RV64_FMT_CB, RV64_ASMFL_C16, {0, 0}}, + {MN("c.andi"), 0x8801u, 0xec03u, RV64_FMT_CB, RV64_ASMFL_C16, {0, 0}}, + {MN("c.sub"), 0x8c01u, 0xfc63u, RV64_FMT_CA, RV64_ASMFL_C16, {0, 0}}, + {MN("c.xor"), 0x8c21u, 0xfc63u, RV64_FMT_CA, RV64_ASMFL_C16, {0, 0}}, + {MN("c.or"), 0x8c41u, 0xfc63u, RV64_FMT_CA, RV64_ASMFL_C16, {0, 0}}, + {MN("c.and"), 0x8c61u, 0xfc63u, RV64_FMT_CA, RV64_ASMFL_C16, {0, 0}}, + {MN("c.subw"), 0x9c01u, 0xfc63u, RV64_FMT_CA, RV64_ASMFL_C16, {0, 0}}, + {MN("c.addw"), 0x9c21u, 0xfc63u, RV64_FMT_CA, RV64_ASMFL_C16, {0, 0}}, + {MN("c.j"), 0xa001u, 0xe003u, RV64_FMT_CJ, RV64_ASMFL_C16, {0, 0}}, + {MN("c.beqz"), 0xc001u, 0xe003u, RV64_FMT_CB, RV64_ASMFL_C16, {0, 0}}, + {MN("c.bnez"), 0xe001u, 0xe003u, RV64_FMT_CB, RV64_ASMFL_C16, {0, 0}}, }; #undef RV64_AMO_ORDER_ROWS @@ -558,20 +567,20 @@ const Rv64InsnDesc* rv64_disasm_find(u32 word) { return NULL; } -const Rv64InsnDesc* rv64_asm_find(const char* mnemonic) { +const Rv64InsnDesc* rv64_asm_find(Slice mnemonic) { /* Prefer canonical (non-alias) rows when both spellings exist; the * caller can still write the alias and we'll match it on a second * pass. Aliases share encoding with the canonical row so the choice * is purely for diagnostics. */ - if (!mnemonic) return NULL; + if (!mnemonic.s) return NULL; for (u32 i = 0; i < rv64_insn_table_n; ++i) { const Rv64InsnDesc* d = &rv64_insn_table[i]; if ((d->flags & RV64_ASMFL_ALIAS)) continue; - if (!strcmp(d->mnemonic, mnemonic)) return d; + if (slice_eq(d->mnemonic, mnemonic)) return d; } for (u32 i = 0; i < rv64_insn_table_n; ++i) { const Rv64InsnDesc* d = &rv64_insn_table[i]; - if (!strcmp(d->mnemonic, mnemonic)) return d; + if (slice_eq(d->mnemonic, mnemonic)) return d; } return NULL; } @@ -601,11 +610,13 @@ static u32 rv64c_lookup_simple(u32 w) { * with custom operand printers. */ static const Rv64InsnDesc rv64_c_table[] = { /* index 0 reserved (no match). */ - {"c.unknown", 0, 0xffffu, RV64_FMT_C_NONE, RV64_ASMFL_C16, {0, 0}}, - {"c.nop", 0x0001u, 0xffffu, RV64_FMT_C_NONE, RV64_ASMFL_C16, {0, 0}}, - {"c.ebreak", 0x9002u, 0xffffu, RV64_FMT_C_NONE, RV64_ASMFL_C16, {0, 0}}, + {MN("c.unknown"), 0, 0xffffu, RV64_FMT_C_NONE, RV64_ASMFL_C16, {0, 0}}, + {MN("c.nop"), 0x0001u, 0xffffu, RV64_FMT_C_NONE, RV64_ASMFL_C16, {0, 0}}, + {MN("c.ebreak"), 0x9002u, 0xffffu, RV64_FMT_C_NONE, RV64_ASMFL_C16, {0, 0}}, }; +#undef MN + const Rv64InsnDesc* rv64_disasm_find_c(u32 word) { u32 hw = word & 0xffffu; u32 idx = rv64c_lookup_simple(hw); @@ -623,7 +634,7 @@ const Rv64InsnDesc* rv64_disasm_find_c(u32 word) { u32 rd_rs1 = (hw >> 7) & 0x1fu; u32 rs2 = (hw >> 2) & 0x1fu; if (funct4 == 0x8u) { - dyn = (Rv64InsnDesc){rs2 == 0 ? "c.jr" : "c.mv", hw, + dyn = (Rv64InsnDesc){slice_from_cstr(rs2 == 0 ? "c.jr" : "c.mv"), hw, 0xffffu, RV64_FMT_CR, RV64_ASMFL_C16, {0, 0}}; return rd_rs1 == 0 ? NULL : &dyn; } @@ -632,30 +643,30 @@ const Rv64InsnDesc* rv64_disasm_find_c(u32 word) { dyn = rv64_c_table[2]; /* c.ebreak */ return &dyn; } - dyn = (Rv64InsnDesc){rs2 == 0 ? "c.jalr" : "c.add", hw, + dyn = (Rv64InsnDesc){slice_from_cstr(rs2 == 0 ? "c.jalr" : "c.add"), hw, 0xffffu, RV64_FMT_CR, RV64_ASMFL_C16, {0, 0}}; return &dyn; } } /* C.LI / C.ADDI / C.LUI — quadrant 1 */ if (op == 1u && f3 == 2u) { - dyn = (Rv64InsnDesc){"c.li", hw, 0xffffu, RV64_FMT_CI, + dyn = (Rv64InsnDesc){slice_from_cstr("c.li"), hw, 0xffffu, RV64_FMT_CI, RV64_ASMFL_C16, {0, 0}}; return &dyn; } if (op == 1u && f3 == 1u) { - dyn = (Rv64InsnDesc){"c.addiw", hw, 0xffffu, RV64_FMT_CI, + dyn = (Rv64InsnDesc){slice_from_cstr("c.addiw"), hw, 0xffffu, RV64_FMT_CI, RV64_ASMFL_C16, {0, 0}}; return &dyn; } if (op == 1u && f3 == 0u) { - dyn = (Rv64InsnDesc){"c.addi", hw, 0xffffu, RV64_FMT_CI, + dyn = (Rv64InsnDesc){slice_from_cstr("c.addi"), hw, 0xffffu, RV64_FMT_CI, RV64_ASMFL_C16, {0, 0}}; return &dyn; } if (op == 1u && f3 == 3u) { u32 rd = (hw >> 7) & 0x1fu; - dyn = (Rv64InsnDesc){rd == 2u ? "c.addi16sp" : "c.lui", hw, + dyn = (Rv64InsnDesc){slice_from_cstr(rd == 2u ? "c.addi16sp" : "c.lui"), hw, 0xffffu, RV64_FMT_CI, RV64_ASMFL_C16, {0, 0}}; return &dyn; } @@ -663,7 +674,7 @@ const Rv64InsnDesc* rv64_disasm_find_c(u32 word) { u32 top = (hw >> 10) & 0x3u; if (top == 0u || top == 1u || top == 2u) { static const char* const names[3] = {"c.srli", "c.srai", "c.andi"}; - dyn = (Rv64InsnDesc){names[top], hw, 0xffffu, RV64_FMT_CB, + dyn = (Rv64InsnDesc){slice_from_cstr(names[top]), hw, 0xffffu, RV64_FMT_CB, RV64_ASMFL_C16, {0, 0}}; return &dyn; } @@ -674,97 +685,97 @@ const Rv64InsnDesc* rv64_disasm_find_c(u32 word) { static const char* const ca1[4] = {"c.subw", "c.addw", NULL, NULL}; const char* name = bit12 ? ca1[subop] : ca0[subop]; if (!name) return NULL; - dyn = (Rv64InsnDesc){name, hw, 0xffffu, RV64_FMT_CA, + dyn = (Rv64InsnDesc){slice_from_cstr(name), hw, 0xffffu, RV64_FMT_CA, RV64_ASMFL_C16, {0, 0}}; return &dyn; } } if (op == 1u && f3 == 5u) { - dyn = (Rv64InsnDesc){"c.j", hw, 0xffffu, RV64_FMT_CJ, + dyn = (Rv64InsnDesc){slice_from_cstr("c.j"), hw, 0xffffu, RV64_FMT_CJ, RV64_ASMFL_C16, {0, 0}}; return &dyn; } if (op == 1u && f3 == 6u) { - dyn = (Rv64InsnDesc){"c.beqz", hw, 0xffffu, RV64_FMT_CB, + dyn = (Rv64InsnDesc){slice_from_cstr("c.beqz"), hw, 0xffffu, RV64_FMT_CB, RV64_ASMFL_C16, {0, 0}}; return &dyn; } if (op == 1u && f3 == 7u) { - dyn = (Rv64InsnDesc){"c.bnez", hw, 0xffffu, RV64_FMT_CB, + dyn = (Rv64InsnDesc){slice_from_cstr("c.bnez"), hw, 0xffffu, RV64_FMT_CB, RV64_ASMFL_C16, {0, 0}}; return &dyn; } /* C.LWSP / C.LDSP — quadrant 2, funct3=010/011 */ if (op == 2u && f3 == 2u) { - dyn = (Rv64InsnDesc){"c.lwsp", hw, 0xffffu, RV64_FMT_CI, + dyn = (Rv64InsnDesc){slice_from_cstr("c.lwsp"), hw, 0xffffu, RV64_FMT_CI, RV64_ASMFL_C16, {0, 0}}; return &dyn; } if (op == 2u && f3 == 3u) { - dyn = (Rv64InsnDesc){"c.ldsp", hw, 0xffffu, RV64_FMT_CI, + dyn = (Rv64InsnDesc){slice_from_cstr("c.ldsp"), hw, 0xffffu, RV64_FMT_CI, RV64_ASMFL_C16, {0, 0}}; return &dyn; } if (op == 2u && f3 == 0u) { - dyn = (Rv64InsnDesc){"c.slli", hw, 0xffffu, RV64_FMT_CI, + dyn = (Rv64InsnDesc){slice_from_cstr("c.slli"), hw, 0xffffu, RV64_FMT_CI, RV64_ASMFL_C16, {0, 0}}; return &dyn; } if (op == 2u && f3 == 1u) { - dyn = (Rv64InsnDesc){"c.fldsp", hw, 0xffffu, RV64_FMT_CI, + dyn = (Rv64InsnDesc){slice_from_cstr("c.fldsp"), hw, 0xffffu, RV64_FMT_CI, RV64_ASMFL_C16 | RV64_ASMFL_FP, {0, 0}}; return &dyn; } /* C.SWSP / C.SDSP — quadrant 2, funct3=110/111 */ if (op == 2u && f3 == 6u) { - dyn = (Rv64InsnDesc){"c.swsp", hw, 0xffffu, RV64_FMT_CSS, + dyn = (Rv64InsnDesc){slice_from_cstr("c.swsp"), hw, 0xffffu, RV64_FMT_CSS, RV64_ASMFL_C16, {0, 0}}; return &dyn; } if (op == 2u && f3 == 7u) { - dyn = (Rv64InsnDesc){"c.sdsp", hw, 0xffffu, RV64_FMT_CSS, + dyn = (Rv64InsnDesc){slice_from_cstr("c.sdsp"), hw, 0xffffu, RV64_FMT_CSS, RV64_ASMFL_C16, {0, 0}}; return &dyn; } if (op == 2u && f3 == 5u) { - dyn = (Rv64InsnDesc){"c.fsdsp", hw, 0xffffu, RV64_FMT_CSS, + dyn = (Rv64InsnDesc){slice_from_cstr("c.fsdsp"), hw, 0xffffu, RV64_FMT_CSS, RV64_ASMFL_C16 | RV64_ASMFL_FP, {0, 0}}; return &dyn; } /* C.ADDI4SPN — quadrant 0, funct3=000 */ if (op == 0u && f3 == 0u) { - dyn = (Rv64InsnDesc){"c.addi4spn", hw, 0xffffu, RV64_FMT_CIW, + dyn = (Rv64InsnDesc){slice_from_cstr("c.addi4spn"), hw, 0xffffu, RV64_FMT_CIW, RV64_ASMFL_C16, {0, 0}}; return &dyn; } /* C.LW / C.LD — quadrant 0, funct3=010/011 */ if (op == 0u && f3 == 2u) { - dyn = (Rv64InsnDesc){"c.lw", hw, 0xffffu, RV64_FMT_CL, + dyn = (Rv64InsnDesc){slice_from_cstr("c.lw"), hw, 0xffffu, RV64_FMT_CL, RV64_ASMFL_C16, {0, 0}}; return &dyn; } if (op == 0u && f3 == 3u) { - dyn = (Rv64InsnDesc){"c.ld", hw, 0xffffu, RV64_FMT_CL, + dyn = (Rv64InsnDesc){slice_from_cstr("c.ld"), hw, 0xffffu, RV64_FMT_CL, RV64_ASMFL_C16, {0, 0}}; return &dyn; } if (op == 0u && f3 == 1u) { - dyn = (Rv64InsnDesc){"c.fld", hw, 0xffffu, RV64_FMT_CL, + dyn = (Rv64InsnDesc){slice_from_cstr("c.fld"), hw, 0xffffu, RV64_FMT_CL, RV64_ASMFL_C16 | RV64_ASMFL_FP, {0, 0}}; return &dyn; } if (op == 0u && f3 == 6u) { - dyn = (Rv64InsnDesc){"c.sw", hw, 0xffffu, RV64_FMT_CS, + dyn = (Rv64InsnDesc){slice_from_cstr("c.sw"), hw, 0xffffu, RV64_FMT_CS, RV64_ASMFL_C16, {0, 0}}; return &dyn; } if (op == 0u && f3 == 7u) { - dyn = (Rv64InsnDesc){"c.sd", hw, 0xffffu, RV64_FMT_CS, + dyn = (Rv64InsnDesc){slice_from_cstr("c.sd"), hw, 0xffffu, RV64_FMT_CS, RV64_ASMFL_C16, {0, 0}}; return &dyn; } if (op == 0u && f3 == 5u) { - dyn = (Rv64InsnDesc){"c.fsd", hw, 0xffffu, RV64_FMT_CS, + dyn = (Rv64InsnDesc){slice_from_cstr("c.fsd"), hw, 0xffffu, RV64_FMT_CS, RV64_ASMFL_C16 | RV64_ASMFL_FP, {0, 0}}; return &dyn; } @@ -830,23 +841,23 @@ static void print_i(StrBuf* sb, u32 w, const Rv64InsnDesc* d) { Rv64I f = rv64_i_unpack(w); i64 imm = rv64_sext((u64)f.imm12, 12); /* Alias: `li rd, imm` — print rd, imm. */ - if ((d->flags & RV64_ASMFL_ALIAS) && !strcmp(d->mnemonic, "li")) { + if ((d->flags & RV64_ASMFL_ALIAS) && slice_eq_cstr(d->mnemonic, "li")) { p_xreg(sb, f.rd); p_sep(sb); strbuf_put_i64(sb, imm); return; } /* Alias: `mv rd, rs1` — print rd, rs1. */ - if ((d->flags & RV64_ASMFL_ALIAS) && !strcmp(d->mnemonic, "mv")) { + if ((d->flags & RV64_ASMFL_ALIAS) && slice_eq_cstr(d->mnemonic, "mv")) { p_xreg(sb, f.rd); p_sep(sb); p_xreg(sb, f.rs1); return; } /* Alias: `sext.w rd, rs1` — print rd, rs1. */ - if ((d->flags & RV64_ASMFL_ALIAS) && !strcmp(d->mnemonic, "sext.w")) { + if ((d->flags & RV64_ASMFL_ALIAS) && slice_eq_cstr(d->mnemonic, "sext.w")) { p_xreg(sb, f.rd); p_sep(sb); p_xreg(sb, f.rs1); return; } /* Alias: `seqz rd, rs` / `not rd, rs` — print rd, rs (drop imm). */ if ((d->flags & RV64_ASMFL_ALIAS) && - (!strcmp(d->mnemonic, "seqz") || !strcmp(d->mnemonic, "not"))) { + (slice_eq_cstr(d->mnemonic, "seqz") || slice_eq_cstr(d->mnemonic, "not"))) { p_xreg(sb, f.rd); p_sep(sb); p_xreg(sb, f.rs1); return; } @@ -902,7 +913,7 @@ static void print_b(StrBuf* sb, u32 w, u64 vaddr, const Rv64InsnDesc* d) { Rv64B f = rv64_b_unpack(w); i64 off = rv64_sext((u64)f.imm13, 13); if ((d->flags & RV64_ASMFL_ALIAS) && - (!strcmp(d->mnemonic, "beqz") || !strcmp(d->mnemonic, "bnez"))) { + (slice_eq_cstr(d->mnemonic, "beqz") || slice_eq_cstr(d->mnemonic, "bnez"))) { p_xreg(sb, f.rs1); p_sep(sb); p_rel(sb, vaddr, off); return; } @@ -914,7 +925,7 @@ static void print_b(StrBuf* sb, u32 w, u64 vaddr, const Rv64InsnDesc* d) { static void print_j(StrBuf* sb, u32 w, u64 vaddr, const Rv64InsnDesc* d) { Rv64J f = rv64_j_unpack(w); i64 off = rv64_sext((u64)f.imm21, 21); - if ((d->flags & RV64_ASMFL_ALIAS) && !strcmp(d->mnemonic, "j")) { + if ((d->flags & RV64_ASMFL_ALIAS) && slice_eq_cstr(d->mnemonic, "j")) { p_rel(sb, vaddr, off); return; } @@ -925,7 +936,7 @@ static void print_j(StrBuf* sb, u32 w, u64 vaddr, const Rv64InsnDesc* d) { static void print_jalr(StrBuf* sb, u32 w, const Rv64InsnDesc* d) { Rv64I f = rv64_i_unpack(w); i64 imm = rv64_sext((u64)f.imm12, 12); - if ((d->flags & RV64_ASMFL_ALIAS) && !strcmp(d->mnemonic, "jr")) { + if ((d->flags & RV64_ASMFL_ALIAS) && slice_eq_cstr(d->mnemonic, "jr")) { p_xreg(sb, f.rs1); return; } @@ -1005,12 +1016,12 @@ static void print_fp_cvt(StrBuf* sb, u32 w, const Rv64InsnDesc* d) { /* rs1: FP if mnemonic is fcvt.X.{S,D} or fsqrt or fmv.x.{w,d}; * GPR if mnemonic is fcvt.{S,D}.{w,wu,l,lu} or fmv.{w,d}.x. */ int rs1_is_fp = 1; - if (!strcmp(d->mnemonic, "fmv.w.x") || !strcmp(d->mnemonic, "fmv.d.x") || - !strncmp(d->mnemonic, "fcvt.s.", 7) || - !strncmp(d->mnemonic, "fcvt.d.", 7)) { + if (slice_eq_cstr(d->mnemonic, "fmv.w.x") || slice_eq_cstr(d->mnemonic, "fmv.d.x") || + slice_has_prefix_cstr(d->mnemonic, "fcvt.s.", 7) || + slice_has_prefix_cstr(d->mnemonic, "fcvt.d.", 7)) { /* These have rs1 as integer GPR (source is integer). Exception: * fcvt.s.d / fcvt.d.s have rs1 as FP. */ - if (!strcmp(d->mnemonic, "fcvt.s.d") || !strcmp(d->mnemonic, "fcvt.d.s")) + if (slice_eq_cstr(d->mnemonic, "fcvt.s.d") || slice_eq_cstr(d->mnemonic, "fcvt.d.s")) rs1_is_fp = 1; else rs1_is_fp = 0; @@ -1041,7 +1052,7 @@ static void print_cr(StrBuf* sb, u32 w, const Rv64InsnDesc* d) { u32 hw = w & 0xffffu; u32 rd_rs1 = (hw >> 7) & 0x1fu; u32 rs2 = (hw >> 2) & 0x1fu; - if (!strcmp(d->mnemonic, "c.jr") || !strcmp(d->mnemonic, "c.jalr")) { + if (slice_eq_cstr(d->mnemonic, "c.jr") || slice_eq_cstr(d->mnemonic, "c.jalr")) { p_xreg(sb, rd_rs1); } else { /* c.mv / c.add */ @@ -1056,7 +1067,7 @@ static void print_ci(StrBuf* sb, u32 w, const Rv64InsnDesc* d) { u32 imm5 = (hw >> 12) & 1u; u32 imm4_0 = (hw >> 2) & 0x1fu; i64 imm; - if (!strcmp(d->mnemonic, "c.lui")) { + if (slice_eq_cstr(d->mnemonic, "c.lui")) { /* nzimm[17:12] = bits 12, 6:2 — signed extended to 18 bits. */ u64 raw = (u64)((imm5 << 5) | imm4_0); imm = rv64_sext(raw, 6) << 12; @@ -1064,7 +1075,7 @@ static void print_ci(StrBuf* sb, u32 w, const Rv64InsnDesc* d) { strbuf_put_hex_u64(sb, (u64)imm); return; } - if (!strcmp(d->mnemonic, "c.addi16sp")) { + if (slice_eq_cstr(d->mnemonic, "c.addi16sp")) { /* nzimm[9|4|6|8:7|5] (scrambled). Just decode for print. */ u32 b9 = (hw >> 12) & 1u; u32 b4 = (hw >> 6) & 1u; @@ -1078,7 +1089,7 @@ static void print_ci(StrBuf* sb, u32 w, const Rv64InsnDesc* d) { strbuf_put_i64(sb, imm); return; } - if (!strcmp(d->mnemonic, "c.lwsp")) { + if (slice_eq_cstr(d->mnemonic, "c.lwsp")) { /* offset[5|4:2|7:6] scaled by 4. */ u32 b5 = imm5; u32 b4_2 = (imm4_0 >> 2) & 7u; @@ -1088,7 +1099,7 @@ static void print_ci(StrBuf* sb, u32 w, const Rv64InsnDesc* d) { p_mem(sb, (i64)off, 2u); return; } - if (!strcmp(d->mnemonic, "c.ldsp") || !strcmp(d->mnemonic, "c.fldsp")) { + if (slice_eq_cstr(d->mnemonic, "c.ldsp") || slice_eq_cstr(d->mnemonic, "c.fldsp")) { /* offset[5|4:3|8:6] scaled by 8. */ u32 b5 = imm5; u32 b4_3 = (imm4_0 >> 3) & 3u; @@ -1100,7 +1111,7 @@ static void print_ci(StrBuf* sb, u32 w, const Rv64InsnDesc* d) { p_mem(sb, (i64)off, 2u); return; } - if (!strcmp(d->mnemonic, "c.slli")) { + if (slice_eq_cstr(d->mnemonic, "c.slli")) { u32 shamt = (imm5 << 5) | imm4_0; p_xreg(sb, rd_rs1); p_sep(sb); strbuf_put_u64(sb, (u64)shamt); @@ -1117,7 +1128,7 @@ static void print_css(StrBuf* sb, u32 w, const Rv64InsnDesc* d) { u32 rs2 = (hw >> 2) & 0x1fu; u32 imm6 = (hw >> 7) & 0x3fu; u32 off; - if (!strcmp(d->mnemonic, "c.swsp")) { + if (slice_eq_cstr(d->mnemonic, "c.swsp")) { /* offset[5:2|7:6] scaled by 4. */ u32 b5_2 = (imm6 >> 2) & 0xfu; u32 b7_6 = imm6 & 3u; @@ -1160,7 +1171,7 @@ static void print_cl(StrBuf* sb, u32 w, const Rv64InsnDesc* d) { u32 b5_3 = (hw >> 10) & 7u; u32 lo = (hw >> 5) & 3u; u32 off; - if (!strcmp(d->mnemonic, "c.lw")) { + if (slice_eq_cstr(d->mnemonic, "c.lw")) { /* offset[5:3|2|6] scaled by 4. */ u32 b2 = (lo >> 1) & 1u; u32 b6 = lo & 1u; @@ -1182,7 +1193,7 @@ static void print_cs(StrBuf* sb, u32 w, const Rv64InsnDesc* d) { u32 b5_3 = (hw >> 10) & 7u; u32 lo = (hw >> 5) & 3u; u32 off; - if (!strcmp(d->mnemonic, "c.sw")) { + if (slice_eq_cstr(d->mnemonic, "c.sw")) { u32 b2 = (lo >> 1) & 1u; u32 b6 = lo & 1u; off = (b6 << 6) | (b5_3 << 3) | (b2 << 2); @@ -1206,11 +1217,11 @@ static void print_ca(StrBuf* sb, u32 w) { static void print_cb(StrBuf* sb, u32 w, u64 vaddr, const Rv64InsnDesc* d) { u32 hw = w & 0xffffu; u32 rs1_3 = (hw >> 7) & 7u; - if (!strcmp(d->mnemonic, "c.srli") || !strcmp(d->mnemonic, "c.srai") || - !strcmp(d->mnemonic, "c.andi")) { + if (slice_eq_cstr(d->mnemonic, "c.srli") || slice_eq_cstr(d->mnemonic, "c.srai") || + slice_eq_cstr(d->mnemonic, "c.andi")) { u32 imm = (((hw >> 12) & 1u) << 5) | ((hw >> 2) & 0x1fu); p_xreg(sb, RVC_REG3(rs1_3)); p_sep(sb); - if (!strcmp(d->mnemonic, "c.andi")) + if (slice_eq_cstr(d->mnemonic, "c.andi")) strbuf_put_i64(sb, rv64_sext((u64)imm, 6)); else strbuf_put_u64(sb, (u64)imm); diff --git a/src/arch/rv64/isa.h b/src/arch/rv64/isa.h @@ -10,6 +10,7 @@ #define CFREE_RV64_ISA_H #include "core/core.h" +#include "core/slice.h" #include "core/strbuf.h" /* ---- Named registers (DWARF / psABI numbering matches HW) ---- */ @@ -485,7 +486,7 @@ typedef struct Rv64C { u32 word; } Rv64C; /* 16-bit halfword in low 16 bits */ * =================================================================== */ typedef struct Rv64InsnDesc { - const char* mnemonic; + Slice mnemonic; u32 match; u32 mask; u8 fmt; /* Rv64Format */ @@ -508,7 +509,7 @@ const Rv64InsnDesc* rv64_disasm_find_c(u32 word); /* Mnemonic → descriptor for the assembler. Returns NULL if not found. * Ignores ALIAS-only rows when those would produce ambiguous parses * (the canonical form is always reachable). */ -const Rv64InsnDesc* rv64_asm_find(const char* mnemonic); +const Rv64InsnDesc* rv64_asm_find(Slice mnemonic); /* =================================================================== * Operand print / parse dispatch. diff --git a/src/arch/rv64/ops.c b/src/arch/rv64/ops.c @@ -5,6 +5,7 @@ #include "arch/rv64/asm.h" #include "arch/rv64/regs.h" #include "core/pool.h" +#include "core/slice.h" /* ---- For a memory access of `nbytes`, pick the right store opcode. ---- */ u32 enc_int_store(u32 nbytes, u32 src, u32 base, i32 off) { @@ -36,7 +37,7 @@ static void rv_load_const(CGTarget* t, Operand dst, ConstBytes cb) { if (dst.cls != RC_FP) { compiler_panic(t->c, a->loc, "rv64 load_const: only FP supported in v1"); } - Sym ro_name = pool_intern_cstr(t->c->global, ".rodata"); + Sym ro_name = pool_intern_slice(t->c->global, SLICE_LIT(".rodata")); ObjSecId ro = obj_section(t->obj, ro_name, SEC_RODATA, SF_ALLOC, 1u); u32 cur_section = t->mc->section_id; @@ -60,7 +61,7 @@ static void rv_load_const(CGTarget* t, Operand dst, ConstBytes cb) { for (int i = tn - 1; i >= 0; --i) namebuf[len++] = tmp[i]; namebuf[len] = 0; } - Sym sname = pool_intern_cstr(t->c->global, namebuf); + Sym sname = pool_intern_slice(t->c->global, slice_from_cstr(namebuf)); ObjSymId sym = obj_symbol(t->obj, sname, SB_LOCAL, SK_OBJ, ro, (u64)ro_off, (u64)cb.size); t->mc->set_section(t->mc, cur_section); @@ -87,7 +88,7 @@ static void rv_load_const(CGTarget* t, Operand dst, ConstBytes cb) { for (int i = tn - 1; i >= 0; --i) anchor_buf[al++] = tmp[i]; anchor_buf[al] = 0; } - Sym aname = pool_intern_cstr(t->c->global, anchor_buf); + Sym aname = pool_intern_slice(t->c->global, slice_from_cstr(anchor_buf)); ObjSymId anchor = obj_symbol(t->obj, aname, SB_LOCAL, SK_OBJ, sec, (u64)auipc_pos, 0); u32 lpos = t->mc->pos(t->mc); @@ -201,7 +202,7 @@ ObjSymId emit_pcrel_anchor(CGTarget* t, u32 sec, u32 auipc_pos) { else { while (v) { tmp[tn++] = '0' + (char)(v % 10); v /= 10; } } for (int i = tn - 1; i >= 0; --i) buf[len++] = tmp[i]; buf[len] = 0; - Sym n = pool_intern_cstr(t->c->global, buf); + Sym n = pool_intern_slice(t->c->global, slice_from_cstr(buf)); return obj_symbol(t->obj, n, SB_LOCAL, SK_OBJ, sec, (u64)auipc_pos, 0); } @@ -2327,14 +2328,13 @@ static void rv_asm_block(CGTarget* t, const char* tmpl, * named in the clobber list (psABI: s0..s11 are CS for integers, fs0.. * fs11 for FP). Same accounting the prologue uses for bound regs. */ for (u32 i = 0; i < nc; ++i) { - size_t len = 0; - const char* s = pool_str(t->c->global, clobs[i], &len); + Slice cs = pool_slice(t->c->global, clobs[i]); char buf[16]; uint32_t dwarf; - if (!s || !len) continue; - if (len >= sizeof buf) continue; - memcpy(buf, s, len); - buf[len] = '\0'; + if (!cs.s || !cs.len) continue; + if (cs.len >= sizeof buf) continue; + memcpy(buf, cs.s, cs.len); + buf[cs.len] = '\0'; if (rv64_register_index(buf, &dwarf) != 0) continue; if (dwarf <= 31u) { /* Integer reg: s0=x8, s1=x9, s2..s11=x18..x27. */ diff --git a/src/arch/rv64/regs.c b/src/arch/rv64/regs.c @@ -7,9 +7,9 @@ #include "arch/rv64/regs.h" #include <stdint.h> -#include <string.h> #include "core/core.h" +#include "core/slice.h" typedef struct Rv64Reg { uint32_t dwarf_idx; @@ -64,9 +64,11 @@ const char* rv64_register_name(uint32_t dwarf_idx) { int rv64_register_index(const char* name, uint32_t* idx_out) { uint32_t i; uint32_t n; + Slice q; if (!name) return 1; + q = slice_from_cstr(name); for (i = 0; i < RV64_REGS_N; ++i) { - if (!strcmp(RV64_REGS[i].name, name)) { + if (slice_eq_cstr(q, RV64_REGS[i].name)) { if (idx_out) *idx_out = RV64_REGS[i].dwarf_idx; return 0; } @@ -79,7 +81,7 @@ int rv64_register_index(const char* name, uint32_t* idx_out) { if (idx_out) *idx_out = 32u + n; return 0; } - if (!strcmp(name, "fp")) { + if (slice_eq_cstr(q, "fp")) { if (idx_out) *idx_out = 8u; return 0; } diff --git a/src/arch/x64/alloc.c b/src/arch/x64/alloc.c @@ -8,6 +8,7 @@ #include <string.h> #include "arch/arch.h" +#include "core/slice.h" #include "arch/x64/internal.h" #include "arch/x64/isa.h" #include "arch/x64/regs.h" @@ -20,29 +21,29 @@ * Registers / frame */ int x_resolve_reg_name(CGTarget* t, Sym name, Reg* out, RegClass* cls_out) { - size_t len = 0; - const char* s = pool_str(t->c->global, name, &len); + Slice ns = pool_slice(t->c->global, name); char buf[16]; u32 idx; - if (!s || !len || len >= sizeof buf) return 1; - memcpy(buf, s, len); - buf[len] = '\0'; - if (!strcmp(buf, "ah")) { + if (!ns.s || !ns.len || ns.len >= sizeof buf) return 1; + memcpy(buf, ns.s, ns.len); + buf[ns.len] = '\0'; + Slice q = slice_from_cstr(buf); + if (slice_eq_cstr(q, "ah")) { if (out) *out = X64_RAX; if (cls_out) *cls_out = RC_INT; return 0; } - if (!strcmp(buf, "ch")) { + if (slice_eq_cstr(q, "ch")) { if (out) *out = X64_RCX; if (cls_out) *cls_out = RC_INT; return 0; } - if (!strcmp(buf, "dh")) { + if (slice_eq_cstr(q, "dh")) { if (out) *out = X64_RDX; if (cls_out) *cls_out = RC_INT; return 0; } - if (!strcmp(buf, "bh")) { + if (slice_eq_cstr(q, "bh")) { if (out) *out = X64_RBX; if (cls_out) *cls_out = RC_INT; return 0; diff --git a/src/arch/x64/arch.c b/src/arch/x64/arch.c @@ -66,20 +66,24 @@ static int x64_apply_label_fixup(Compiler* c, const ArchLabelFixup* fx) { } static const CfreePredefinedMacro x64_predefined_macros[] = { - {"__x86_64", "1"}, - {"__x86_64__", "1"}, - {"__amd64", "1"}, - {"__amd64__", "1"}, - {"__LP64__", "1"}, - {"__ORDER_LITTLE_ENDIAN__", "1234"}, - {"__ORDER_BIG_ENDIAN__", "4321"}, - {"__BYTE_ORDER__", "__ORDER_LITTLE_ENDIAN__"}, - {"__LITTLE_ENDIAN__", "1"}, + {CFREE_SLICE_LIT("__x86_64"), CFREE_SLICE_LIT("1")}, + {CFREE_SLICE_LIT("__x86_64__"), CFREE_SLICE_LIT("1")}, + {CFREE_SLICE_LIT("__amd64"), CFREE_SLICE_LIT("1")}, + {CFREE_SLICE_LIT("__amd64__"), CFREE_SLICE_LIT("1")}, + {CFREE_SLICE_LIT("__LP64__"), CFREE_SLICE_LIT("1")}, + {CFREE_SLICE_LIT("__ORDER_LITTLE_ENDIAN__"), CFREE_SLICE_LIT("1234")}, + {CFREE_SLICE_LIT("__ORDER_BIG_ENDIAN__"), CFREE_SLICE_LIT("4321")}, + {CFREE_SLICE_LIT("__BYTE_ORDER__"), CFREE_SLICE_LIT("__ORDER_LITTLE_ENDIAN__")}, + {CFREE_SLICE_LIT("__LITTLE_ENDIAN__"), CFREE_SLICE_LIT("1")}, }; static int x64_register_at_public(uint32_t idx, CfreeArchReg* out) { + const char* nm = NULL; + int rc; if (!out) return 1; - return x64_register_iter_get(idx, &out->dwarf_idx, &out->name); + rc = x64_register_iter_get(idx, &out->dwarf_idx, &nm); + if (rc == 0) out->name = cfree_slice_cstr(nm); + return rc; } static CGTarget* x64_backend_make(Compiler* c, ObjBuilder* o, diff --git a/src/arch/x64/asm.c b/src/arch/x64/asm.c @@ -7,6 +7,7 @@ #include "asm/asm_helpers.h" #include "core/arena.h" #include "core/pool.h" +#include "core/slice.h" #include "core/strbuf.h" struct X64Asm { @@ -46,16 +47,17 @@ typedef struct X64AsmOperand { static int x64_reg_from_name(AsmDriver* d, Sym s, u32* reg_out, u32* width_out, u32* high8_out) { - size_t n = 0; - const char* p = pool_str(asm_driver_pool(d), s, &n); + Slice sl = pool_slice(asm_driver_pool(d), s); char buf[16]; u32 reg; u32 width = 8; - if (!p || n < 2 || n >= sizeof buf) return 0; - memcpy(buf, p, n); - buf[n] = '\0'; - if (!strcmp(buf, "ah") || !strcmp(buf, "ch") || !strcmp(buf, "dh") || - !strcmp(buf, "bh")) { + Slice q; + if (!sl.s || sl.len < 2 || sl.len >= sizeof buf) return 0; + memcpy(buf, sl.s, sl.len); + buf[sl.len] = '\0'; + q = slice_from_cstr(buf); + if (slice_eq_cstr(q, "ah") || slice_eq_cstr(q, "ch") || + slice_eq_cstr(q, "dh") || slice_eq_cstr(q, "bh")) { static const u32 high_map[4] = {4u, 5u, 6u, 7u}; const char* names = "acdb"; for (u32 i = 0; i < 4u; ++i) { @@ -69,17 +71,19 @@ static int x64_reg_from_name(AsmDriver* d, Sym s, u32* reg_out, } if (x64_register_hw_index(buf, &reg) != 0) return 0; if (reg > 15u) return 0; - if (!strcmp(buf, "al") || !strcmp(buf, "cl") || !strcmp(buf, "dl") || - !strcmp(buf, "bl") || !strcmp(buf, "spl") || !strcmp(buf, "bpl") || - !strcmp(buf, "sil") || !strcmp(buf, "dil") || buf[n - 1] == 'b') { + if (slice_eq_cstr(q, "al") || slice_eq_cstr(q, "cl") || + slice_eq_cstr(q, "dl") || slice_eq_cstr(q, "bl") || + slice_eq_cstr(q, "spl") || slice_eq_cstr(q, "bpl") || + slice_eq_cstr(q, "sil") || slice_eq_cstr(q, "dil") || + buf[sl.len - 1] == 'b') { width = 1; - } else if (!strcmp(buf, "ax") || !strcmp(buf, "cx") || - !strcmp(buf, "dx") || !strcmp(buf, "bx") || - !strcmp(buf, "sp") || !strcmp(buf, "bp") || - !strcmp(buf, "si") || !strcmp(buf, "di") || - buf[n - 1] == 'w') { + } else if (slice_eq_cstr(q, "ax") || slice_eq_cstr(q, "cx") || + slice_eq_cstr(q, "dx") || slice_eq_cstr(q, "bx") || + slice_eq_cstr(q, "sp") || slice_eq_cstr(q, "bp") || + slice_eq_cstr(q, "si") || slice_eq_cstr(q, "di") || + buf[sl.len - 1] == 'w') { width = 2; - } else if (buf[n - 1] == 'd' || buf[0] == 'e') { + } else if (buf[sl.len - 1] == 'd' || buf[0] == 'e') { width = 4; } if (reg_out) *reg_out = reg; @@ -89,8 +93,9 @@ static int x64_reg_from_name(AsmDriver* d, Sym s, u32* reg_out, } static int x64_xmm_from_name(AsmDriver* d, Sym s, u32* reg_out) { - size_t n = 0; - const char* p = pool_str(asm_driver_pool(d), s, &n); + Slice sl = pool_slice(asm_driver_pool(d), s); + const char* p = sl.s; + size_t n = sl.len; u32 reg = 0; if (!p || n < 4 || n > 5) return 0; if (p[0] != 'x' || p[1] != 'm' || p[2] != 'm') return 0; @@ -104,8 +109,9 @@ static int x64_xmm_from_name(AsmDriver* d, Sym s, u32* reg_out) { } static int x64_segment_prefix_from_name(AsmDriver* d, Sym s, u8* prefix_out) { - size_t n = 0; - const char* p = pool_str(asm_driver_pool(d), s, &n); + Slice sl = pool_slice(asm_driver_pool(d), s); + const char* p = sl.s; + size_t n = sl.len; if (!p || n != 2) return 0; if (p[0] == 'f' && p[1] == 's') { if (prefix_out) *prefix_out = 0x64; @@ -480,10 +486,9 @@ static int parse_mnemonic(const char* s, size_t n, X64MnInfo* out) { tail = n - 1; } if (tail > after) { - size_t cc_n = tail - after; + Slice cc = {{s + after}, tail - after}; for (size_t i = 0; i < sizeof kCC / sizeof kCC[0]; ++i) { - size_t kn = strlen(kCC[i].name); - if (cc_n == kn && memcmp(s + after, kCC[i].name, kn) == 0) { + if (slice_eq_cstr(cc, kCC[i].name)) { out->cc = kCC[i].cc; memcpy(out->base, "cmov", 4); out->base[4] = '\0'; @@ -496,10 +501,9 @@ static int parse_mnemonic(const char* s, size_t n, X64MnInfo* out) { /* SETcc: set<cc>. */ if (n > 3 && memcmp(s, "set", 3) == 0) { - size_t cc_n = n - 3; + Slice cc = {{s + 3}, n - 3}; for (size_t i = 0; i < sizeof kCC / sizeof kCC[0]; ++i) { - size_t kn = strlen(kCC[i].name); - if (cc_n == kn && memcmp(s + 3, kCC[i].name, kn) == 0) { + if (slice_eq_cstr(cc, kCC[i].name)) { out->cc = kCC[i].cc; memcpy(out->base, "set", 3); out->base[3] = '\0'; @@ -511,10 +515,9 @@ static int parse_mnemonic(const char* s, size_t n, X64MnInfo* out) { /* Jcc: j<cc> — but NOT "jmp" / "jmpq" (handled above). */ if (n > 1 && s[0] == 'j' && !(n >= 3 && s[1] == 'm' && s[2] == 'p')) { - size_t cc_n = n - 1; + Slice cc = {{s + 1}, n - 1}; for (size_t i = 0; i < sizeof kCC / sizeof kCC[0]; ++i) { - size_t kn = strlen(kCC[i].name); - if (cc_n == kn && memcmp(s + 1, kCC[i].name, kn) == 0) { + if (slice_eq_cstr(cc, kCC[i].name)) { out->cc = kCC[i].cc; out->base[0] = 'j'; out->base[1] = '\0'; @@ -556,11 +559,10 @@ static u32 row_implied_width(const X64InsnDesc* d) { * AND whose width filter is compatible. Returns NULL on miss. */ static const X64InsnDesc* find_mnemonic_row(const X64MnInfo* info) { u32 want_w = info->width; /* 0 = any */ + Slice base = {{info->base}, info->base_len}; for (u32 i = 0; i < x64_insn_table_n; ++i) { const X64InsnDesc* d = &x64_insn_table[i]; - size_t mn = strlen(d->mnemonic); - if (mn != info->base_len) continue; - if (memcmp(d->mnemonic, info->base, mn) != 0) continue; + if (!slice_eq(d->mnemonic, base)) continue; if (want_w != 0) { u32 rw = row_implied_width(d); if (rw != 0 && rw != want_w) continue; @@ -608,12 +610,11 @@ static void parse_br_rm(X64ParseCtx* p) { /* Look up the ALU_RM_IMM8 row for a given mnemonic root; the /digit * picks the operation (0=add, 1=or, 4=and, 5=sub, 6=xor, 7=cmp). */ -static const X64InsnDesc* find_alu_imm_row(const char* root, u32 root_len) { +static const X64InsnDesc* find_alu_imm_row(Slice root) { for (u32 i = 0; i < x64_insn_table_n; ++i) { const X64InsnDesc* d = &x64_insn_table[i]; if (d->fmt != X64_FMT_ALU_RM_IMM8) continue; - if (strlen(d->mnemonic) != root_len) continue; - if (memcmp(d->mnemonic, root, root_len) != 0) continue; + if (!slice_eq(d->mnemonic, root)) continue; return d; } return NULL; @@ -633,9 +634,7 @@ static void parse_alu_rr(X64ParseCtx* p) { /* Immediate source → not an ALU_RR encoding. Redirect to the * ALU_RM_IMM row for this mnemonic. */ if (src.kind == X64_ASM_OP_IMM && dst.kind == X64_ASM_OP_REG) { - const X64InsnDesc* imm_row = - find_alu_imm_row(p->desc->mnemonic, - (u32)strlen(p->desc->mnemonic)); + const X64InsnDesc* imm_row = find_alu_imm_row(p->desc->mnemonic); if (!imm_row) asm_driver_panic(p->d, "x64 asm: no alu-imm row"); if (imm_fits_i8(src.imm)) emit_alu_imm8(p->mc, width_to_w(p->width), imm_row->modrm_reg, dst.reg, @@ -1013,15 +1012,15 @@ static void parse_sse_rr(X64ParseCtx* p) { } if (dst.kind == X64_ASM_OP_MEM && src.kind == X64_ASM_OP_XMM && p->desc->opc[1] == 0x10u && - (!strcmp(p->desc->mnemonic, "movsd") || - !strcmp(p->desc->mnemonic, "movss"))) { + (slice_eq_cstr(p->desc->mnemonic, "movsd") || + slice_eq_cstr(p->desc->mnemonic, "movss"))) { emit_sse_store(p->mc, p->desc->leg_pfx, 0x11, src.reg, dst.base, dst.disp); return; } if (dst.kind == X64_ASM_OP_MEM && src.kind == X64_ASM_OP_XMM && p->desc->opc[1] == 0x28u && - !strcmp(p->desc->mnemonic, "movaps")) { + slice_eq_cstr(p->desc->mnemonic, "movaps")) { emit_sse_store(p->mc, p->desc->leg_pfx, 0x29, src.reg, dst.base, dst.disp); return; @@ -1179,8 +1178,9 @@ static u32 width_from_info(const X64MnInfo* info, const X64InsnDesc* d) { static void x64_arch_asm_insn(ArchAsm* base, AsmDriver* d, Sym mnemonic) { X64Asm* a = (X64Asm*)base; MCEmitter* mc = asm_driver_mc(d); - size_t n = 0; - const char* p = pool_str(asm_driver_pool(d), mnemonic, &n); + Slice mnsl = pool_slice(asm_driver_pool(d), mnemonic); + const char* p = mnsl.s; + size_t n = mnsl.len; X64MnInfo info; const X64InsnDesc* desc; X64ParseCtx ctx; @@ -1214,8 +1214,7 @@ static void x64_arch_asm_insn(ArchAsm* base, AsmDriver* d, Sym mnemonic) { for (u32 i = 0; i < x64_insn_table_n; ++i) { const X64InsnDesc* dr = &x64_insn_table[i]; if (dr->fmt == X64_FMT_MOV_RI && - strlen(dr->mnemonic) == 3 && - memcmp(dr->mnemonic, "mov", 3) == 0) { + slice_eq_cstr(dr->mnemonic, "mov")) { ctx.d = d; ctx.mc = mc; ctx.desc = dr; @@ -1275,8 +1274,7 @@ static void x64_arch_asm_insn(ArchAsm* base, AsmDriver* d, Sym mnemonic) { for (u32 i = 0; i < x64_insn_table_n; ++i) { const X64InsnDesc* dr = &x64_insn_table[i]; if (dr->fmt != X64_FMT_BR_RM) continue; - if (strlen(dr->mnemonic) != info.base_len) continue; - if (memcmp(dr->mnemonic, info.base, info.base_len) != 0) continue; + if (!slice_eq(dr->mnemonic, (Slice){{info.base}, info.base_len})) continue; desc = dr; break; } @@ -1325,7 +1323,8 @@ void x64_inline_bind(X64Asm* a, const AsmConstraint* outs, u32 nout, _Noreturn static void inline_panic(X64Asm* a, const char* msg) { SrcLoc loc = {0, 0, 0}; - compiler_panic(a->c, loc, "x64 inline asm: %s", msg); + compiler_panic(a->c, loc, "x64 inline asm: %.*s", + SLICE_ARG(slice_from_cstr(msg))); } /* Width selector for x64_reg_spelling: matches the operand-modifier @@ -1464,7 +1463,7 @@ static void render_operand(X64Asm* a, StrBuf* sb, u32 idx, int form) { } static u32 find_named_operand(X64Asm* a, const char* name, size_t len) { - Sym needle = pool_intern(a->c->global, name, len); + Sym needle = pool_intern_slice(a->c->global, (Slice){.s = name, .len = len}); u32 i; for (i = 0; i < a->nout; ++i) { if (a->outs[i].name == needle) return i; diff --git a/src/arch/x64/disasm.c b/src/arch/x64/disasm.c @@ -36,7 +36,7 @@ typedef struct X64Disasm { static void emit_mnemonic(StrBuf* sb, const X64InsnDesc* d, const X64DecodeCtx* ctx, const u8* bytes) { if (ctx->has_lock) strbuf_puts(sb, "lock "); - strbuf_puts(sb, d->mnemonic); + strbuf_put_slice(sb, d->mnemonic); /* Jcc / SETcc / CMOVcc: the table stores the bare prefix ("j", "set", * "cmov") and we append the condition suffix from the opcode byte. */ if (d->fmt == X64_FMT_JCC_REL32 || d->fmt == X64_FMT_SETCC_RM || @@ -81,9 +81,9 @@ static u32 x64_decode(ArchDisasm* base, const u8* bytes, size_t len, u64 vaddr, out->vaddr = vaddr; out->bytes = bytes; out->nbytes = 1; - out->mnemonic = strbuf_cstr(&d->mnem); - out->operands = strbuf_cstr(&d->ops); - out->annotation = strbuf_cstr(&d->ann); + out->mnemonic = strbuf_slice(&d->mnem); + out->operands = strbuf_slice(&d->ops); + out->annotation = strbuf_slice(&d->ann); return 1; } @@ -93,9 +93,9 @@ static u32 x64_decode(ArchDisasm* base, const u8* bytes, size_t len, u64 vaddr, out->vaddr = vaddr; out->bytes = bytes; out->nbytes = 1; - out->mnemonic = strbuf_cstr(&d->mnem); - out->operands = strbuf_cstr(&d->ops); - out->annotation = strbuf_cstr(&d->ann); + out->mnemonic = strbuf_slice(&d->mnem); + out->operands = strbuf_slice(&d->ops); + out->annotation = strbuf_slice(&d->ann); return 1; } @@ -107,18 +107,18 @@ static u32 x64_decode(ArchDisasm* base, const u8* bytes, size_t len, u64 vaddr, out->vaddr = vaddr; out->bytes = bytes; out->nbytes = 1; - out->mnemonic = strbuf_cstr(&d->mnem); - out->operands = strbuf_cstr(&d->ops); - out->annotation = strbuf_cstr(&d->ann); + out->mnemonic = strbuf_slice(&d->mnem); + out->operands = strbuf_slice(&d->ops); + out->annotation = strbuf_slice(&d->ann); return 1; } out->vaddr = vaddr; out->bytes = bytes; out->nbytes = total; - out->mnemonic = strbuf_cstr(&d->mnem); - out->operands = strbuf_cstr(&d->ops); - out->annotation = strbuf_cstr(&d->ann); + out->mnemonic = strbuf_slice(&d->mnem); + out->operands = strbuf_slice(&d->ops); + out->annotation = strbuf_slice(&d->ann); return total; } diff --git a/src/arch/x64/emit.c b/src/arch/x64/emit.c @@ -11,6 +11,7 @@ #include "arch/x64/x64.h" #include "core/arena.h" #include "core/pool.h" +#include "core/slice.h" #include "obj/obj.h" #include "arch/x64/internal.h" @@ -832,7 +833,7 @@ static u32 x_compute_frame_size(const XImpl *a, u32 cs_used, u32 cs_fp_used) { * cfree references it on demand from the prologue and lets the linker * resolve it. */ static ObjSymId x_chkstk_sym(CGTarget *t) { - Sym name = pool_intern_cstr(t->c->global, "__chkstk"); + Sym name = pool_intern_slice(t->c->global, SLICE_LIT("__chkstk")); ObjSymId s = obj_symbol_find(t->obj, name); if (s != 0) return s; return obj_symbol(t->obj, name, SB_GLOBAL, SK_UNDEF, OBJ_SEC_NONE, 0, 0); diff --git a/src/arch/x64/internal.h b/src/arch/x64/internal.h @@ -17,6 +17,7 @@ #include "arch/x64/x64.h" #include "core/arena.h" #include "core/pool.h" +#include "core/slice.h" #include "obj/obj.h" /* Prologue placeholder budget for the unplanned-regs path (the C @@ -185,7 +186,8 @@ static inline int type_is_signed(CfreeCgTypeId t) { static inline _Noreturn void x_panic(CGTarget* t, const char* what) { SrcLoc loc = impl_of(t)->loc; - compiler_panic(t->c, loc, "x64: %s not implemented", what); + compiler_panic(t->c, loc, "x64: %.*s not implemented", + SLICE_ARG(slice_from_cstr(what))); } /* ============================================================ diff --git a/src/arch/x64/isa.c b/src/arch/x64/isa.c @@ -28,7 +28,7 @@ * ==================================================================== */ #define ROW(mn, lp, ol, b0, b1, b2, lm, mr, wr, f, fl) \ - {mn, lp, ol, {b0, b1, b2}, lm, mr, wr, f, fl} + {{{(mn)}, sizeof(mn) - 1}, lp, ol, {b0, b1, b2}, lm, mr, wr, f, fl} #define NO_MODRM 0xFFu const X64InsnDesc x64_insn_table[] = { diff --git a/src/arch/x64/isa.h b/src/arch/x64/isa.h @@ -30,6 +30,7 @@ #include "core/bytes.h" #include "core/core.h" +#include "core/slice.h" #include "core/strbuf.h" /* ---- GPR numbering (DWARF / ABI matches HW encoding 0..15) ---- */ @@ -307,7 +308,7 @@ typedef enum X64Format { * ==================================================================== */ typedef struct X64InsnDesc { - const char* mnemonic; /* AT&T mnemonic without size suffix; printer adds + Slice mnemonic; /* AT&T mnemonic without size suffix; printer adds a size letter (b/w/l/q) based on fmt + ctx. */ u8 leg_pfx; /* X64_PFX_NONE / 0x66 / 0xF2 / 0xF3 */ u8 opc_len; /* 1..3 */ diff --git a/src/arch/x64/ops.c b/src/arch/x64/ops.c @@ -19,6 +19,7 @@ #include "arch/x64/x64.h" #include "core/arena.h" #include "core/pool.h" +#include "core/slice.h" #include "obj/obj.h" /* ============================================================ @@ -36,7 +37,7 @@ static void x_load_const(CGTarget* t, Operand dst, ConstBytes cb) { if (dst.cls != RC_FP) compiler_panic(t->c, a->loc, "x64 load_const: only FP supported in v1"); - Sym ro_name = pool_intern_cstr(t->c->global, ".rodata"); + Sym ro_name = pool_intern_slice(t->c->global, SLICE_LIT(".rodata")); ObjSecId ro = obj_section(t->obj, ro_name, SEC_RODATA, SF_ALLOC, 1u); u32 cur_section = t->mc->section_id; @@ -62,7 +63,7 @@ static void x_load_const(CGTarget* t, Operand dst, ConstBytes cb) { for (int i = tn - 1; i >= 0; --i) namebuf[len++] = tmp[i]; namebuf[len] = 0; - Sym sname = pool_intern_cstr(t->c->global, namebuf); + Sym sname = pool_intern_slice(t->c->global, slice_from_cstr(namebuf)); ObjSymId sym = obj_symbol(t->obj, sname, SB_LOCAL, SK_OBJ, ro, (u64)ro_off, (u64)cb.size); t->mc->set_section(t->mc, cur_section); @@ -450,7 +451,7 @@ static void x_tls_addr_of_win64(CGTarget* t, Operand dst, ObjSymId sym, emit_u32le(mc, 0x58u); /* (2) mov r11d, [rip + _tls_index]: 44 8B 1D disp32. */ - Sym idx_name = pool_intern_cstr(t->c->global, "_tls_index"); + Sym idx_name = pool_intern_slice(t->c->global, SLICE_LIT("_tls_index")); ObjSymId idx_sym = obj_symbol_find(t->obj, idx_name); if (idx_sym == 0) { idx_sym = obj_symbol(t->obj, idx_name, SB_GLOBAL, SK_UNDEF, @@ -2578,8 +2579,9 @@ static void x_intrinsic(CGTarget* t, IntrinKind kind, Operand* dsts, u32 nd, Operand da = args[0], sa = args[1], nb = args[2]; if (da.kind != OPK_REG || sa.kind != OPK_REG || nb.kind != OPK_IMM) { compiler_panic(t->c, a->loc, - "x64 intrinsic: %s with non-const n or non-REG ptr", - kind == INTRIN_MEMCPY ? "memcpy" : "memmove"); + "x64 intrinsic: %.*s with non-const n or non-REG ptr", + SLICE_ARG(slice_from_cstr( + kind == INTRIN_MEMCPY ? "memcpy" : "memmove"))); } u32 dr = da.v.reg & 0xFu; u32 sr = sa.v.reg & 0xFu; diff --git a/src/arch/x64/regs.c b/src/arch/x64/regs.c @@ -2,7 +2,7 @@ #include "arch/x64/regs.h" -#include <string.h> +#include "core/slice.h" typedef struct X64Reg { uint32_t dwarf_idx; @@ -43,11 +43,13 @@ static int gpr_alias_index(const char* name, const uint32_t* map, {"r15", "r15d", "r15w", "r15b", NULL}, }; uint32_t i; + Slice q; if (!name) return 1; + q = slice_from_cstr(name); for (i = 0; i < 16u; ++i) { uint32_t j; for (j = 0; aliases[i][j]; ++j) { - if (!strcmp(name, aliases[i][j])) { + if (slice_eq_cstr(q, aliases[i][j])) { if (idx_out) *idx_out = map[i]; return 0; } @@ -71,10 +73,13 @@ int x64_register_index(const char* name, uint32_t* idx_out) { }; if (!name) return 1; if (name[0] == '%') ++name; - for (i = 0; i < X64_REGS_N; ++i) { - if (!strcmp(X64_REGS[i].name, name)) { - if (idx_out) *idx_out = X64_REGS[i].dwarf_idx; - return 0; + { + Slice q = slice_from_cstr(name); + for (i = 0; i < X64_REGS_N; ++i) { + if (slice_eq_cstr(q, X64_REGS[i].name)) { + if (idx_out) *idx_out = X64_REGS[i].dwarf_idx; + return 0; + } } } return gpr_alias_index(name, dwarf, idx_out); diff --git a/src/asm/asm.c b/src/asm/asm.c @@ -30,6 +30,7 @@ #include "core/hashmap.h" #include "core/heap.h" #include "core/pool.h" +#include "core/slice.h" #include "obj/obj.h" HASHMAP_DEFINE(SymSecMap, Sym, ObjSecId, hash_u32); @@ -111,7 +112,9 @@ _Noreturn static void d_panicf(AsmDriver* d, const char* fmt, ...) { /* ---- spelling helpers ---- */ static const char* asm_str(AsmDriver* d, Sym s, size_t* nout) { - return pool_str(d->pool, s, nout); + Slice sl = pool_slice(d->pool, s); + if (nout) *nout = sl.len; + return sl.s; } static int sym_eq(AsmDriver* d, Sym s, const char* lit) { @@ -422,7 +425,7 @@ ObjSymId asm_driver_intern_sym(AsmDriver* d, Sym name) { ObjSecId asm_driver_cur_section(AsmDriver* d) { if (d->cur_sec == OBJ_SEC_NONE) { - if (!d->n_text) d->n_text = pool_intern_cstr(d->pool, ".text"); + if (!d->n_text) d->n_text = pool_intern_slice(d->pool, SLICE_LIT(".text")); d->cur_sec = ensure_section(d, d->n_text, SEC_TEXT, (u16)(SF_ALLOC | SF_EXEC), 4); d->mc->set_section(d->mc, d->cur_sec); @@ -456,7 +459,8 @@ int asm_driver_eat_punct(AsmDriver* d, u32 p) { void asm_driver_expect_punct(AsmDriver* d, u32 p, const char* what) { if (!asm_driver_eat_punct(d, p)) - d_panicf(d, "asm: expected '%s' (%s)", "punct", what); + d_panicf(d, "asm: expected '%.*s' (%.*s)", SLICE_ARG(SLICE_LIT("punct")), + SLICE_ARG(slice_from_cstr(what))); } i64 asm_driver_parse_const(AsmDriver* d) { @@ -584,7 +588,7 @@ static void decode_string(AsmDriver* d, Sym spelling, u8** out, u32* nout) { static Sym expect_ident(AsmDriver* d, const char* what) { AsmTok t = d_peek(d); if (t.kind != ASM_TOK_IDENT) - d_panicf(d, "asm: %s: expected identifier", what); + d_panicf(d, "asm: %.*s: expected identifier", SLICE_ARG(slice_from_cstr(what))); (void)d_next(d); return t.v.ident; } @@ -621,25 +625,25 @@ static void emit_int_directive(AsmDriver* d, u32 width) { static void do_directive(AsmDriver* d, Sym name) { if (sym_eq(d, name, "text")) { - if (!d->n_text) d->n_text = pool_intern_cstr(d->pool, ".text"); + if (!d->n_text) d->n_text = pool_intern_slice(d->pool, SLICE_LIT(".text")); set_section(d, d->n_text, SEC_TEXT, (u16)(SF_ALLOC | SF_EXEC), 4); d_skip_to_eol(d); return; } if (sym_eq(d, name, "data")) { - if (!d->n_data) d->n_data = pool_intern_cstr(d->pool, ".data"); + if (!d->n_data) d->n_data = pool_intern_slice(d->pool, SLICE_LIT(".data")); set_section(d, d->n_data, SEC_DATA, (u16)(SF_ALLOC | SF_WRITE), 8); d_skip_to_eol(d); return; } if (sym_eq(d, name, "rodata")) { - if (!d->n_rodata) d->n_rodata = pool_intern_cstr(d->pool, ".rodata"); + if (!d->n_rodata) d->n_rodata = pool_intern_slice(d->pool, SLICE_LIT(".rodata")); set_section(d, d->n_rodata, SEC_RODATA, (u16)SF_ALLOC, 8); d_skip_to_eol(d); return; } if (sym_eq(d, name, "bss")) { - if (!d->n_bss) d->n_bss = pool_intern_cstr(d->pool, ".bss"); + if (!d->n_bss) d->n_bss = pool_intern_slice(d->pool, SLICE_LIT(".bss")); set_section(d, d->n_bss, SEC_BSS, (u16)(SF_ALLOC | SF_WRITE), 8); d_skip_to_eol(d); return; @@ -653,7 +657,8 @@ static void do_directive(AsmDriver* d, Sym name) { } else if (t.kind == ASM_TOK_STR) { size_t n = 0; const char* p = asm_str(d, t.spelling, &n); - if (n >= 2 && p[0] == '"') sname = pool_intern(d->pool, p + 1, n - 2); + if (n >= 2 && p[0] == '"') + sname = pool_intern_slice(d->pool, (Slice){ .s = p + 1, .len = n - 2 }); (void)d_next(d); } else if (tok_is_punct(t, '.')) { (void)d_next(d); @@ -665,7 +670,7 @@ static void do_directive(AsmDriver* d, Sym name) { if (ni + 1 >= sizeof buf) d_panicf(d, "asm: .section: name too long"); buf[0] = '.'; for (size_t i = 0; i < ni; ++i) buf[i + 1] = nm[i]; - sname = pool_intern(d->pool, buf, ni + 1); + sname = pool_intern_slice(d->pool, (Slice){ .s = buf, .len = ni + 1 }); } else { d_panicf(d, "asm: .section: expected name"); } @@ -747,7 +752,7 @@ static void do_directive(AsmDriver* d, Sym name) { size_t sn = 0; const char* sp = asm_str(d, t.spelling, &sn); if (sn >= 2 && sp[0] == '"' && sp[sn - 1] == '"') - tag = pool_intern(d->pool, sp + 1, sn - 2); + tag = pool_intern_slice(d->pool, (Slice){ .s = sp + 1, .len = sn - 2 }); } else { d_panicf(d, "asm: .type: tag"); } @@ -945,7 +950,7 @@ static Sym maybe_compose_mnemonic(AsmDriver* d, Sym head) { for (size_t i = 0; i < hn; ++i) buf[i] = hp[i]; buf[hn] = '.'; for (size_t i = 0; i < rn; ++i) buf[hn + 1 + i] = rp[i]; - head = pool_intern(d->pool, buf, n); + head = pool_intern_slice(d->pool, (Slice){ .s = buf, .len = n }); } } diff --git a/src/asm/asm_lex.c b/src/asm/asm_lex.c @@ -15,6 +15,7 @@ #include "core/heap.h" #include "core/pool.h" +#include "core/slice.h" struct AsmLexer { Compiler* c; @@ -129,7 +130,8 @@ AsmLexer* asm_lex_open_mem(Compiler* c, const char* name, const char* src, l->src = src ? src : ""; l->len = src ? len : 0; l->pos = 0; - if (source_add_memory(c->sources, name, &l->file_id) != CFREE_OK) { + if (source_add_memory(c->sources, slice_from_cstr(name), &l->file_id) != + CFREE_OK) { h->free(h, l, sizeof(*l)); return NULL; } @@ -168,7 +170,9 @@ static Sym intern_spliced(AsmLexer* l, size_t start, size_t end) { break; } } - if (!has_splice) return pool_intern(l->pool, l->src + start, end - start); + if (!has_splice) + return pool_intern_slice( + l->pool, (Slice){ .s = l->src + start, .len = end - start }); buf = (char*)l->heap->alloc(l->heap, end - start, 1); k = 0; @@ -179,7 +183,7 @@ static Sym intern_spliced(AsmLexer* l, size_t start, size_t end) { } buf[k++] = l->src[i++]; } - sym = pool_intern(l->pool, buf, k); + sym = pool_intern_slice(l->pool, (Slice){ .s = buf, .len = k }); l->heap->free(l->heap, buf, end - start); return sym; } @@ -474,7 +478,7 @@ AsmTok asm_lex_next(AsmLexer* l) { break; } } - t.spelling = pool_intern(l->pool, pbuf, k); + t.spelling = pool_intern_slice(l->pool, (Slice){ .s = pbuf, .len = k }); l->heap->free(l->heap, pbuf, plen ? plen : 1); return t; } diff --git a/src/cg/arith.c b/src/cg/arith.c @@ -949,7 +949,8 @@ CfreeCgTypeId api_atomic_pointee(CfreeCg* g, CfreeCgTypeId pty, const char* who) { CfreeCgTypeId pointee = cg_type_pointee(g->c, pty); if (!pointee) { - compiler_panic(g->c, g->cur_loc, "%s: operand is not a pointer", who); + compiler_panic(g->c, g->cur_loc, "%.*s: operand is not a pointer", + SLICE_ARG(slice_from_cstr(who))); return builtin_id(CFREE_CG_BUILTIN_I32); } return pointee; diff --git a/src/cg/asm.c b/src/cg/asm.c @@ -1,11 +1,9 @@ #include "cg/internal.h" const char* api_sym_cstr(CfreeCg* g, CfreeSym sym) { - size_t len; const char* s; if (!sym) return ""; - s = pool_str(g->c->global, (Sym)sym, &len); - (void)len; + s = pool_slice(g->c->global, (Sym)sym).s; return s ? s : ""; } @@ -240,7 +238,7 @@ void cfree_cg_inline_asm(CfreeCg* g, CfreeCgInlineAsm asm_block) { out_reg_owned[i] = 1; } - sym_memory = pool_intern_cstr(g->c->global, "memory"); + sym_memory = pool_intern_slice(g->c->global, SLICE_LIT("memory")); has_memory_clobber = 0; for (u32 i = 0; i < nclobbers; ++i) { if (clobs[i] == sym_memory) has_memory_clobber = 1; @@ -304,10 +302,9 @@ void cfree_cg_inline_asm(CfreeCg* g, CfreeCgInlineAsm asm_block) { if (out_reg_owned) h->free(h, out_reg_owned, noutputs); } -void cfree_cg_file_scope_asm(CfreeCg* g, const char* asm_source, - size_t asm_source_len) { +void cfree_cg_file_scope_asm(CfreeCg* g, CfreeSlice asm_source) { AsmLexer* lex; - if (!g || !asm_source) return; + if (!g || !asm_source.s) return; /* The C-source backend bypasses MCEmitter entirely; file-scope asm has * no portable C source equivalent (Phase 4 territory — see * doc/CBACKEND.md). Panic with the same shape as other unimplemented @@ -317,7 +314,8 @@ void cfree_cg_file_scope_asm(CfreeCg* g, const char* asm_source, "C target: file-scope asm not yet supported"); } api_local_const_memory_boundary(g); - lex = asm_lex_open_mem(g->c, "<file-scope asm>", asm_source, asm_source_len); + lex = asm_lex_open_mem(g->c, "<file-scope asm>", asm_source.s, + asm_source.len); if (!lex) compiler_panic(g->c, api_no_loc(), "CfreeCg: file-scope asm out of memory"); asm_parse(g->c, lex, g->mc); diff --git a/src/cg/control.c b/src/cg/control.c @@ -404,21 +404,25 @@ ApiCgScope* api_scope_from_handle(CfreeCg* g, CfreeCgScope scope, slot = ((u32)scope & 0xffu); generation = ((u32)scope >> 8); if (slot == 0 || slot > API_CG_MAX_SCOPES) { - compiler_panic(g->c, g->cur_loc, "%s: invalid scope handle", who); + compiler_panic(g->c, g->cur_loc, "%.*s: invalid scope handle", + SLICE_ARG(slice_from_cstr(who))); return NULL; } slot--; if (slot >= g->nscopes) { - compiler_panic(g->c, g->cur_loc, "%s: stale scope handle", who); + compiler_panic(g->c, g->cur_loc, "%.*s: stale scope handle", + SLICE_ARG(slice_from_cstr(who))); return NULL; } if (require_top && slot + 1u != g->nscopes) { - compiler_panic(g->c, g->cur_loc, "%s: non-LIFO scope end", who); + compiler_panic(g->c, g->cur_loc, "%.*s: non-LIFO scope end", + SLICE_ARG(slice_from_cstr(who))); return NULL; } s = &g->scopes[slot]; if (!s->active || s->generation != generation) { - compiler_panic(g->c, g->cur_loc, "%s: stale scope handle", who); + compiler_panic(g->c, g->cur_loc, "%.*s: stale scope handle", + SLICE_ARG(slice_from_cstr(who))); return NULL; } return s; diff --git a/src/cg/data.c b/src/cg/data.c @@ -122,8 +122,9 @@ void cfree_cg_data_begin(CfreeCg* g, CfreeCgSym cg_sym, } else if (attrs.flags & CFREE_CG_DATADEF_ZERO_FILL) { sec_kind = SEC_BSS; sec_flags = SF_ALLOC | SF_WRITE; - sec_name_sym = attrs.section ? (Sym)attrs.section - : pool_intern_cstr(c->global, ".bss"); + sec_name_sym = attrs.section + ? (Sym)attrs.section + : pool_intern_slice(c->global, SLICE_LIT(".bss")); } else if (attrs.section) { sec_name_sym = (Sym)attrs.section; if (attrs.flags & CFREE_CG_DATADEF_READONLY) { @@ -137,7 +138,7 @@ void cfree_cg_data_begin(CfreeCg* g, CfreeCgSym cg_sym, (decl_attrs.as.object.flags & CFREE_CG_OBJ_READONLY)) { sec_kind = SEC_RODATA; sec_flags = SF_ALLOC; - sec_name_sym = pool_intern_cstr(c->global, ".rodata"); + sec_name_sym = pool_intern_slice(c->global, SLICE_LIT(".rodata")); } else if (decl_attrs.as.object.flags & CFREE_CG_OBJ_TLS) { sec_kind = SEC_DATA; sec_flags = SF_ALLOC | SF_WRITE | SF_TLS; @@ -145,7 +146,7 @@ void cfree_cg_data_begin(CfreeCg* g, CfreeCgSym cg_sym, } else { sec_kind = SEC_DATA; sec_flags = SF_ALLOC | SF_WRITE; - sec_name_sym = pool_intern_cstr(c->global, ".data"); + sec_name_sym = pool_intern_slice(c->global, SLICE_LIT(".data")); } if (attrs.flags & CFREE_CG_DATADEF_RETAIN) sec_flags |= SF_RETAIN; if (attrs.flags & CFREE_CG_DATADEF_MERGE) sec_flags |= SF_MERGE; @@ -630,6 +631,7 @@ ObjSymId api_emit_label_table(CfreeCg* g, const Label* labels, u32 n) { RelocKind rk; u8 pad[8]; char name_buf[40]; + StrBuf name_sb; Sym anon; ObjSymId sym; u32 i; @@ -659,7 +661,7 @@ ObjSymId api_emit_label_table(CfreeCg* g, const Label* labels, u32 n) { (unsigned)ptrsz); return OBJ_SYM_NONE; } - sec_name = pool_intern_cstr(c->global, ".rodata"); + sec_name = pool_intern_slice(c->global, SLICE_LIT(".rodata")); sec = obj_section(ob, sec_name, SEC_RODATA, SF_ALLOC, ptral); base = obj_align_to(ob, sec, ptral); /* Write `n` placeholder slots first; emit_label_data_reloc later @@ -680,8 +682,12 @@ ObjSymId api_emit_label_table(CfreeCg* g, const Label* labels, u32 n) { mc->emit_label_data_reloc(mc, sec, base + i * ptrsz, ml, rk, ptrsz, /*extra_addend=*/0); } - snprintf(name_buf, sizeof name_buf, ".Lcfree_jt.%u", g->rodata_counter++); - anon = pool_intern_cstr(c->global, name_buf); + strbuf_init(&name_sb, name_buf, sizeof name_buf); + strbuf_put_slice(&name_sb, SLICE_LIT(".Lcfree_jt.")); + strbuf_put_u64(&name_sb, g->rodata_counter++); + anon = pool_intern_slice( + c->global, + (Slice){.s = strbuf_cstr(&name_sb), .len = strbuf_len(&name_sb)}); sym = obj_symbol(ob, anon, SB_LOCAL, SK_OBJ, sec, base, (u64)n * ptrsz); return sym; } diff --git a/src/cg/debug.c b/src/cg/debug.c @@ -9,7 +9,8 @@ DebugTypeId api_debug_type(CfreeCg* g, CfreeCgTypeId id) { case CFREE_CG_TYPE_VOID: return debug_type_void(g->debug); case CFREE_CG_TYPE_BOOL: - return debug_type_base(g->debug, pool_intern_cstr(g->c->global, "_Bool"), + return debug_type_base(g->debug, + pool_intern_slice(g->c->global, SLICE_LIT("_Bool")), DEBUG_BE_BOOL, 1); case CFREE_CG_TYPE_INT: { const char* name = "long long"; @@ -19,14 +20,15 @@ DebugTypeId api_debug_type(CfreeCg* g, CfreeCgTypeId id) { name = "short"; else if (ty->integer.width <= 32) name = "int"; - return debug_type_base(g->debug, pool_intern_cstr(g->c->global, name), - DEBUG_BE_SIGNED, - (u32)((ty->integer.width + 7u) / 8u)); + return debug_type_base( + g->debug, pool_intern_slice(g->c->global, slice_from_cstr(name)), + DEBUG_BE_SIGNED, (u32)((ty->integer.width + 7u) / 8u)); } case CFREE_CG_TYPE_FLOAT: { const char* name = ty->fp.width <= 32 ? "float" : "double"; - return debug_type_base(g->debug, pool_intern_cstr(g->c->global, name), - DEBUG_BE_FLOAT, (u32)((ty->fp.width + 7u) / 8u)); + return debug_type_base( + g->debug, pool_intern_slice(g->c->global, slice_from_cstr(name)), + DEBUG_BE_FLOAT, (u32)((ty->fp.width + 7u) / 8u)); } case CFREE_CG_TYPE_PTR: { DebugTypeId pointee = api_debug_type(g, ty->ptr.pointee); @@ -68,7 +70,8 @@ DebugTypeId api_debug_type(CfreeCg* g, CfreeCgTypeId id) { return debug_type_record_end(b); } case CFREE_CG_TYPE_ENUM: - return debug_type_base(g->debug, pool_intern_cstr(g->c->global, "int"), + return debug_type_base(g->debug, + pool_intern_slice(g->c->global, SLICE_LIT("int")), DEBUG_BE_SIGNED, ty->size ? (u32)ty->size : 4u); case CFREE_CG_TYPE_ALIAS: { DebugTypeId base = api_debug_type(g, ty->alias.base); diff --git a/src/cg/internal.h b/src/cg/internal.h @@ -17,6 +17,8 @@ #include "core/heap.h" #include "core/pool.h" #include "core/segvec.h" +#include "core/slice.h" +#include "core/strbuf.h" #include "debug/debug.h" #include "obj/obj.h" #include "opt/opt.h" @@ -221,8 +223,7 @@ const char* api_asm_constraint_body(const char* s); int api_asm_is_early_clobber(const char* s); void api_asm_spill_sv(CfreeCg* g, ApiSValue* sv, Reg phys, RegClass cls); void cfree_cg_inline_asm(CfreeCg* g, CfreeCgInlineAsm asm_block); -void cfree_cg_file_scope_asm(CfreeCg* g, const char* asm_source, - size_t asm_source_len); +void cfree_cg_file_scope_asm(CfreeCg* g, CfreeSlice asm_source); MemAccess api_mem_for_atomic(CfreeCg* g, CfreeCgTypeId val_ty); int cfree_cg_atomic_is_legal(CfreeCompiler* c, CfreeCgMemAccess access, CfreeCgMemOrder order); diff --git a/src/cg/memory.c b/src/cg/memory.c @@ -58,6 +58,7 @@ CfreeCgSym cfree_cg_const_data(CfreeCg* g, const uint8_t* data, size_t len, ObjSecId sec; u32 base; char name_buf[32]; + StrBuf name_sb; Sym anon_name; ObjSymId sym; CfreeCgDecl attrs; @@ -66,14 +67,18 @@ CfreeCgSym cfree_cg_const_data(CfreeCg* g, const uint8_t* data, size_t len, ob = g->obj; pty = resolve_type(c, pointee_type); if (!pty) return CFREE_CG_SYM_NONE; - sec_name = pool_intern_cstr(c->global, ".rodata"); + sec_name = pool_intern_slice(c->global, SLICE_LIT(".rodata")); sec = obj_section(ob, sec_name, SEC_RODATA, SF_ALLOC, align ? align : (u32)abi_cg_alignof(c->abi, pointee_type)); base = obj_align_to( ob, sec, align ? align : (u32)abi_cg_alignof(c->abi, pointee_type)); obj_write(ob, sec, data, len); - snprintf(name_buf, sizeof(name_buf), ".Lcfree_ro.%u", g->rodata_counter++); - anon_name = pool_intern_cstr(c->global, name_buf); + strbuf_init(&name_sb, name_buf, sizeof(name_buf)); + strbuf_put_slice(&name_sb, SLICE_LIT(".Lcfree_ro.")); + strbuf_put_u64(&name_sb, g->rodata_counter++); + anon_name = pool_intern_slice( + c->global, + (Slice){.s = strbuf_cstr(&name_sb), .len = strbuf_len(&name_sb)}); sym = obj_symbol(ob, anon_name, SB_LOCAL, SK_OBJ, sec, base, (u64)len); memset(&attrs, 0, sizeof(attrs)); attrs.kind = CFREE_CG_DECL_OBJECT; diff --git a/src/cg/session.c b/src/cg/session.c @@ -232,7 +232,8 @@ void cfree_cg_func_begin_attrs(CfreeCg* g, CfreeCgSym cg_sym, attrs = api_sym_attrs(g, cg_sym); abi = abi_cg_func_info(c->abi, fty); - text_sec = obj_section(ob, pool_intern_cstr(c->global, ".text"), SEC_TEXT, + text_sec = obj_section(ob, pool_intern_slice(c->global, SLICE_LIT(".text")), + SEC_TEXT, SF_EXEC | SF_ALLOC, 4); if (sym != OBJ_SYM_NONE) { diff --git a/src/cg/value.c b/src/cg/value.c @@ -433,7 +433,8 @@ CfreeCgTypeId api_mem_access_type(CfreeCg* g, CfreeCgMemAccess access, CfreeCgTypeId ty = resolve_type(g->c, access.type); if (!ty) ty = resolve_type(g->c, fallback); if (!ty) { - compiler_panic(g->c, g->cur_loc, "CfreeCg: %s has no value type", who); + compiler_panic(g->c, g->cur_loc, "CfreeCg: %.*s has no value type", + SLICE_ARG(slice_from_cstr(who))); } return ty; } @@ -441,10 +442,12 @@ CfreeCgTypeId api_mem_access_type(CfreeCg* g, CfreeCgMemAccess access, u32 api_mem_type_size(CfreeCg* g, CfreeCgTypeId ty, const char* who) { ty = resolve_type(g->c, ty); if (!ty) { - compiler_panic(g->c, g->cur_loc, "CfreeCg: %s has invalid type", who); + compiler_panic(g->c, g->cur_loc, "CfreeCg: %.*s has invalid type", + SLICE_ARG(slice_from_cstr(who))); } if (cg_type_is_void(g->c, ty)) { - compiler_panic(g->c, g->cur_loc, "CfreeCg: %s uses void type", who); + compiler_panic(g->c, g->cur_loc, "CfreeCg: %.*s uses void type", + SLICE_ARG(slice_from_cstr(who))); } return abi_cg_sizeof(g->c->abi, ty); } @@ -453,17 +456,18 @@ void api_require_scalar_mem_type(CfreeCg* g, const char* who, CfreeCgTypeId ty) { if (cg_type_is_aggregate(g->c, ty)) { compiler_panic(g->c, g->cur_loc, - "CfreeCg: %s cannot use aggregate value type (size %u); " + "CfreeCg: %.*s cannot use aggregate value type (size %u); " "copy fields or use byte memory operations", - who, (unsigned)api_mem_type_size(g, ty, who)); + SLICE_ARG(slice_from_cstr(who)), + (unsigned)api_mem_type_size(g, ty, who)); } (void)api_mem_type_size(g, ty, who); } void api_require_pointer_value(CfreeCg* g, const char* who, CfreeCgTypeId ty) { if (!cg_type_pointee(g->c, ty)) { - compiler_panic(g->c, g->cur_loc, "CfreeCg: %s operand must be a pointer", - who); + compiler_panic(g->c, g->cur_loc, "CfreeCg: %.*s operand must be a pointer", + SLICE_ARG(slice_from_cstr(who))); } } @@ -476,22 +480,25 @@ void api_validate_memory_value(CfreeCg* g, const char* who, value_ty = resolve_type(g->c, value_ty); api_require_scalar_mem_type(g, who, access_ty); if (!value_ty) { - compiler_panic(g->c, g->cur_loc, "CfreeCg: %s value has no type", who); + compiler_panic(g->c, g->cur_loc, "CfreeCg: %.*s value has no type", + SLICE_ARG(slice_from_cstr(who))); } if (cg_type_is_aggregate(g->c, value_ty)) { compiler_panic(g->c, g->cur_loc, - "CfreeCg: %s value is aggregate (size %u); copy fields or " + "CfreeCg: %.*s value is aggregate (size %u); copy fields or " "use byte memory operations", - who, (unsigned)api_mem_type_size(g, value_ty, who)); + SLICE_ARG(slice_from_cstr(who)), + (unsigned)api_mem_type_size(g, value_ty, who)); } access_size = api_mem_type_size(g, access_ty, who); value_size = api_mem_type_size(g, value_ty, who); if (access_size != value_size || api_type_class(access_ty) != api_type_class(value_ty)) { compiler_panic(g->c, g->cur_loc, - "CfreeCg: %s value type/size mismatch: access size %u, " + "CfreeCg: %.*s value type/size mismatch: access size %u, " "value size %u", - who, (unsigned)access_size, (unsigned)value_size); + SLICE_ARG(slice_from_cstr(who)), (unsigned)access_size, + (unsigned)value_size); } } diff --git a/src/cg/wide.c b/src/cg/wide.c @@ -171,7 +171,8 @@ CfreeCgSym api_runtime_helper(CfreeCg* g, const char* name, CfreeCgTypeId ret, decl.kind = CFREE_CG_DECL_FUNC; decl.linkage_name = cfree_cg_c_linkage_name((CfreeCompiler*)g->c, - pool_intern_cstr(g->c->global, name)); + pool_intern_slice(g->c->global, + slice_from_cstr(name))); decl.display_name = decl.linkage_name; decl.type = cfree_cg_type_func((CfreeCompiler*)g->c, sig); decl.sym.bind = CFREE_SB_GLOBAL; diff --git a/src/core/core.h b/src/core/core.h @@ -87,8 +87,8 @@ void source_free(SourceManager*); CfreeStatus source_add_file(SourceManager*, const char* path, int system_header, u32* id_out); -CfreeStatus source_add_memory(SourceManager*, const char* name, u32* id_out); -CfreeStatus source_add_builtin(SourceManager*, const char* name, u32* id_out); +CfreeStatus source_add_memory(SourceManager*, CfreeSlice name, u32* id_out); +CfreeStatus source_add_builtin(SourceManager*, CfreeSlice name, u32* id_out); CfreeStatus source_add_include(SourceManager*, u32 includer_file_id, u32 included_file_id, SrcLoc include_loc, int system); diff --git a/src/core/pool.c b/src/core/pool.c @@ -95,7 +95,9 @@ void pool_fini(Pool* p) { p->entries = NULL; } -Sym pool_intern(Pool* p, const char* s, size_t len) { +Sym pool_intern_slice(Pool* p, Slice in) { + const char* s = in.s; + size_t len = in.len; u32 h, mask, i; Sym sym; @@ -110,12 +112,11 @@ Sym pool_intern(Pool* p, const char* s, size_t len) { if (sym_eq(&p->entries[sym], s, len, h)) return sym; i = (i + 1) & mask; } - /* Not found: allocate a new entry. The stored buffer carries a - * trailing NUL byte that callers may rely on (so `pool_str` can be - * fed straight to strcmp / printf %s); the recorded `len` is still - * the logical string length, exclusive of the terminator. The - * strtab content itself can carry embedded NULs, so consumers that - * care about exact bytes should compare via (len, memcmp). */ + /* Not found: allocate a new entry. The stored buffer carries a trailing + * NUL so a returned slice's pointer can be handed to a NUL-terminated + * boundary API; the recorded `len` is the logical length, exclusive of the + * terminator. The strtab content may carry embedded NULs, so exact-byte + * consumers compare via (len, memcmp). */ if (entries_grow(p)) return 0; { char* dst = (char*)arena_alloc(&p->arena, len + 1, 1); @@ -132,18 +133,7 @@ Sym pool_intern(Pool* p, const char* s, size_t len) { return sym; } -Sym pool_intern_cstr(Pool* p, const char* s) { - size_t n = 0; - if (!s) return 0; - while (s[n]) ++n; - return pool_intern(p, s, n); -} - -const char* pool_str(Pool* p, Sym sym, size_t* len_out) { - if (sym == 0 || sym >= p->nentries) { - if (len_out) *len_out = 0; - return NULL; - } - if (len_out) *len_out = p->entries[sym].len; - return p->entries[sym].data; +Slice pool_slice(Pool* p, Sym sym) { + if (sym == 0 || sym >= p->nentries) return SLICE_NULL; + return (Slice){ .s = p->entries[sym].data, .len = p->entries[sym].len }; } diff --git a/src/core/pool.h b/src/core/pool.h @@ -4,6 +4,7 @@ #include "core/arena.h" #include "core/core.h" #include "core/heap.h" +#include "core/slice.h" typedef struct PoolEntry { const char* data; @@ -32,9 +33,11 @@ struct Pool { void pool_init(Pool*, Heap*); void pool_fini(Pool*); -/* Strings. Returns canonical id; equal strings → equal ids. */ -Sym pool_intern(Pool*, const char* s, size_t len); -Sym pool_intern_cstr(Pool*, const char* s); -const char* pool_str(Pool*, Sym, size_t* len_out); +/* Interning. Returns the canonical id; equal byte sequences → equal ids + * (Sym 0 for the empty slice). pool_slice returns the interned bytes as a + * slice (SLICE_NULL for Sym 0); its pointer is NUL-terminated as a boundary + * convenience, with the NUL excluded from len. */ +Sym pool_intern_slice(Pool*, Slice); +Slice pool_slice(Pool*, Sym); #endif diff --git a/src/core/slice.c b/src/core/slice.c @@ -0,0 +1,28 @@ +#include "core/slice.h" + +#include <string.h> + +Slice slice_from_cstr(const char* z) { + if (!z) return SLICE_NULL; + return (Slice){ .s = z, .len = strlen(z) }; +} + +bool slice_eq(Slice a, Slice b) { + if (a.len != b.len) return false; + if (a.len == 0) return true; + return memcmp(a.s, b.s, a.len) == 0; +} + +bool slice_eq_cstr(Slice a, const char* z) { + size_t i; + if (!z) return a.len == 0; + for (i = 0; i < a.len; ++i) { + if (z[i] == '\0' || z[i] != a.s[i]) return false; + } + return z[a.len] == '\0'; +} + +Slice slice_dup(Arena* arena, Slice in) { + char* dst = arena_strdup(arena, in.s, in.len); + return (Slice){ .s = dst, .len = in.len }; +} diff --git a/src/core/slice.h b/src/core/slice.h @@ -0,0 +1,40 @@ +#ifndef CFREE_SLICE_H +#define CFREE_SLICE_H + +/* + * Internal fat-pointer string/byte view. `Slice` is the internal alias of the + * public CfreeSlice: a borrowed (ptr, len) pair, readable as text (`s`) or + * bytes (`data`). `len` never counts a trailing NUL. + * + * cfree carries lengths everywhere; NUL termination is only a boundary + * convenience. slice_from_cstr() is the single sanctioned place that scans a + * NUL terminator, used to lift OS/argv strings into slices at the boundary. + */ + +#include "core/arena.h" +#include "core/core.h" + +typedef CfreeSlice Slice; + +/* Build a slice from a string literal (length is compile-time, no strlen). */ +#define SLICE_LIT(lit) ((Slice){ .s = (lit), .len = sizeof(lit) - 1 }) +/* The empty slice. */ +#define SLICE_NULL ((Slice){ .s = NULL, .len = 0 }) +/* Spread a slice into printf "%.*s" arguments. */ +#define SLICE_ARG(x) CFREE_SLICE_ARG(x) + +/* Boundary helper: lift a NUL-terminated C string into a slice. The only + * sanctioned NUL scan; use exclusively where a string arrives from the OS + * (argv, getenv) or another NUL-terminated foreign API. NULL yields SLICE_NULL. */ +Slice slice_from_cstr(const char* z); + +/* Byte-exact equality. */ +bool slice_eq(Slice a, Slice b); +/* Equality against a NUL-terminated literal/string (compares bytes, no NUL). */ +bool slice_eq_cstr(Slice a, const char* z); + +/* Copy into the arena with a trailing NUL (so the result is also usable at a + * boundary). The trailing NUL is not counted in the returned length. */ +Slice slice_dup(Arena*, Slice); + +#endif diff --git a/src/core/source.c b/src/core/source.c @@ -7,6 +7,7 @@ #include "core/core.h" #include "core/heap.h" #include "core/pool.h" +#include "core/slice.h" typedef struct SrcMgrFile { SourceFile info; @@ -90,13 +91,13 @@ void source_free(SourceManager* sm) { sm->heap->free(sm->heap, sm, sizeof(*sm)); } -static CfreeStatus file_register(SourceManager* sm, const char* name, +static CfreeStatus file_register(SourceManager* sm, Slice name, SourceFileKind kind, int system_header, u32* id_out) { Sym sym; u32 id; if (files_grow(sm, sm->nfiles + 1)) return CFREE_NOMEM; - sym = pool_intern_cstr(sm->c->global, name ? name : ""); + sym = pool_intern_slice(sm->c->global, name); id = sm->nfiles++; memset(&sm->files[id], 0, sizeof(sm->files[id])); sm->files[id].info.id = id; @@ -110,15 +111,16 @@ static CfreeStatus file_register(SourceManager* sm, const char* name, CfreeStatus source_add_file(SourceManager* sm, const char* path, int system_header, u32* id_out) { - return file_register(sm, path, SRC_FILE_REAL, system_header, id_out); + return file_register(sm, slice_from_cstr(path ? path : ""), SRC_FILE_REAL, + system_header, id_out); } -CfreeStatus source_add_memory(SourceManager* sm, const char* name, +CfreeStatus source_add_memory(SourceManager* sm, CfreeSlice name, u32* id_out) { return file_register(sm, name, SRC_FILE_MEMORY, 0, id_out); } -CfreeStatus source_add_builtin(SourceManager* sm, const char* name, +CfreeStatus source_add_builtin(SourceManager* sm, CfreeSlice name, u32* id_out) { return file_register(sm, name, SRC_FILE_BUILTIN, 0, id_out); } diff --git a/src/core/strbuf.h b/src/core/strbuf.h @@ -12,6 +12,7 @@ #include <stddef.h> #include "core/core.h" +#include "core/slice.h" typedef struct StrBuf { char* base; /* start of buffer (caller owned) */ @@ -43,6 +44,13 @@ static inline size_t strbuf_len(const StrBuf* sb) { static inline const char* strbuf_cstr(const StrBuf* sb) { return sb->base; } +/* View the accumulated bytes as a Slice. The backing buffer stays + * NUL-terminated, so the slice's `.s` is safe to hand to NUL-requiring + * boundaries while `.len` carries the exact length. */ +static inline Slice strbuf_slice(const StrBuf* sb) { + return (Slice){ .s = sb->base, .len = strbuf_len(sb) }; +} + static inline void strbuf_putc(StrBuf* sb, char c) { if (sb->p < sb->end) { *sb->p++ = c; @@ -63,6 +71,11 @@ static inline void strbuf_putn(StrBuf* sb, const char* s, size_t n) { for (size_t i = 0; i < n; ++i) strbuf_putc(sb, s[i]); } +/* Append a slice's bytes verbatim (length-explicit, no NUL scan). */ +static inline void strbuf_put_slice(StrBuf* sb, Slice s) { + strbuf_putn(sb, s.s, s.len); +} + void strbuf_put_u64(StrBuf*, u64 v); void strbuf_put_i64(StrBuf*, i64 v); void strbuf_put_hex_u64(StrBuf*, u64 v); /* "0x" + hex, no padding */ diff --git a/src/dbg/step.c b/src/dbg/step.c @@ -9,6 +9,8 @@ #include <string.h> +#include "core/slice.h" + #define DBG_STEP_LINE_INSN_CAP 1024u /* DWARF line/CFI tables are authored in image-relative vaddrs (cfree's @@ -46,9 +48,9 @@ static int stop_is_internal_completion(const CfreeJitSession* s) { } static CfreeStatus dwarf_line_for(CfreeJitSession* s, uint64_t pc, - const char** file, uint32_t* line) { + CfreeSlice* file, uint32_t* line) { uint32_t col = 0; - *file = NULL; + *file = CFREE_SLICE_NULL; *line = 0; return cfree_dwarf_addr_to_line(s->dwarf, step_rt_to_img(s, pc), file, line, &col); @@ -60,20 +62,20 @@ static CfreeStatus dwarf_sub_for(CfreeJitSession* s, uint64_t pc, return cfree_dwarf_subprogram_at(s->dwarf, step_rt_to_img(s, pc), out); } -static int line_changed(const char* base_file, uint32_t base_line, - const char* new_file, uint32_t new_line) { +static int line_changed(CfreeSlice base_file, uint32_t base_line, + CfreeSlice new_file, uint32_t new_line) { if (new_line == 0) return 0; if (base_line == 0) return 1; if (new_line != base_line) return 1; - if (base_file != new_file) { - if (!base_file || !new_file) return 1; - if (strcmp(base_file, new_file) != 0) return 1; + if (base_file.s != new_file.s) { + if (!base_file.s || !new_file.s) return 1; + if (!slice_eq(base_file, new_file)) return 1; } return 0; } static CfreeStatus run_step_line_loop(CfreeJitSession* s) { - const char* base_file = NULL; + CfreeSlice base_file = CFREE_SLICE_NULL; uint32_t base_line = 0; CfreeDwarfSubprogram base_sub; int have_sub; @@ -83,7 +85,7 @@ static CfreeStatus run_step_line_loop(CfreeJitSession* s) { have_sub = (dwarf_sub_for(s, s->stop.regs.pc, &base_sub) == CFREE_OK); for (i = 0; i < DBG_STEP_LINE_INSN_CAP; ++i) { - const char* new_file = NULL; + CfreeSlice new_file = CFREE_SLICE_NULL; uint32_t new_line = 0; CfreeDwarfSubprogram new_sub; int have_new_sub; diff --git a/src/debug/debug.c b/src/debug/debug.c @@ -6,6 +6,7 @@ #include "core/core.h" #include "core/heap.h" #include "core/pool.h" +#include "core/slice.h" #include "core/vec.h" #include "debug/debug_internal.h" @@ -13,7 +14,7 @@ static _Noreturn void debug_oom(Debug* d, const char* what) { SrcLoc nl = {0, 0, 0}; - compiler_panic(d->c, nl, "debug: oom (%s)", what); + compiler_panic(d->c, nl, "debug: oom (%.*s)", SLICE_ARG(slice_from_cstr(what))); } static DebugTypeId type_alloc(Debug* d) { @@ -93,25 +94,27 @@ void debug_free(Debug* d) { /* ---- file table ---- */ static void split_path(Pool* p, Sym path, Sym* dir_out, Sym* base_out) { - size_t len = 0; - const char* s = pool_str(p, path, &len); + Slice sl = pool_slice(p, path); + const char* s = sl.s; + size_t len = sl.len; size_t i; size_t slash = (size_t)-1; if (!s || len == 0) { - *dir_out = pool_intern_cstr(p, ""); - *base_out = path ? path : pool_intern_cstr(p, ""); + *dir_out = pool_intern_slice(p, SLICE_LIT("")); + *base_out = path ? path : pool_intern_slice(p, SLICE_LIT("")); return; } for (i = 0; i < len; ++i) { if (s[i] == '/') slash = i; } if (slash == (size_t)-1) { - *dir_out = pool_intern_cstr(p, ""); + *dir_out = pool_intern_slice(p, SLICE_LIT("")); *base_out = path; return; } - *dir_out = pool_intern(p, s, slash); - *base_out = pool_intern(p, s + slash + 1, len - slash - 1); + *dir_out = pool_intern_slice(p, (Slice){ .s = s, .len = slash }); + *base_out = + pool_intern_slice(p, (Slice){ .s = s + slash + 1, .len = len - slash - 1 }); } u32 debug_file(Debug* d, u32 source_file_id) { @@ -122,7 +125,7 @@ u32 debug_file(Debug* d, u32 source_file_id) { DebugFile* slot; Sym path = 0, dir, base; if (sf) path = sf->path ? sf->path : sf->name; - if (!path) path = pool_intern_cstr(d->c->global, ""); + if (!path) path = pool_intern_slice(d->c->global, SLICE_LIT("")); split_path(d->c->global, path, &dir, &base); if (VEC_GROW(d->heap, d->files, d->files_cap, d->nfiles + 1)) debug_oom(d, "file table"); diff --git a/src/debug/debug_emit.c b/src/debug/debug_emit.c @@ -20,6 +20,7 @@ #include "core/core.h" #include "core/heap.h" #include "core/pool.h" +#include "core/slice.h" #include "core/vec.h" #include "debug/debug_internal.h" @@ -61,12 +62,16 @@ static u32 str_intern(StrTab *s, Heap *h, Pool *pool, Sym sym) { size_t len; const char *str; if (sym == 0) - sym = pool_intern_cstr(pool, ""); + sym = pool_intern_slice(pool, SLICE_LIT("")); found = SymToU32_get(&s->by_sym, sym); if (found) return *found; ofs = buf_pos(&s->buf); - str = pool_str(pool, sym, &len); + { + Slice sl = pool_slice(pool, sym); + str = sl.s; + len = sl.len; + } if (str && len) buf_write(&s->buf, str, len); { @@ -263,7 +268,7 @@ static void add_rng_reloc(EmitCtx *e, u32 buf_offset, ObjSymId sym) { static void emit_strx4(EmitCtx *e, Buf *b, Sym name) { str_intern(&e->str, e->heap, e->pool, name); { - Sym key = name ? name : pool_intern_cstr(e->pool, ""); + Sym key = name ? name : pool_intern_slice(e->pool, SLICE_LIT("")); u32 idx = str_index_of(&e->str, key); form_u32(b, idx); } @@ -711,7 +716,7 @@ static void emit_subprogram_die(EmitCtx *e, DebugFunc *f) { /* Section flushing. */ static ObjSecId mk_section(EmitCtx *e, const char *name) { - Sym n = pool_intern_cstr(e->pool, name); + Sym n = pool_intern_slice(e->pool, slice_from_cstr(name)); return obj_section(e->ob, n, SEC_DEBUG, 0, 1); } @@ -948,7 +953,7 @@ static void emit_section_line(EmitCtx *e) { dirs[ndirs++] = e->d->files[0].dir; } else { if (!VEC_GROW(e->heap, dirs, dirs_cap, ndirs + 1)) - dirs[ndirs++] = pool_intern_cstr(pool, ""); + dirs[ndirs++] = pool_intern_slice(pool, SLICE_LIT("")); } for (i = 1; i < e->d->nfiles; ++i) { Sym dir = e->d->files[i].dir; @@ -990,7 +995,7 @@ static void emit_section_line(EmitCtx *e) { u32 ofs; form_uleb(&hdr_body, 1); at = buf_pos(&hdr_body); - ofs = line_str_offset(e, pool_intern_cstr(pool, "")); + ofs = line_str_offset(e, pool_intern_slice(pool, SLICE_LIT(""))); form_u32(&hdr_body, ofs); if (!VEC_GROW(e->heap, lsp_slots, lsp_cap, nlsp + 1)) { lsp_slots[nlsp].at = at; @@ -1309,13 +1314,13 @@ void debug_emit(Debug *d) { ec.ssym_line_str = mk_section_sym(&ec, ec.sec_line_str); ec.ssym_str_off = mk_section_sym(&ec, ec.sec_str_off); - producer_sym = pool_intern_cstr(pool, "cfree 0.1"); + producer_sym = pool_intern_slice(pool, SLICE_LIT("cfree 0.1")); if (d->nfiles > 0) { primary_dir = d->files[0].dir; primary_base = d->files[0].base; } else { - primary_dir = pool_intern_cstr(pool, ""); - primary_base = pool_intern_cstr(pool, ""); + primary_dir = pool_intern_slice(pool, SLICE_LIT("")); + primary_base = pool_intern_slice(pool, SLICE_LIT("")); } /* CU root DIE */ diff --git a/src/debug/dwarf_line.c b/src/debug/dwarf_line.c @@ -12,6 +12,7 @@ #include "core/core.h" #include "core/heap.h" +#include "core/slice.h" #include "core/util.h" #include "debug/dwarf_internal.h" @@ -183,8 +184,8 @@ static const char* build_file_norm(CfreeDebugInfo* d, DwLineProgram* lp, if (!path) path = ""; dir_idx = lp->files[idx].dir_index; dir = (dir_idx < lp->ndirs) ? lp->dirs[dir_idx] : ""; - plen = strlen(path); - dlen = strlen(dir); + plen = slice_from_cstr(path).len; + dlen = slice_from_cstr(dir).len; /* If path is already absolute (starts with /), return as-is. */ if (plen > 0 && path[0] == '/') return path; if (dlen > 0) { @@ -441,14 +442,14 @@ void dw_build_line(CfreeDebugInfo* d, u32 cu_idx) { /* Lookup helpers. Build all CU line tables on demand, walk each. */ CfreeStatus cfree_dwarf_addr_to_line(CfreeDebugInfo* d, uint64_t pc, - const char** file_out, uint32_t* line_out, + CfreeSlice* file_out, uint32_t* line_out, uint32_t* col_out) { /* Status codes: * CFREE_OK — PC has a line entry; outputs filled. * CFREE_NOT_FOUND — PC has no line entry (either inside a CU's * coverage with no row, or outside every CU). */ u32 i; - if (file_out) *file_out = NULL; + if (file_out) *file_out = CFREE_SLICE_NULL; if (line_out) *line_out = 0; if (col_out) *col_out = 0; if (!d) return CFREE_INVALID; @@ -468,7 +469,7 @@ CfreeStatus cfree_dwarf_addr_to_line(CfreeDebugInfo* d, uint64_t pc, const char* f = ""; if (best->file_index < lp->nfile_norm && lp->file_norm) f = lp->file_norm[best->file_index]; - if (file_out) *file_out = f; + if (file_out) *file_out = cfree_slice_cstr(f); if (line_out) *line_out = best->line; if (col_out) *col_out = best->column; return CFREE_OK; @@ -484,13 +485,13 @@ static int dw_file_matches(const char* file_norm, const char* user, size_t ulen) size_t flen; if (!file_norm) return 0; if (dw_streq(file_norm, user)) return 1; - flen = strlen(file_norm); + flen = slice_from_cstr(file_norm).len; if (flen <= ulen) return 0; if (file_norm[flen - ulen - 1] != '/') return 0; return memcmp(file_norm + flen - ulen, user, ulen) == 0; } -CfreeStatus cfree_dwarf_line_to_addr(CfreeDebugInfo* d, const char* file, +CfreeStatus cfree_dwarf_line_to_addr(CfreeDebugInfo* d, CfreeSlice file, uint32_t line, uint64_t* pc_out) { /* Status: * CFREE_OK — unique match; *pc_out filled. @@ -505,8 +506,8 @@ CfreeStatus cfree_dwarf_line_to_addr(CfreeDebugInfo* d, const char* file, const char* alt_path = NULL; int line_hits = 0; if (pc_out) *pc_out = 0; - if (!d || !file) return CFREE_INVALID; - ulen = strlen(file); + if (!d || !file.s) return CFREE_INVALID; + ulen = file.len; if (ulen == 0) return CFREE_INVALID; for (i = 0; i < d->ncus; ++i) { DwLineProgram* lp; @@ -519,7 +520,7 @@ CfreeStatus cfree_dwarf_line_to_addr(CfreeDebugInfo* d, const char* file, if (r->end_sequence) continue; if (r->file_index >= lp->nfile_norm || !lp->file_norm) continue; f = lp->file_norm[r->file_index]; - if (!dw_file_matches(f, file, ulen)) continue; + if (!dw_file_matches(f, file.s, ulen)) continue; if (r->line != line) continue; ++line_hits; if (!first_path) { @@ -542,7 +543,7 @@ CfreeStatus cfree_dwarf_line_to_addr(CfreeDebugInfo* d, const char* file, * which case only the first `cap` are written). Returns 0 on success * (including 0 candidates), 1 on invalid args. Intended for REPL * disambiguation after cfree_dwarf_line_to_addr returns 3. */ -CfreeStatus cfree_dwarf_line_to_addr_all(CfreeDebugInfo* d, const char* file, +CfreeStatus cfree_dwarf_line_to_addr_all(CfreeDebugInfo* d, CfreeSlice file, uint32_t line, CfreeDwarfLineMatch* out, uint32_t cap, uint32_t* n_out) { @@ -553,8 +554,8 @@ CfreeStatus cfree_dwarf_line_to_addr_all(CfreeDebugInfo* d, const char* file, size_t ulen; uint32_t total = 0; if (n_out) *n_out = 0; - if (!d || !file) return CFREE_INVALID; - ulen = strlen(file); + if (!d || !file.s) return CFREE_INVALID; + ulen = file.len; if (ulen == 0) return CFREE_INVALID; for (i = 0; i < d->ncus; ++i) { DwLineProgram* lp; @@ -570,13 +571,14 @@ CfreeStatus cfree_dwarf_line_to_addr_all(CfreeDebugInfo* d, const char* file, if (r->line != line) continue; if (r->file_index >= lp->nfile_norm || !lp->file_norm) continue; f = lp->file_norm[r->file_index]; - if (!dw_file_matches(f, file, ulen)) continue; + if (!dw_file_matches(f, file.s, ulen)) continue; /* Dedupe by file_norm path so the candidate list is one entry per * source file even if the line has many per-instruction rows. */ if (out) { uint32_t lim = total < cap ? total : cap; for (k = 0; k < lim; ++k) { - if (out[k].file == f || (out[k].file && dw_streq(out[k].file, f))) { + if (out[k].file.s == f || + (out[k].file.s && dw_streq(out[k].file.s, f))) { dup = 1; break; } @@ -585,7 +587,7 @@ CfreeStatus cfree_dwarf_line_to_addr_all(CfreeDebugInfo* d, const char* file, if (dup) continue; if (out && total < cap) { out[total].pc = r->address; - out[total].file = f; + out[total].file = cfree_slice_cstr(f); } ++total; } diff --git a/src/debug/dwarf_open.c b/src/debug/dwarf_open.c @@ -15,6 +15,7 @@ #include "core/core.h" #include "core/heap.h" #include "core/pool.h" +#include "core/slice.h" #include "core/util.h" #include "core/vec.h" #include "debug/dwarf_internal.h" @@ -31,7 +32,7 @@ void dw_find_section(CfreeDebugInfo* d, const char* name, DwSection* out) { for (i = 0; i < n; ++i) { CfreeObjSecInfo info; if (cfree_obj_section(d->obj, i, &info) != CFREE_OK) continue; - if (info.name && dw_streq(info.name, name)) { + if (info.name.len && cfree_slice_eq_cstr(info.name, name)) { size_t len = 0; const uint8_t* p = NULL; if (cfree_obj_section_data(d->obj, i, &p, &len) != CFREE_OK) continue; @@ -136,8 +137,8 @@ const char* dw_cstr(const u8* base, u32 size, u32* off) { /* ---- string interning ------------------------------------------------- */ const char* dw_intern(CfreeDebugInfo* d, const char* s, size_t len) { - Sym sym = pool_intern(d->strs, s, len); - return pool_str(d->strs, sym, NULL); + Sym sym = pool_intern_slice(d->strs, (Slice){ .s = s, .len = len }); + return pool_slice(d->strs, sym).s; } /* Resolve a .debug_str offset. */ diff --git a/src/debug/dwarf_query.c b/src/debug/dwarf_query.c @@ -18,10 +18,11 @@ static void fill_subprogram(CfreeDebugInfo *d, DwSubprog *sp, CfreeDwarfSubprogram *out) { memset(out, 0, sizeof(*out)); - out->name = sp->name ? sp->name : ""; + out->name = sp->name ? cfree_slice_cstr(sp->name) : CFREE_SLICE_NULL; out->low_pc = sp->low_pc; out->high_pc = sp->high_pc; - out->decl_file = sp->decl_file ? sp->decl_file : ""; + out->decl_file = + sp->decl_file ? cfree_slice_cstr(sp->decl_file) : CFREE_SLICE_NULL; out->decl_line = sp->decl_line; out->return_type = sp->type_die_offset ? dw_type_from_die(d, sp->cu_idx, sp->type_die_offset) @@ -65,12 +66,12 @@ static DwSubprog *dw_find_subprog_named(CfreeDebugInfo *d, const char *name) { return NULL; } -CfreeStatus cfree_dwarf_subprogram_named(CfreeDebugInfo *d, const char *name, +CfreeStatus cfree_dwarf_subprogram_named(CfreeDebugInfo *d, CfreeSlice name, CfreeDwarfSubprogram *out) { DwSubprog *sp; - if (!d || !name || !out) + if (!d || !name.s || !out) return CFREE_INVALID; - sp = dw_find_subprog_named(d, name); + sp = dw_find_subprog_named(d, name.s); if (!sp) return CFREE_NOT_FOUND; fill_subprogram(d, sp, out); @@ -78,7 +79,7 @@ CfreeStatus cfree_dwarf_subprogram_named(CfreeDebugInfo *d, const char *name, } CfreeStatus cfree_dwarf_func_at(CfreeDebugInfo *d, uint64_t pc, - const char **name_out, uint64_t *low_out, + CfreeSlice *name_out, uint64_t *low_out, uint64_t *high_out) { CfreeDwarfSubprogram sp; CfreeStatus st = cfree_dwarf_subprogram_at(d, pc, &sp); @@ -171,7 +172,7 @@ static void fill_varloc(CfreeDebugInfo *d, u32 cu_idx, const DwLocal *v, u64 pc, out->v.expr.len = 0; } -CfreeStatus cfree_dwarf_var_at(CfreeDebugInfo *d, uint64_t pc, const char *name, +CfreeStatus cfree_dwarf_var_at(CfreeDebugInfo *d, uint64_t pc, CfreeSlice name, CfreeDwarfVarLoc *out) { /* Status codes: * CFREE_OK — found; *out filled. @@ -181,7 +182,7 @@ CfreeStatus cfree_dwarf_var_at(CfreeDebugInfo *d, uint64_t pc, const char *name, */ DwSubprog *sp; u32 i; - if (!d || !name || !out) + if (!d || !name.s || !out) return CFREE_INVALID; memset(out, 0, sizeof(*out)); sp = dw_find_subprog(d, pc); @@ -191,7 +192,7 @@ CfreeStatus cfree_dwarf_var_at(CfreeDebugInfo *d, uint64_t pc, const char *name, * after enclosing). */ for (i = sp->nlocals; i > 0; --i) { DwLocal *v = &sp->locals[i - 1]; - if (!v->name || !dw_streq(v->name, name)) + if (!v->name || !dw_streq(v->name, name.s)) continue; if (v->has_scope && (pc < v->scope_lo || pc >= v->scope_hi)) continue; @@ -201,7 +202,7 @@ CfreeStatus cfree_dwarf_var_at(CfreeDebugInfo *d, uint64_t pc, const char *name, /* Then params. */ for (i = 0; i < sp->nparams; ++i) { DwLocal *v = &sp->params[i]; - if (!v->name || !dw_streq(v->name, name)) + if (!v->name || !dw_streq(v->name, name.s)) continue; fill_varloc(d, sp->cu_idx, v, pc, out); return CFREE_OK; @@ -211,7 +212,7 @@ CfreeStatus cfree_dwarf_var_at(CfreeDebugInfo *d, uint64_t pc, const char *name, dw_build_globals(d); for (i = 0; i < d->nglobals; ++i) { DwLocal *v = &d->globals[i]; - if (!v->name || !dw_streq(v->name, name)) + if (!v->name || !dw_streq(v->name, name.s)) continue; fill_varloc(d, 0, v, pc, out); return CFREE_OK; @@ -361,7 +362,7 @@ CfreeIterResult cfree_dwarf_vars_at_next(CfreeDwarfVarIter *it, DwLocal *v = &it->sp->locals[--it->idx]; if (v->has_scope && (it->pc < v->scope_lo || it->pc >= v->scope_hi)) break; - out->name = v->name ? v->name : ""; + out->name = v->name ? cfree_slice_cstr(v->name) : CFREE_SLICE_NULL; out->role = CFREE_DVR_LOCAL; fill_varloc(it->d, it->sp->cu_idx, v, it->pc, &out->loc); return CFREE_ITER_ITEM; @@ -380,7 +381,7 @@ CfreeIterResult cfree_dwarf_vars_at_next(CfreeDwarfVarIter *it, } { DwLocal *v = &it->sp->params[it->idx++]; - out->name = v->name ? v->name : ""; + out->name = v->name ? cfree_slice_cstr(v->name) : CFREE_SLICE_NULL; out->role = CFREE_DVR_ARG; fill_varloc(it->d, it->sp->cu_idx, v, it->pc, &out->loc); return CFREE_ITER_ITEM; @@ -398,7 +399,7 @@ CfreeIterResult cfree_dwarf_vars_at_next(CfreeDwarfVarIter *it, } { DwLocal *v = &it->d->globals[it->idx++]; - out->name = v->name ? v->name : ""; + out->name = v->name ? cfree_slice_cstr(v->name) : CFREE_SLICE_NULL; out->role = CFREE_DVR_GLOBAL; fill_varloc(it->d, 0, v, it->pc, &out->loc); return CFREE_ITER_ITEM; @@ -451,16 +452,16 @@ CfreeStatus cfree_dwarf_param_iter_new(CfreeDebugInfo *d, uint64_t pc, } CfreeStatus cfree_dwarf_param_iter_new_named(CfreeDebugInfo *d, - const char *name, + CfreeSlice name, CfreeDwarfParamIter **out) { CfreeDwarfParamIter *it; DwSubprog *sp; if (!out) return CFREE_INVALID; *out = NULL; - if (!d || !name) + if (!d || !name.s) return CFREE_INVALID; - sp = dw_find_subprog_named(d, name); + sp = dw_find_subprog_named(d, name.s); if (!sp) return CFREE_NOT_FOUND; dw_build_locals(d, sp); @@ -484,7 +485,7 @@ CfreeIterResult cfree_dwarf_param_iter_next(CfreeDwarfParamIter *it, return CFREE_ITER_END; { DwLocal *v = &it->sp->params[it->idx++]; - out->name = v->name ? v->name : ""; + out->name = v->name ? cfree_slice_cstr(v->name) : CFREE_SLICE_NULL; out->role = CFREE_DVR_ARG; fill_varloc(it->d, it->sp->cu_idx, v, it->pc, &out->loc); } diff --git a/src/debug/dwarf_type.c b/src/debug/dwarf_type.c @@ -387,14 +387,14 @@ static CfreeDwarfTypeKind map_kind(const CfreeDwarfType* t) { CfreeDwarfTypeInfo cfree_dwarf_type_info(const CfreeDwarfType* t) { CfreeDwarfTypeInfo info; memset(&info, 0, sizeof(info)); - info.name = ""; + info.name = CFREE_SLICE_NULL; if (!t) { info.kind = CFREE_DT_VOID; return info; } info.kind = map_kind(t); info.byte_size = t->byte_size; - info.name = t->name ? t->name : ""; + info.name = t->name ? cfree_slice_cstr(t->name) : CFREE_SLICE_NULL; info.element_count = t->element_count; /* For TYPEDEF/PTR/ARRAY: expose inner. For BASE_CHAR map signedness. */ switch (t->kind) { @@ -462,7 +462,7 @@ CfreeIterResult cfree_dwarf_field_iter_next(CfreeDwarfFieldIter* it, if (it->idx >= t->nfields) return CFREE_ITER_END; { DwField* f = &t->fields[it->idx++]; - out->name = f->name ? f->name : ""; + out->name = f->name ? cfree_slice_cstr(f->name) : CFREE_SLICE_NULL; out->byte_offset = f->byte_offset; out->bit_offset = f->bit_offset; out->bit_size = f->bit_size; @@ -509,7 +509,8 @@ CfreeIterResult cfree_dwarf_enum_iter_next(CfreeDwarfEnumIter* it, t = it->t; if (t->kind != DTK_ENUM) return CFREE_ITER_END; if (it->idx >= t->nevals) return CFREE_ITER_END; - out->name = t->evals[it->idx].name ? t->evals[it->idx].name : ""; + out->name = t->evals[it->idx].name ? cfree_slice_cstr(t->evals[it->idx].name) + : CFREE_SLICE_NULL; out->value = t->evals[it->idx].value; it->idx++; return CFREE_ITER_ITEM; diff --git a/src/emu/elf_load.c b/src/emu/elf_load.c @@ -26,6 +26,7 @@ #include <string.h> #include "core/core.h" +#include "core/slice.h" #include "emu/emu.h" #include "emu/rv64_ops.h" #include "obj/elf.h" @@ -364,13 +365,13 @@ int emu_load_elf(Compiler* c, CfreeEmuArch arch, const u8* bytes, size_t len, } for (i = 0; i < (u32)argc; ++i) { - size_t slen = strlen(argv[i]) + 1u; + size_t slen = slice_from_cstr(argv[i]).len + 1u; cursor -= slen; memcpy(guest_base + (cursor - lo_va), argv[i], slen); argv_addrs[i] = cursor; } for (i = 0; i < (u32)envc; ++i) { - size_t slen = strlen(envp[i]) + 1u; + size_t slen = slice_from_cstr(envp[i]).len + 1u; cursor -= slen; memcpy(guest_base + (cursor - lo_va), envp[i], slen); envp_addrs[i] = cursor; diff --git a/src/emu/emu.c b/src/emu/emu.c @@ -14,6 +14,7 @@ #include <string.h> #include "core/pool.h" +#include "core/slice.h" #include "link/link.h" #include "obj/obj.h" @@ -383,5 +384,5 @@ Sym emu_block_sym_name(Compiler* c, u64 guest_pc) { guest_pc >>= 4; } buf[26] = '\0'; - return pool_intern_cstr(c->global, buf); + return pool_intern_slice(c->global, slice_from_cstr(buf)); } diff --git a/src/emu/emu.h b/src/emu/emu.h @@ -171,7 +171,7 @@ Sym emu_block_sym_name(Compiler*, u64 guest_pc); /* External resolver passed to link_set_extern_resolver. `user` is * the CfreeEmu*. Returns NULL for unrecognized names — the linker * promotes that to a fatal undefined-symbol diagnostic. */ -void* emu_runtime_extern_resolver(void* user, const char* name); +void* emu_runtime_extern_resolver(void* user, CfreeSlice name); /* Memory helpers; called from JITted blocks. The host process owns * the guest AS, so loads/stores bounds-check against the EmuCPUState's diff --git a/src/emu/runtime.c b/src/emu/runtime.c @@ -490,31 +490,23 @@ void emu_syscall(EmuCPUState* s) { * (or the running emu's CPUState). Returning NULL surfaces as a * fatal "undefined reference" diagnostic from link_resolve_extend. */ -static int streq(const char* a, const char* b) { - while (*a && *a == *b) { - ++a; - ++b; - } - return *a == 0 && *b == 0; -} - -void* emu_runtime_extern_resolver(void* user, const char* name) { - if (!name) return NULL; +void* emu_runtime_extern_resolver(void* user, CfreeSlice name) { + if (!name.s) return NULL; - if (streq(name, EMU_SYM_CPU_STATE)) { + if (cfree_slice_eq_cstr(name, EMU_SYM_CPU_STATE)) { CfreeEmu* e = (CfreeEmu*)user; return (void*)emu_internal_cpu(e); } - if (streq(name, EMU_SYM_LOAD8)) return (void*)emu_mem_load8; - if (streq(name, EMU_SYM_LOAD16)) return (void*)emu_mem_load16; - if (streq(name, EMU_SYM_LOAD32)) return (void*)emu_mem_load32; - if (streq(name, EMU_SYM_LOAD64)) return (void*)emu_mem_load64; - if (streq(name, EMU_SYM_STORE8)) return (void*)emu_mem_store8; - if (streq(name, EMU_SYM_STORE16)) return (void*)emu_mem_store16; - if (streq(name, EMU_SYM_STORE32)) return (void*)emu_mem_store32; - if (streq(name, EMU_SYM_STORE64)) return (void*)emu_mem_store64; - if (streq(name, EMU_SYM_SYSCALL)) return (void*)emu_syscall; + if (cfree_slice_eq_cstr(name, EMU_SYM_LOAD8)) return (void*)emu_mem_load8; + if (cfree_slice_eq_cstr(name, EMU_SYM_LOAD16)) return (void*)emu_mem_load16; + if (cfree_slice_eq_cstr(name, EMU_SYM_LOAD32)) return (void*)emu_mem_load32; + if (cfree_slice_eq_cstr(name, EMU_SYM_LOAD64)) return (void*)emu_mem_load64; + if (cfree_slice_eq_cstr(name, EMU_SYM_STORE8)) return (void*)emu_mem_store8; + if (cfree_slice_eq_cstr(name, EMU_SYM_STORE16)) return (void*)emu_mem_store16; + if (cfree_slice_eq_cstr(name, EMU_SYM_STORE32)) return (void*)emu_mem_store32; + if (cfree_slice_eq_cstr(name, EMU_SYM_STORE64)) return (void*)emu_mem_store64; + if (cfree_slice_eq_cstr(name, EMU_SYM_SYSCALL)) return (void*)emu_syscall; /* EMU_SYM_DISPATCH is the cross-block tail-call helper; it shares * the host address of the dispatcher entry. The dispatcher loop diff --git a/src/link/link.c b/src/link/link.c @@ -19,6 +19,7 @@ #include "core/heap.h" #include "core/pool.h" +#include "core/slice.h" #include "core/vec.h" #include "link/link_internal.h" @@ -79,7 +80,7 @@ Linker* link_new(Compiler* c) { * so the on-disk symbol is `_main` (the mangled form of `main`). * Format choice lives in obj_format_default_entry_name. */ l->entry_name = - pool_intern_cstr(c->global, obj_format_default_entry_name(c)); + pool_intern_slice(c->global, slice_from_cstr(obj_format_default_entry_name(c))); /* Match the rest of libcfree's lifetime story: the new'd Linker is * registered for cleanup in case a panic fires before link_free. */ l->deferred = compiler_defer(c, linker_cleanup, l); @@ -146,17 +147,21 @@ LinkInputId link_add_obj_bytes(Linker* l, const char* name, const u8* data, default: compiler_panic(l->c, no_loc(), "link_add_obj_bytes: unsupported object format " - "(fmt=%u) for '%s'", - (u32)fmt, name ? name : "(unnamed)"); + "(fmt=%u) for '%.*s'", + (u32)fmt, + SLICE_ARG(name ? slice_from_cstr(name) + : SLICE_LIT("(unnamed)"))); } if (!ob) compiler_panic(l->c, no_loc(), - "link_add_obj_bytes: %s returned NULL for '%s'", - reader_name, name ? name : "(unnamed)"); + "link_add_obj_bytes: %.*s returned NULL for '%.*s'", + SLICE_ARG(slice_from_cstr(reader_name)), + SLICE_ARG(name ? slice_from_cstr(name) + : SLICE_LIT("(unnamed)"))); in = inputs_push(l, &id); in->order = l->next_input_order++; in->obj = ob; /* re-uses the ObjBuilder slot for ownership */ - in->name = name ? pool_intern_cstr(l->c->global, name) : 0; + in->name = name ? pool_intern_slice(l->c->global, slice_from_cstr(name)) : 0; /* PE/COFF short-import: read_coff_short_import stashes the providing * DLL name on the builder. Reclassify the input as a DSO so the * resolver treats its symbols as exports (matching the .lib archive @@ -216,19 +221,23 @@ LinkInputId link_add_dso_bytes(Linker* l, const char* name, const u8* data, default: compiler_panic(l->c, no_loc(), "link_add_dso_bytes: unsupported DSO format " - "(fmt=%u) for '%s'", - (u32)fmt, name ? name : "(unnamed)"); + "(fmt=%u) for '%.*s'", + (u32)fmt, + SLICE_ARG(name ? slice_from_cstr(name) + : SLICE_LIT("(unnamed)"))); } } if (!ob) compiler_panic(l->c, no_loc(), - "link_add_dso_bytes: %s returned NULL for '%s'", - reader_name, name ? name : "(unnamed)"); + "link_add_dso_bytes: %.*s returned NULL for '%.*s'", + SLICE_ARG(slice_from_cstr(reader_name)), + SLICE_ARG(name ? slice_from_cstr(name) + : SLICE_LIT("(unnamed)"))); in = inputs_push(l, &id); in->kind = LINK_INPUT_DSO_BYTES; in->order = l->next_input_order++; in->obj = ob; - in->name = name ? pool_intern_cstr(l->c->global, name) : 0; + in->name = name ? pool_intern_slice(l->c->global, slice_from_cstr(name)) : 0; /* DT_SONAME wins; fall back to the file's basename if the DSO has * no SONAME (matches GNU ld's behaviour for hand-rolled libraries * that forgot to set DT_SONAME). */ @@ -239,7 +248,7 @@ LinkInputId link_add_dso_bytes(Linker* l, const char* name, const u8* data, const char* p; for (p = name; *p; ++p) if (*p == '/') base = p + 1; - in->soname = pool_intern_cstr(l->c->global, base); + in->soname = pool_intern_slice(l->c->global, slice_from_cstr(base)); } else { in->soname = 0; } @@ -312,7 +321,7 @@ static Sym derive_dll_name_from_archive_path(Compiler* c, const char* path) { base = path; for (p = path; *p; ++p) if (*p == '/' || *p == '\\') base = p + 1; - n = strlen(base); + n = slice_from_cstr(base).len; /* Strip trailing ".dll.a" / ".a" / ".lib" (case-sensitive — mingw * uses lowercase, MSVC uses .lib). */ if (n >= 6 && memcmp(base + n - 6, ".dll.a", 6) == 0) n -= 6; @@ -329,7 +338,7 @@ static Sym derive_dll_name_from_archive_path(Compiler* c, const char* path) { out = (char*)arena_array(c->scratch, char, out_len); memcpy(out, base, n); memcpy(out + n, ".dll", 4); - sym = pool_intern(c->global, out, (u32)out_len); + sym = pool_intern_slice(c->global, (Slice){ .s = out, .len = (u32)out_len }); return sym; } @@ -343,11 +352,11 @@ static Sym derive_dll_name_from_archive_member(Compiler* c, base = member_name; for (p = member_name; *p; ++p) if (*p == '/' || *p == '\\') base = p + 1; - n = strlen(base); + n = slice_from_cstr(base).len; if (n >= 4 && memcmp(base + n - 4, ".dll", 4) == 0) - return pool_intern(c->global, base, (u32)n); + return pool_intern_slice(c->global, (Slice){ .s = base, .len = (u32)n }); if (n >= 4 && memcmp(base + n - 4, ".DLL", 4) == 0) - return pool_intern(c->global, base, (u32)n); + return pool_intern_slice(c->global, (Slice){ .s = base, .len = (u32)n }); return fallback; } @@ -474,7 +483,7 @@ static CoffArMemberClass classify_coff_archive_member_bytes( if (imp_bare_name == 0) { const char* tail = nm + kCoffImpPrefixLen_; u32 tail_len = nlen - kCoffImpPrefixLen_; - imp_bare_name = pool_intern(c->global, tail, tail_len); + imp_bare_name = pool_intern_slice(c->global, (Slice){ .s = tail, .len = tail_len }); } } else if (nlen > kCoffHeadPrefixLen_ && memcmp(nm, kCoffHeadPrefix_, kCoffHeadPrefixLen_) == 0) { @@ -511,7 +520,11 @@ static ObjBuilder* build_coff_long_import_shim(Compiler* c, Sym bare_name, ObjSymId id; ObjSymId imp_id; if (bare_name == 0 || dll_name == 0) return NULL; - bare = pool_str(c->global, bare_name, &bare_len); + { + Slice bare_s = pool_slice(c->global, bare_name); + bare = bare_s.s; + bare_len = bare_s.len; + } if (!bare || bare_len == 0) return NULL; ob = obj_new(c); if (!ob) return NULL; @@ -522,7 +535,7 @@ static ObjBuilder* build_coff_long_import_shim(Compiler* c, Sym bare_name, imp_buf = (char*)arena_array(c->scratch, char, imp_len); memcpy(imp_buf, kCoffImpPrefix_, kCoffImpPrefixLen_); memcpy(imp_buf + kCoffImpPrefixLen_, bare, bare_len); - imp_sn = pool_intern(c->global, imp_buf, imp_len); + imp_sn = pool_intern_slice(c->global, (Slice){ .s = imp_buf, .len = imp_len }); imp_id = obj_symbol_ex(ob, imp_sn, SB_GLOBAL, SV_DEFAULT, SK_OBJ, OBJ_SEC_NONE, 0, 0, 0); obj_sym_mark_referenced(ob, imp_id); @@ -535,7 +548,11 @@ static int coff_skip_long_import_shim_bare(Compiler* c, Sym bare_name) { const char* s; size_t n = 0; if (!bare_name) return 0; - s = pool_str(c->global, bare_name, &n); + { + Slice s_s = pool_slice(c->global, bare_name); + s = s_s.s; + n = s_s.len; + } if (!s) return 0; /* llvm-mingw's UCRT libmsvcrt.a intentionally provides these legacy * CRT entry helpers as regular archive members later in the same @@ -548,7 +565,7 @@ static int coff_skip_long_import_shim_bare(Compiler* c, Sym bare_name) { LinkInputId link_add_archive_bytes(Linker* l, const char* name, const u8* data, size_t len, u8 whole_archive, u8 link_mode, u8 group_id) { - CfreeBytes in_arc; + CfreeSlice in_arc; CfreeArIter* it = NULL; CfreeArMember mem; LinkArchive* ar; @@ -560,13 +577,13 @@ LinkInputId link_add_archive_bytes(Linker* l, const char* name, const u8* data, if (is_coff_target) archive_dll_name = derive_dll_name_from_archive_path(l->c, name); - in_arc.name = name; in_arc.data = data; in_arc.len = len; if (cfree_ar_iter_new(cfree_compiler_context(l->c), &in_arc, &it) != CFREE_OK || !it) compiler_panic(l->c, no_loc(), - "link_add_archive_bytes: '%s' is not a valid ar archive", - name ? name : "(unnamed)"); + "link_add_archive_bytes: '%.*s' is not a valid ar archive", + SLICE_ARG(name ? slice_from_cstr(name) + : SLICE_LIT("(unnamed)"))); /* Two-pass: count members so we allocate the member array exactly * once. The linker_release path frees by nmembers, so we need @@ -579,7 +596,7 @@ LinkInputId link_add_archive_bytes(Linker* l, const char* name, const u8* data, ar = LinkArchives_push(&l->archives, NULL); if (!ar) compiler_panic(l->c, no_loc(), "link: out of memory growing archives"); - ar->name = name ? pool_intern_cstr(l->c->global, name) : 0; + ar->name = name ? pool_intern_slice(l->c->global, slice_from_cstr(name)) : 0; ar->order = l->next_input_order++; ar->whole_archive = whole_archive; ar->link_mode = link_mode; @@ -600,9 +617,10 @@ LinkInputId link_add_archive_bytes(Linker* l, const char* name, const u8* data, * principle hold mixed formats (in practice it never does). */ if (cfree_ar_iter_new(cfree_compiler_context(l->c), &in_arc, &it) != CFREE_OK || !it) compiler_panic(l->c, no_loc(), - "link_add_archive_bytes: ar_iter_init failed on '%s' " + "link_add_archive_bytes: ar_iter_init failed on '%.*s' " "second pass", - name ? name : "(unnamed)"); + SLICE_ARG(name ? slice_from_cstr(name) + : SLICE_LIT("(unnamed)"))); n = 0; while (cfree_ar_iter_next(it, &mem) == CFREE_ITER_ITEM && n < ar->nmembers) { ObjBuilder* ob = NULL; @@ -621,7 +639,7 @@ LinkInputId link_add_archive_bytes(Linker* l, const char* name, const u8* data, ob = NULL; } else { Sym member_dll = - derive_dll_name_from_archive_member(l->c, mem.name, + derive_dll_name_from_archive_member(l->c, mem.name.s, archive_dll_name); ob = build_coff_long_import_shim(l->c, bare, member_dll); } @@ -630,7 +648,7 @@ LinkInputId link_add_archive_bytes(Linker* l, const char* name, const u8* data, } if (cls != COFF_AR_KEEP) { ar->members[n].name = - mem.name ? pool_intern_cstr(l->c->global, mem.name) : 0; + mem.name.len ? pool_intern_slice(l->c->global, mem.name) : 0; ar->members[n].obj = ob; ++n; continue; @@ -638,30 +656,34 @@ LinkInputId link_add_archive_bytes(Linker* l, const char* name, const u8* data, } switch (mfmt) { case CFREE_BIN_ELF: - ob = read_elf(l->c, mem.name, mem.data, mem.size); + ob = read_elf(l->c, mem.name.s, mem.data, mem.size); break; case CFREE_BIN_MACHO: - ob = read_macho(l->c, mem.name, mem.data, mem.size); + ob = read_macho(l->c, mem.name.s, mem.data, mem.size); break; case CFREE_BIN_COFF: - ob = read_coff(l->c, mem.name, mem.data, mem.size); + ob = read_coff(l->c, mem.name.s, mem.data, mem.size); break; default: compiler_panic(l->c, no_loc(), "link_add_archive_bytes: unsupported member " - "format (fmt=%u) for '%s' in archive '%s'", + "format (fmt=%u) for '%.*s' in archive '%.*s'", (u32)mfmt, - mem.name ? mem.name : "(unnamed)", - name ? name : "(unnamed)"); + SLICE_ARG(mem.name.len ? mem.name + : SLICE_LIT("(unnamed)")), + SLICE_ARG(name ? slice_from_cstr(name) + : SLICE_LIT("(unnamed)"))); } if (!ob) compiler_panic(l->c, no_loc(), "link_add_archive_bytes: object read failed for " - "member '%s' of archive '%s'", - mem.name ? mem.name : "(unnamed)", - name ? name : "(unnamed)"); + "member '%.*s' of archive '%.*s'", + SLICE_ARG(mem.name.len ? mem.name + : SLICE_LIT("(unnamed)")), + SLICE_ARG(name ? slice_from_cstr(name) + : SLICE_LIT("(unnamed)"))); ar->members[n].name = - mem.name ? pool_intern_cstr(l->c->global, mem.name) : 0; + mem.name.len ? pool_intern_slice(l->c->global, mem.name) : 0; ar->members[n].obj = ob; ++n; } @@ -678,9 +700,11 @@ Sym link_intern_c_name(Linker* l, const char* name) { return obj_format_c_mangle(l->c, name); } -void link_set_entry(Linker* l, const char* name) { - if (!l || !name) return; - l->entry_name = link_intern_c_name(l, name); +void link_set_entry(Linker* l, CfreeSlice name) { + if (!l || !name.s || name.len == 0) return; + /* entry names from the API/script are interned arena/pool slices and + * thus NUL-terminated; the mangler scans a C string. */ + l->entry_name = link_intern_c_name(l, name.s); } void link_clear_entry(Linker* l) { @@ -691,7 +715,8 @@ void link_clear_entry(Linker* l) { void link_set_script(Linker* l, const CfreeLinkScript* script) { if (!l || !script) return; l->script = script; - if (script->entry) l->entry_name = link_intern_c_name(l, script->entry); + if (script->entry.s && script->entry.len) + l->entry_name = link_intern_c_name(l, script->entry.s); } void link_set_extern_resolver(Linker* l, LinkExternResolver fn, void* user) { @@ -732,9 +757,10 @@ void link_set_jit_host(Linker* l, const CfreeJitHost* host) { l->jit_host = host; } -void link_set_interp_path(Linker* l, const char* path) { +void link_set_interp_path(Linker* l, CfreeSlice path) { if (!l) return; - l->interp_path = (path && path[0]) ? pool_intern_cstr(l->c->global, path) : 0; + l->interp_path = + (path.s && path.len) ? pool_intern_slice(l->c->global, path) : 0; } /* ---- debug-input capture ---- diff --git a/src/link/link.h b/src/link/link.h @@ -164,7 +164,7 @@ LinkInputId link_add_archive_bytes(Linker*, const char* name, const u8* data, size_t len, u8 whole_archive, u8 link_mode, u8 group_id); -void link_set_entry(Linker*, const char* name); +void link_set_entry(Linker*, CfreeSlice name); void link_clear_entry(Linker*); /* Borrowed reference; the script and every sub-object must outlive * link_resolve. The linker accepts only the structured form — there is no @@ -204,7 +204,7 @@ void link_set_pe_subsystem(Linker*, u16 subsystem); /* Runtime loader path written into PT_INTERP / .interp. NULL leaves the * default ("/lib/ld-musl-aarch64.so.1" for aarch64-linux). Only * consulted when -pie is enabled (or any DSO input is present). */ -void link_set_interp_path(Linker*, const char* path); +void link_set_interp_path(Linker*, CfreeSlice path); /* Borrowed JIT host. The layout passes read execmem->page_size; the JIT * mapper reads the full host (execmem reserve/protect, tls). NULL on diff --git a/src/link/link_coff.c b/src/link/link_coff.c @@ -45,6 +45,7 @@ #include "core/core.h" #include "core/heap.h" #include "core/pool.h" +#include "core/slice.h" #include "core/util.h" #include "core/vec.h" #include "link/link.h" @@ -217,7 +218,7 @@ typedef struct CoffTlsLayout { } CoffTlsLayout; static LinkSymId coff_find_sym(LinkImage* img, const char* name) { - Sym sym = pool_intern_cstr(img->c->global, name); + Sym sym = pool_intern_slice(img->c->global, slice_from_cstr(name)); u32 n = LinkSyms_count(&img->syms); u32 i; for (i = 0; i < n; ++i) { @@ -238,8 +239,9 @@ static LinkSymId coff_find_tls_index_sym(LinkImage* img) { static const LinkSection* coff_symbol_section(const LinkImage* img, const LinkSymbol* s) { if (s->name) { - size_t n = 0; - const char* nm = pool_str(img->c->global, s->name, &n); + Slice nm_s = pool_slice(img->c->global, s->name); + const char* nm = nm_s.s; + size_t n = nm_s.len; const char* sec_name = NULL; if (nm && n == 6 && memcmp(nm, "__xd_a", 6) == 0) sec_name = ".CRT$XDA"; @@ -255,13 +257,10 @@ static const LinkSection* coff_symbol_section(const LinkImage* img, sec_name = ".CRT$XLZ"; if (sec_name) { u32 i; - size_t sn = strlen(sec_name); for (i = 0; i < img->nsections; ++i) { const LinkSection* ls = &img->sections[i]; - size_t ln = 0; - const char* lname = - ls->name ? pool_str(img->c->global, ls->name, &ln) : NULL; - if (lname && ln == sn && memcmp(lname, sec_name, sn) == 0) + if (ls->name && + slice_eq_cstr(pool_slice(img->c->global, ls->name), sec_name)) return ls; } } @@ -279,14 +278,15 @@ static u64 coff_symbol_final_va(const LinkImage* img, const LinkSymbol* s = LinkSyms_at(&img->syms, id - 1); if (!s->defined || s->kind == SK_ABS) { compiler_panic(img->c, no_loc(), - "link_emit_coff: `%s` is not a defined section-bound " + "link_emit_coff: `%.*s` is not a defined section-bound " "symbol", - what); + SLICE_ARG(slice_from_cstr(what))); } const LinkSection* sec = coff_symbol_section(img, s); if (!sec) { compiler_panic(img->c, no_loc(), - "link_emit_coff: `%s` has no containing section", what); + "link_emit_coff: `%.*s` has no containing section", + SLICE_ARG(slice_from_cstr(what))); } u8 b = map[sec->id - 1].bucket; return PE_IMAGE_BASE + (u64)out[b].rva + @@ -457,8 +457,9 @@ static int coff_import_cmp(const void* a, const void* b) { static const char* coff_import_lookup_name(Compiler* c, const LinkSymbol* s, size_t* nlen_out) { - size_t nlen = 0; - const char* nm = s->name ? pool_str(c->global, s->name, &nlen) : NULL; + Slice nm_s = s->name ? pool_slice(c->global, s->name) : SLICE_NULL; + const char* nm = nm_s.s; + size_t nlen = nm_s.len; static const char kImpPrefix[] = "__imp_"; const size_t kImpPrefixLen = sizeof(kImpPrefix) - 1u; if (nm && nlen > kImpPrefixLen && @@ -478,8 +479,9 @@ static const char* coff_import_lookup_name(Compiler* c, const LinkSymbol* s, * IAT-routed call). */ static int coff_import_is_func(Compiler* c, const LinkSymbol* s) { if (s->name) { - size_t nlen = 0; - const char* nm = pool_str(c->global, s->name, &nlen); + Slice nm_s = pool_slice(c->global, s->name); + const char* nm = nm_s.s; + size_t nlen = nm_s.len; if (nm && nlen > 6u && memcmp(nm, "__imp_", 6u) == 0) return 0; } if (s->kind == SK_FUNC || s->kind == SK_IFUNC) return 1; @@ -646,8 +648,9 @@ static void coff_plan_idata_layout(LinkImage* img, CoffImportTable* it) { /* Block 5: DLL name strings (NUL-terminated). */ it->name_base = off; for (u32 d = 0; d < it->ndlls; ++d) { - size_t nlen = 0; - const char* nm = pool_str(c->global, it->dlls[d].soname, &nlen); + Slice nm_s = pool_slice(c->global, it->dlls[d].soname); + const char* nm = nm_s.s; + size_t nlen = nm_s.len; if (!nm || nlen == 0) compiler_panic(c, no_loc(), "link_emit_coff: providing DSO has empty soname"); @@ -786,8 +789,9 @@ static void coff_emit_idata(LinkImage* img, const CoffImportTable* it, /* Block 5: DLL name strings. */ for (u32 d = 0; d < it->ndlls; ++d) { - size_t nlen = 0; - const char* nm = pool_str(c->global, it->dlls[d].soname, &nlen); + Slice nm_s = pool_slice(c->global, it->dlls[d].soname); + const char* nm = nm_s.s; + size_t nlen = nm_s.len; memcpy(buf + it->dlls[d].name_off, nm, nlen); /* NUL already zero. */ } @@ -865,17 +869,20 @@ static u16 coff_machine_or_panic(Compiler* c) { static int coff_section_name_starts(Compiler* c, const LinkSection* ls, const char* prefix) { - size_t n = 0; - size_t pn = strlen(prefix); - const char* s = ls->name ? pool_str(c->global, ls->name, &n) : NULL; + size_t pn = slice_from_cstr(prefix).len; + Slice s_s = ls->name ? pool_slice(c->global, ls->name) : SLICE_NULL; + const char* s = s_s.s; + size_t n = s_s.len; return s && n >= pn && memcmp(s, prefix, pn) == 0; } static int coff_section_name_cmp(Compiler* c, const LinkSection* a, const LinkSection* b) { - size_t an = 0, bn = 0; - const char* as = a->name ? pool_str(c->global, a->name, &an) : ""; - const char* bs = b->name ? pool_str(c->global, b->name, &bn) : ""; + Slice as_s = a->name ? pool_slice(c->global, a->name) : SLICE_NULL; + Slice bs_s = b->name ? pool_slice(c->global, b->name) : SLICE_NULL; + const char* as = as_s.s ? as_s.s : ""; + const char* bs = bs_s.s ? bs_s.s : ""; + size_t an = as_s.len, bn = bs_s.len; size_t n = an < bn ? an : bn; int cmp = n ? memcmp(as, bs, n) : 0; if (cmp) return cmp; @@ -1466,7 +1473,7 @@ static void coff_write_section_header(Writer* w, const char* name, u32 file_offset, u32 characteristics) { u8 nm[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - size_t n = strlen(name); + size_t n = slice_from_cstr(name).len; if (n > 8) n = 8; memcpy(nm, name, n); cfree_writer_write(w, nm, 8); diff --git a/src/link/link_dyn.c b/src/link/link_dyn.c @@ -36,6 +36,7 @@ #include "core/bytes.h" #include "core/heap.h" #include "core/pool.h" +#include "core/slice.h" #include "core/util.h" #include "core/vec.h" #include "link/link.h" @@ -339,8 +340,9 @@ static void build_dynsym(LinkImage* img, LinkDynState* dyn, LinkSymId lsid = il->funcs[i]; LinkSymbol* s = LinkSyms_at(&img->syms, lsid - 1); DynSymRec* r = &dyn->dynsym[idx]; - size_t namelen = 0; - const char* nm = pool_str(img->c->global, s->name, &namelen); + Slice nm_s = pool_slice(img->c->global, s->name); + const char* nm = nm_s.s; + size_t namelen = nm_s.len; r->st_name = bb_append_str(dynstr, nm, (u32)namelen); r->st_info = ELF64_ST_INFO(STB_GLOBAL, STT_FUNC); r->st_other = STV_DEFAULT; @@ -354,8 +356,9 @@ static void build_dynsym(LinkImage* img, LinkDynState* dyn, LinkSymId lsid = il->datas[i]; LinkSymbol* s = LinkSyms_at(&img->syms, lsid - 1); DynSymRec* r = &dyn->dynsym[idx]; - size_t namelen = 0; - const char* nm = pool_str(img->c->global, s->name, &namelen); + Slice nm_s = pool_slice(img->c->global, s->name); + const char* nm = nm_s.s; + size_t namelen = nm_s.len; u8 elf_type = STT_OBJECT; if (s->kind == SK_TLS) elf_type = STT_TLS; @@ -419,7 +422,7 @@ static void build_gnu_hash(Heap* h, LinkImage* img, LinkDynState* dyn, for (i = 0; i < hashed; ++i) { const DynSymRec* r = &dyn->dynsym[sym_offset + i]; const char* name = (const char*)dynstr->data + r->st_name; - size_t n = name ? strlen(name) : 0; + size_t n = name ? slice_from_cstr(name).len : 0; hashes[i] = gnu_hash_name(name, (u32)n); } @@ -526,7 +529,7 @@ void layout_dyn(Linker* l, LinkImage* img) { dyn->interp_path = l->interp_path ? l->interp_path - : pool_intern_cstr(l->c->global, arch->default_musl_interp); + : pool_intern_slice(l->c->global, slice_from_cstr(arch->default_musl_interp)); /* Step 1: enumerate imports + DT_NEEDED. */ collect_imports(l, img, h, &imports); @@ -541,8 +544,9 @@ void layout_dyn(Linker* l, LinkImage* img) { { u32 ni; for (ni = 0; ni < dyn->nneeded; ++ni) { - size_t slen = 0; - const char* s = pool_str(l->c->global, dyn->needed[ni], &slen); + Slice s_s = pool_slice(l->c->global, dyn->needed[ni]); + const char* s = s_s.s; + size_t slen = s_s.len; if (s && slen) (void)bb_append_str(&dynstr, s, (u32)slen); } } @@ -604,8 +608,9 @@ void layout_dyn(Linker* l, LinkImage* img) { compiler_panic(img->c, no_loc(), "link: oom on rela_dyn"); dyn->nrela_dyn = 0; - size_t namelen; - const char* interp_str = pool_str(l->c->global, dyn->interp_path, &namelen); + Slice interp_s = pool_slice(l->c->global, dyn->interp_path); + const char* interp_str = interp_s.s; + size_t namelen = interp_s.len; u64 interp_bytes = (u64)namelen + 1u; u64 dynsym_bytes = (u64)dyn->ndynsym * ELF64_SYM_SIZE; u64 dynstr_bytes = (u64)dyn->dynstr_len; @@ -785,15 +790,15 @@ void layout_dyn(Linker* l, LinkImage* img) { /* helper: populate a fresh LinkSection for a segment-internal range */ /* Inline because the args differ enough (sem, name) per slot. */ - Sym name_interp = pool_intern_cstr(l->c->global, ".interp"); - Sym name_dynsym = pool_intern_cstr(l->c->global, ".dynsym"); - Sym name_dynstr = pool_intern_cstr(l->c->global, ".dynstr"); - Sym name_gnu_hash = pool_intern_cstr(l->c->global, ".gnu.hash"); - Sym name_rela_dyn = pool_intern_cstr(l->c->global, ".rela.dyn"); - Sym name_rela_plt = pool_intern_cstr(l->c->global, ".rela.plt"); - Sym name_dynamic = pool_intern_cstr(l->c->global, ".dynamic"); - Sym name_plt = pool_intern_cstr(l->c->global, ".plt"); - Sym name_got_plt = pool_intern_cstr(l->c->global, ".got.plt"); + Sym name_interp = pool_intern_slice(l->c->global, SLICE_LIT(".interp")); + Sym name_dynsym = pool_intern_slice(l->c->global, SLICE_LIT(".dynsym")); + Sym name_dynstr = pool_intern_slice(l->c->global, SLICE_LIT(".dynstr")); + Sym name_gnu_hash = pool_intern_slice(l->c->global, SLICE_LIT(".gnu.hash")); + Sym name_rela_dyn = pool_intern_slice(l->c->global, SLICE_LIT(".rela.dyn")); + Sym name_rela_plt = pool_intern_slice(l->c->global, SLICE_LIT(".rela.plt")); + Sym name_dynamic = pool_intern_slice(l->c->global, SLICE_LIT(".dynamic")); + Sym name_plt = pool_intern_slice(l->c->global, SLICE_LIT(".plt")); + Sym name_got_plt = pool_intern_slice(l->c->global, SLICE_LIT(".got.plt")); #define INIT_SEC(IDX, NAME, SEG_IDX, OFF_IN_SEG, SIZE, ALIGN, FLAGS, SEM) \ do { \ diff --git a/src/link/link_elf.c b/src/link/link_elf.c @@ -49,6 +49,7 @@ #include "core/heap.h" #include "core/pool.h" +#include "core/slice.h" #include "core/util.h" #include "core/vec.h" #include "link/link.h" @@ -256,7 +257,8 @@ static void emit_dyn_record(LinkImage* img, u64 site_vaddr, u32 reloc_type, static const LinkArchDesc* elf_arch_or_panic(Compiler* c, const char* where) { const LinkArchDesc* arch = link_arch_desc_for(c); if (!arch || !arch->e_machine) - compiler_panic(c, no_loc(), "%s: no ELF arch descriptor", where); + compiler_panic(c, no_loc(), "%.*s: no ELF arch descriptor", + SLICE_ARG(slice_from_cstr(where))); return arch; } @@ -403,9 +405,10 @@ static void apply_all_relocs(LinkImage* img, u64 img_base) { continue; } { - size_t nl = 0; - const char* nm = - tgt->name ? pool_str(img->c->global, tgt->name, &nl) : ""; + Slice nm_s = tgt->name ? pool_slice(img->c->global, tgt->name) + : SLICE_NULL; + const char* nm = nm_s.s ? nm_s.s : ""; + size_t nl = nm_s.len; compiler_panic( img->c, no_loc(), "link: unhandled reloc kind %u against imported symbol '%.*s'", @@ -482,7 +485,7 @@ static u32 strb_add(StrBuilder* s, const char* str, u32 slen) { } static u32 strb_add_cstr(StrBuilder* s, const char* str) { - return strb_add(s, str, (u32)strlen(str)); + return strb_add(s, str, (u32)slice_from_cstr(str).len); } /* ---- symtab builder ---- */ @@ -723,8 +726,9 @@ void link_emit_elf(LinkImage* img, Writer* w) { u32 ni; for (ni = 0; ni < dyn->nneeded; ++ni) { Sym soname = dyn->needed[ni]; - size_t namelen = 0; - const char* nm = pool_str(c->global, soname, &namelen); + Slice nm_s = pool_slice(c->global, soname); + const char* nm = nm_s.s; + size_t namelen = nm_s.len; /* Linear search dynstr for this name. */ u32 off = 0; if (nm && namelen) { @@ -928,8 +932,9 @@ void link_emit_elf(LinkImage* img, Writer* w) { for (i = 0; i < noutshdr; ++i) { const OutShdr* o = &outshdrs[i]; if (o->name) { - size_t nlen; - const char* nm = pool_str(c->global, o->name, &nlen); + Slice nm_s = pool_slice(c->global, o->name); + const char* nm = nm_s.s; + size_t nlen = nm_s.len; outshdr_name_off[i] = nm && nlen ? strb_add(&shstrtab, nm, (u32)nlen) : 0; } else { @@ -989,7 +994,11 @@ void link_emit_elf(LinkImage* img, Writer* w) { LinkSymId canonical = symhash_get(&img->globals, s->name); if (canonical != LINK_SYM_NONE && canonical != s->id) continue; } - nm = s->name ? pool_str(c->global, s->name, &namelen) : ""; + { + Slice nm_s = s->name ? pool_slice(c->global, s->name) : SLICE_NULL; + nm = nm_s.s ? nm_s.s : ""; + namelen = nm_s.len; + } shndx = sym_shndx_for(s, outshdrs, noutshdr); /* st_value: in ET_EXEC, defined non-ABS symbols carry * absolute virtual addresses (IMAGE_BASE + image @@ -1285,13 +1294,13 @@ void link_emit_elf(LinkImage* img, Writer* w) { Sym n_reladyn = 0, n_relaplt = 0, n_dynamic = 0; Sym n_gotplt = 0; if (pie && img->dyn) { - n_dynsym = pool_intern_cstr(c->global, ".dynsym"); - n_dynstr = pool_intern_cstr(c->global, ".dynstr"); - n_gnuhash = pool_intern_cstr(c->global, ".gnu.hash"); - n_reladyn = pool_intern_cstr(c->global, ".rela.dyn"); - n_relaplt = pool_intern_cstr(c->global, ".rela.plt"); - n_dynamic = pool_intern_cstr(c->global, ".dynamic"); - n_gotplt = pool_intern_cstr(c->global, ".got.plt"); + n_dynsym = pool_intern_slice(c->global, SLICE_LIT(".dynsym")); + n_dynstr = pool_intern_slice(c->global, SLICE_LIT(".dynstr")); + n_gnuhash = pool_intern_slice(c->global, SLICE_LIT(".gnu.hash")); + n_reladyn = pool_intern_slice(c->global, SLICE_LIT(".rela.dyn")); + n_relaplt = pool_intern_slice(c->global, SLICE_LIT(".rela.plt")); + n_dynamic = pool_intern_slice(c->global, SLICE_LIT(".dynamic")); + n_gotplt = pool_intern_slice(c->global, SLICE_LIT(".got.plt")); } /* Two-pass: first find dynsym/dynstr/gotplt indices for sh_link * fixups, then emit. */ diff --git a/src/link/link_jit.c b/src/link/link_jit.c @@ -18,6 +18,7 @@ #include "core/heap.h" #include "core/metrics.h" #include "core/pool.h" +#include "core/slice.h" #include "core/util.h" #include "jit/tlv_thunk.h" #include "link/link.h" @@ -283,7 +284,7 @@ static void jit_patch_tlv_descriptors(CfreeJit* jit) { * marks a descriptor's +0 slot. * * Bitmap over LinkSymId so the inner reloc test is O(1). */ - Sym tlv_name = pool_intern_cstr(c->global, "__tlv_bootstrap"); + Sym tlv_name = pool_intern_slice(c->global, SLICE_LIT("__tlv_bootstrap")); u32 nsyms = LinkSyms_count(&img->syms); Heap* h = (Heap*)c->ctx->heap; u8* is_tlv_bootstrap = (u8*)h->alloc(h, nsyms + 1u, 1u); @@ -681,8 +682,8 @@ CfreeJit* cfree_jit_from_image(LinkImage* img) { /* Run .init_array constructors in forward order. */ { typedef void (*VoidFn)(void); - void* p_start = cfree_jit_lookup(jit, "__init_array_start"); - void* p_end = cfree_jit_lookup(jit, "__init_array_end"); + void* p_start = cfree_jit_lookup(jit, CFREE_SLICE_LIT("__init_array_start")); + void* p_end = cfree_jit_lookup(jit, CFREE_SLICE_LIT("__init_array_end")); if (p_start && p_end) { VoidFn* fn = (VoidFn*)p_start; VoidFn* end = (VoidFn*)p_end; @@ -742,14 +743,15 @@ void cfree_jit_free(CfreeJit* jit) { heap->free(heap, jit, sizeof(*jit)); } -void* cfree_jit_lookup(CfreeJit* jit, const char* name) { +void* cfree_jit_lookup(CfreeJit* jit, CfreeSlice name) { Sym sym; LinkSymId id; const LinkSymbol* s; - if (!jit || !name) return NULL; + if (!jit || !name.s) return NULL; /* C-symbol mangling lives in obj_format_c_mangle so JIT lookups by - * source-level name find the symbol regardless of target format. */ - sym = obj_format_c_mangle(jit->c, name); + * source-level name find the symbol regardless of target format. + * name.s is NUL-terminated (CFREE_SLICE_LIT / cfree_slice_cstr / interned). */ + sym = obj_format_c_mangle(jit->c, name.s); id = symhash_get(&jit->image->globals, sym); if (id == LINK_SYM_NONE) return NULL; s = LinkSyms_at(&jit->image->syms, id - 1); @@ -958,8 +960,9 @@ static void jit_append_obj_inner(CfreeJit* jit, ObjBuilder* ob) { if (prev && prev->defined && jit_bind_strength((u8)s->bind) == jit_bind_strength(SB_GLOBAL) && jit_bind_strength(prev->bind) == jit_bind_strength(SB_GLOBAL)) { - size_t namelen; - const char* nm = pool_str(jit->c->global, s->name, &namelen); + Slice nm_s = pool_slice(jit->c->global, s->name); + const char* nm = nm_s.s; + size_t namelen = nm_s.len; obj_format_demangle_c(jit->c, &nm, &namelen); obj_symiter_free(it); compiler_panic(jit->c, no_loc(), @@ -988,15 +991,14 @@ static void jit_append_obj_inner(CfreeJit* jit, ObjBuilder* ob) { obj_symiter_free(it2); } if (!ok && jit->linker->resolver) { - size_t namelen; - const char* nm = pool_str(jit->c->global, s->name, &namelen); - (void)namelen; - if (jit->linker->resolver(jit->linker->resolver_user, nm)) ok = 1; + Slice nm_s = pool_slice(jit->c->global, s->name); + if (jit->linker->resolver(jit->linker->resolver_user, nm_s)) ok = 1; } if (!ok && s->bind == SB_WEAK) ok = 1; if (!ok) { - size_t nlen; - const char* nm = pool_str(jit->c->global, s->name, &nlen); + Slice nm_s = pool_slice(jit->c->global, s->name); + const char* nm = nm_s.s; + size_t nlen = nm_s.len; if (nm && nlen == 15u && memcmp(nm, "__tlv_bootstrap", 15u) == 0) ok = 1; if (!ok) { @@ -1070,8 +1072,9 @@ static void jit_append_obj_inner(CfreeJit* jit, ObjBuilder* ob) { if (prev && prev->defined && jit_bind_strength((u8)s->bind) == jit_bind_strength(SB_GLOBAL) && jit_bind_strength(prev->bind) == jit_bind_strength(SB_GLOBAL)) { - size_t namelen; - const char* nm = pool_str(jit->c->global, s->name, &namelen); + Slice nm_s = pool_slice(jit->c->global, s->name); + const char* nm = nm_s.s; + size_t namelen = nm_s.len; obj_format_demangle_c(jit->c, &nm, &namelen); obj_symiter_free(it); compiler_panic(jit->c, no_loc(), @@ -1149,10 +1152,8 @@ static void jit_append_obj_inner(CfreeJit* jit, ObjBuilder* ob) { } } if (jit->linker->resolver && s->name != 0) { - size_t namelen; - const char* nm = pool_str(jit->c->global, s->name, &namelen); - void* p = jit->linker->resolver(jit->linker->resolver_user, nm); - (void)namelen; + Slice nm_s = pool_slice(jit->c->global, s->name); + void* p = jit->linker->resolver(jit->linker->resolver_user, nm_s); if (p) { s->kind = SK_ABS; s->vaddr = (u64)(uintptr_t)p; @@ -1167,8 +1168,9 @@ static void jit_append_obj_inner(CfreeJit* jit, ObjBuilder* ob) { continue; } if (s->name != 0) { - size_t nlen; - const char* nm = pool_str(jit->c->global, s->name, &nlen); + Slice nm_s = pool_slice(jit->c->global, s->name); + const char* nm = nm_s.s; + size_t nlen = nm_s.len; if (nm && nlen == 15u && memcmp(nm, "__tlv_bootstrap", 15u) == 0) { s->kind = SK_ABS; s->vaddr = 0; @@ -1431,7 +1433,7 @@ static int jit_view_input_has_debug(CfreeJit* jit, u32 ii) { const Section* s = obj_section_get(ob, (ObjSecId)(k + 1)); const char* nm; if (!s || !s->name) continue; - nm = pool_str(in_pool, s->name, NULL); + nm = pool_slice(in_pool, s->name).s; if (jit_view_is_debug_name(nm)) return 1; } return 0; @@ -1477,7 +1479,7 @@ static ViewSec* view_sec_for(CfreeJit* jit, ViewSec* tab, u32* ntab, ViewSec** tab_out) { Heap* h = (Heap*)jit->c->ctx->heap; Pool* view_pool = obj_compiler(view_ob)->global; - Sym vn = pool_intern_cstr(view_pool, name); + Sym vn = pool_intern_slice(view_pool, slice_from_cstr(name)); u32 i; for (i = 0; i < *ntab; ++i) { if (tab[i].view_name == vn) { @@ -1563,11 +1565,11 @@ static void jit_view_copy_debug_section(CfreeJit* jit, u32 ii, if (ts && ts->kind == SK_SECTION && ts->section_id != OBJ_SEC_NONE) { const Section* tsec = obj_section_get(in_ob, ts->section_id); if (tsec && tsec->kind == SEC_DEBUG && tsec->name) { - size_t tnlen = 0; - const char* tnm = - pool_str(obj_compiler(in_ob)->global, tsec->name, &tnlen); + Slice tnm_s = pool_slice(obj_compiler(in_ob)->global, tsec->name); + const char* tnm = tnm_s.s; + size_t tnlen = tnm_s.len; if (tnm) { - Sym v_tn = pool_intern(view_pool, tnm, tnlen); + Sym v_tn = pool_intern_slice(view_pool, (Slice){ .s = tnm, .len = tnlen }); ViewSec* tgt = view_sec_find(tab, ntab, v_tn); if (tgt) { S = (u64)tgt->snap; @@ -1637,10 +1639,9 @@ static CfreeObjFile* jit_view_build(CfreeJit* jit) { for (k = 0; k < nsec; ++k) { const Section* s = obj_section_get(in_ob, (ObjSecId)(k + 1)); const char* nm; - size_t nlen = 0; ViewSec* vs; if (!s || !s->name) continue; - nm = pool_str(obj_compiler(in_ob)->global, s->name, &nlen); + nm = pool_slice(obj_compiler(in_ob)->global, s->name).s; if (!nm || !jit_view_is_debug_name(nm)) continue; vs = view_sec_for(jit, tab, &ntab, &cap, nm, s->flags, s->align ? s->align : 1u, s->entsize, view_ob, &tab); @@ -1659,9 +1660,14 @@ static CfreeObjFile* jit_view_build(CfreeJit* jit) { Sym v_nm; ViewSec* vs; if (!s || !s->name) continue; - nm = pool_str(obj_compiler(in_ob)->global, s->name, &nlen); + { + Slice nm_s = pool_slice(obj_compiler(in_ob)->global, s->name); + nm = nm_s.s; + nlen = nm_s.len; + } if (!nm || !jit_view_is_debug_name(nm)) continue; - v_nm = pool_intern(obj_compiler(view_ob)->global, nm, nlen); + v_nm = pool_intern_slice(obj_compiler(view_ob)->global, + (Slice){ .s = nm, .len = nlen }); vs = view_sec_find(tab, ntab, v_nm); if (!vs) continue; jit_view_copy_debug_section(jit, ii, (ObjSecId)(k + 1), view_ob, tab, @@ -1693,12 +1699,15 @@ static int jit_sym_kind_visible(u8 k) { /* Resolve a LinkSymbol's interned name to a stable C string, stripping * the target format's C-mangling prefix (Mach-O's leading `_`) so the * user sees the source-level name. */ -static const char* jit_sym_name_cstr(CfreeJit* jit, const LinkSymbol* s) { - size_t len = 0; - const char* nm = pool_str(jit->c->global, s->name, &len); - if (!nm) return NULL; +static Slice jit_sym_name_slice(CfreeJit* jit, const LinkSymbol* s) { + Slice nm_s = pool_slice(jit->c->global, s->name); + const char* nm = nm_s.s; + size_t len = nm_s.len; + if (!nm) return CFREE_SLICE_NULL; obj_format_demangle_c(jit->c, &nm, &len); - return nm; + nm_s.s = nm; + nm_s.len = len; + return nm_s; } static uint64_t jit_sym_runtime_addr(CfreeJit* jit, const LinkSymbol* s) { @@ -1707,13 +1716,13 @@ static uint64_t jit_sym_runtime_addr(CfreeJit* jit, const LinkSymbol* s) { } CfreeStatus cfree_jit_addr_to_sym(CfreeJit* jit, uint64_t addr, - const char** name_out, uint64_t* off_out) { + CfreeSlice* name_out, uint64_t* off_out) { u32 n; u32 i; const LinkSymbol* best = NULL; uint64_t best_base = 0; uint64_t best_off = (uint64_t)-1; - if (name_out) *name_out = NULL; + if (name_out) *name_out = CFREE_SLICE_NULL; if (off_out) *off_out = 0; if (!jit) return CFREE_INVALID; n = LinkSyms_count(&jit->image->syms); @@ -1735,7 +1744,7 @@ CfreeStatus cfree_jit_addr_to_sym(CfreeJit* jit, uint64_t addr, } } if (best) { - if (name_out) *name_out = jit_sym_name_cstr(jit, best); + if (name_out) *name_out = jit_sym_name_slice(jit, best); if (off_out) *off_out = addr - best_base; return CFREE_OK; } @@ -1770,7 +1779,7 @@ CfreeIterResult cfree_jit_sym_iter_next(CfreeJitSymIter* it, CfreeJitSym* out) { LinkSymbol* s = LinkSyms_at(&it->jit->image->syms, it->next++); if (!s || !s->defined) continue; if (!jit_sym_kind_visible(s->kind)) continue; - out->name = jit_sym_name_cstr(it->jit, s); + out->name = jit_sym_name_slice(it->jit, s); out->addr = jit_sym_runtime_addr(it->jit, s); out->size = s->size; out->kind = (CfreeSymKind)s->kind; @@ -1855,8 +1864,8 @@ void cfree_jit_run_dtors(CfreeJit* jit) { void* p_start; void* p_end; if (!jit) return; - p_start = cfree_jit_lookup(jit, "__fini_array_start"); - p_end = cfree_jit_lookup(jit, "__fini_array_end"); + p_start = cfree_jit_lookup(jit, CFREE_SLICE_LIT("__fini_array_start")); + p_end = cfree_jit_lookup(jit, CFREE_SLICE_LIT("__fini_array_end")); if (p_start && p_end) { VoidFn* begin = (VoidFn*)p_start; VoidFn* fn = (VoidFn*)p_end; diff --git a/src/link/link_layout.c b/src/link/link_layout.c @@ -18,6 +18,7 @@ #include "core/heap.h" #include "core/metrics.h" #include "core/pool.h" +#include "core/slice.h" #include "core/util.h" #include "core/vec.h" #include "link/link.h" @@ -413,8 +414,8 @@ void link_layout_sections(Linker* l, LinkImage* img, const GcLive* g) { static int match_glob(const char* pat, const char* name) { size_t plen, nlen; if (!pat || !name) return 0; - plen = strlen(pat); - nlen = strlen(name); + plen = slice_from_cstr(pat).len; + nlen = slice_from_cstr(name).len; if (plen == 1 && pat[0] == '*') return 1; if (plen >= 2 && pat[plen - 1] == '*') { if (nlen + 1 < plen) return 0; @@ -439,12 +440,12 @@ static u64 eval_link_expr(Linker* l, LinkImage* img, u64 dot, case CFREE_LE_DOT: return dot; case CFREE_LE_SYM: { - Sym name = pool_intern_cstr(l->c->global, e->v.name); + Sym name = pool_intern_slice(l->c->global, e->v.name); LinkSymId id = symhash_get(&img->globals, name); if (id == LINK_SYM_NONE) { compiler_panic(l->c, no_loc(), - "linker script: undefined symbol '%s' in expression", - e->v.name); + "linker script: undefined symbol '%.*s' in expression", + SLICE_ARG(pool_slice(l->c->global, name))); } return LinkSyms_at(&img->syms, id - 1)->vaddr; } @@ -513,8 +514,8 @@ void link_emit_boundary_sym(Linker* l, LinkImage* img, const char* name, u8 kind = SK_OBJ; u32 i, n; if (l->c->target.obj == CFREE_OBJ_COFF && - (strcmp(name, "__ImageBase") == 0 || - strcmp(name, "_tls_used") == 0)) { + (slice_eq_cstr(slice_from_cstr(name), "__ImageBase") || + slice_eq_cstr(slice_from_cstr(name), "_tls_used"))) { kind = SK_ABS; } memset(&rec, 0, sizeof(rec)); @@ -552,9 +553,11 @@ void link_define_boundary(Linker* l, LinkImage* img, const char* name, } /* Upsert a global symbol (mirror of emit_boundary_sym, used by apply_asn). */ -static void upsert_global_sym(Linker* l, LinkImage* img, const char* name, +static void upsert_global_sym(Linker* l, LinkImage* img, CfreeSlice name, u64 vaddr) { - link_emit_boundary_sym(l, img, name, vaddr); + /* Script sym slices are arena-interned and NUL-terminated; the boundary + * emitter mangles via obj_format_c_mangle which needs a C string. */ + link_emit_boundary_sym(l, img, name.s, vaddr); } /* Apply one CfreeLinkAssignment. */ @@ -573,13 +576,15 @@ static void apply_asn(Linker* l, LinkImage* img, u64* dot, break; case CFREE_LAS_SYM: case CFREE_LAS_PROVIDE: - if (asn->sym) upsert_global_sym(l, img, asn->sym, v); + if (asn->sym.s) upsert_global_sym(l, img, asn->sym, v); break; } } static int input_match_section(const CfreeLinkInputMatch* m, const char* nm) { - return match_glob(m->section_pattern, nm); + /* section_pattern is an arena-interned, NUL-terminated span of the + * script text; match_glob scans it as a C string. */ + return match_glob(m->section_pattern.s, nm); } static void link_layout_sections_scripted(Linker* l, LinkImage* img, @@ -630,7 +635,8 @@ static void link_layout_sections_scripted(Linker* l, LinkImage* img, u32 nseg_max = 0; for (si = 0; si < script->nsections; ++si) - if (strcmp(script->sections[si].name, "/DISCARD/") != 0) ++nseg_max; + if (!slice_eq_cstr(script->sections[si].name, "/DISCARD/")) + ++nseg_max; img->segments = nseg_max ? (LinkSegment*)h->alloc(h, sizeof(*img->segments) * nseg_max, _Alignof(LinkSegment)) @@ -655,7 +661,7 @@ static void link_layout_sections_scripted(Linker* l, LinkImage* img, for (si = 0; si < script->nsections; ++si) { const CfreeLinkOutputSection* os = &script->sections[si]; - int is_discard = (strcmp(os->name, "/DISCARD/") == 0); + int is_discard = slice_eq_cstr(os->name, "/DISCARD/"); if (is_discard) { u32 mi; @@ -666,11 +672,12 @@ static void link_layout_sections_scripted(Linker* l, LinkImage* img, for (j = 1; j < obj_section_count(ob); ++j) { const Section* s; const char* nm; - size_t nl; if (claimed[ii][j]) continue; s = obj_section_get(ob, j); if (!s) continue; - nm = pool_str(l->c->global, s->name, &nl); + { + nm = pool_slice(l->c->global, s->name).s; + } if (!nm) continue; if (input_match_section(im, nm)) claimed[ii][j] = 1; } @@ -704,7 +711,6 @@ static void link_layout_sections_scripted(Linker* l, LinkImage* img, for (j = 1; j < obj_section_count(ob); ++j) { const Section* s; const char* nm; - size_t nl; u32 align; u64 ofs; LinkSection* ls; @@ -713,7 +719,9 @@ static void link_layout_sections_scripted(Linker* l, LinkImage* img, if (!link_gc_live_get(g, ii, j)) continue; s = obj_section_get(ob, j); if (!s || !link_section_kept(s)) continue; - nm = pool_str(l->c->global, s->name, &nl); + { + nm = pool_slice(l->c->global, s->name).s; + } if (!nm) continue; if (!input_match_section(im, nm)) continue; @@ -910,7 +918,7 @@ void link_layout_commons(Linker* l, LinkImage* img) { commsec->size = bss_cursor - bss_start; commsec->flags = SF_ALLOC | SF_WRITE; commsec->align = max_align; - commsec->name = pool_intern_cstr(img->c->global, ".bss.common"); + commsec->name = pool_intern_slice(img->c->global, SLICE_LIT(".bss.common")); commsec->sem = SSEM_NOBITS; img->nsections++; diff --git a/src/link/link_macho.c b/src/link/link_macho.c @@ -43,6 +43,7 @@ #include "core/heap.h" #include "core/pool.h" #include "core/sha256.h" +#include "core/slice.h" #include "core/util.h" #include "core/vec.h" #include "link/link.h" @@ -433,7 +434,7 @@ static void collect_imports(MCtx* x) { if (in->kind == LINK_INPUT_DSO_BYTES) install = in->soname; } if (install == 0) - install = pool_intern_cstr(x->c->global, "/usr/lib/libSystem.B.dylib"); + install = pool_intern_slice(x->c->global, SLICE_LIT("/usr/lib/libSystem.B.dylib")); u32 ord = dylib_ordinal_of(x, install); if (!ord) { if (VEC_GROW(h, x->dylibs, cap_d, x->ndylibs + 1u)) @@ -637,8 +638,9 @@ static int sec_needs_data_const(const LinkImage* img, const LinkSection* ls) { * a previous version used a shared static buffer which aliased all * sections to whichever name was set last. */ static void pick_macho_names(const LinkSection* ls, Compiler* c, MSec* m) { - size_t nlen; - const char* nm = pool_str(c->global, ls->name, &nlen); + Slice nm_s = pool_slice(c->global, ls->name); + const char* nm = nm_s.s; + size_t nlen = nm_s.len; if (nm) { /* Comma-form: "__SEG,__sect" round-tripped from a Mach-O input. */ for (size_t i = 0; i < nlen; ++i) { @@ -732,7 +734,8 @@ static void plan_layout(MCtx* x) { m->link_sec_id = ls->id; pick_macho_names(ls, x->c, m); /* Force into __TEXT. */ - if (strcmp(m->segname, "__TEXT") != 0) m->segname = "__TEXT"; + if (!slice_eq_cstr(slice_from_cstr(m->segname), "__TEXT")) + m->segname = "__TEXT"; m->align = ls->align ? ls->align : 1u; m->size = ls->size; m->segidx = 1; @@ -809,7 +812,8 @@ static void plan_layout(MCtx* x) { memset(m, 0, sizeof(*m)); m->link_sec_id = ls->id; pick_macho_names(ls, x->c, m); - if (strcmp(m->segname, "__DATA") != 0) m->segname = "__DATA"; + if (!slice_eq_cstr(slice_from_cstr(m->segname), "__DATA")) + m->segname = "__DATA"; m->align = ls->align ? ls->align : 1u; m->size = ls->size; m->segidx = 3; @@ -819,9 +823,9 @@ static void plan_layout(MCtx* x) { * __mod_init_func / __mod_term_func sections must carry the * S_MOD_INIT_FUNC_POINTERS / S_MOD_TERM_FUNC_POINTERS type or dyld * skips them entirely — leaving constructors unrun at startup. */ - if (strcmp(m->sectname, "__mod_init_func") == 0) + if (slice_eq_cstr(slice_from_cstr(m->sectname), "__mod_init_func")) m->flags = 0x00000009u /*S_MOD_INIT_FUNC_POINTERS*/; - else if (strcmp(m->sectname, "__mod_term_func") == 0) + else if (slice_eq_cstr(slice_from_cstr(m->sectname), "__mod_term_func")) m->flags = 0x0000000au /*S_MOD_TERM_FUNC_POINTERS*/; else if (ls->flags & SF_TLS) { /* TLV sections: dyld dispatches by section type, not name. Map @@ -830,7 +834,7 @@ static void plan_layout(MCtx* x) { * __thread_bss → S_THREAD_LOCAL_ZEROFILL (zero-init data). Done * by sectname so per-TU inputs without a Mach-O ext_type still * get the right section type. */ - if (strcmp(m->sectname, "__thread_vars") == 0) { + if (slice_eq_cstr(slice_from_cstr(m->sectname), "__thread_vars")) { m->flags = S_THREAD_LOCAL_VARIABLES; /* Each descriptor is three pointers (24B) whose first word is * dyld's _tlv_bootstrap thunk pointer. Clang/llvm emit @@ -889,8 +893,10 @@ static void plan_layout(MCtx* x) { u32 j = a; while (j > 0) { MSec* prev = &x->secs[base + j - 1]; - int cmp = strcmp(prev->segname, key.segname); - if (cmp == 0) cmp = strcmp(prev->sectname, key.sectname); + /* Ordering compare for stable sort: slices don't order, keep strcmp. */ + int cmp = strcmp(prev->segname, key.segname); /* ordering */ + if (cmp == 0) + cmp = strcmp(prev->sectname, key.sectname); /* ordering */ if (cmp <= 0) break; x->secs[base + j] = x->secs[base + j - 1]; msec_repair_name_ptrs(&x->secs[base + j]); @@ -910,8 +916,10 @@ static void plan_layout(MCtx* x) { for (u32 a = sg->first_sec; a < sg->first_sec + sg->nsects; ++a) { int seen = 0; for (u32 b = sg->first_sec; b < a; ++b) { - if (strcmp(x->secs[a].sectname, x->secs[b].sectname) == 0 && - strcmp(x->secs[a].segname, x->secs[b].segname) == 0) { + if (slice_eq_cstr(slice_from_cstr(x->secs[a].sectname), + x->secs[b].sectname) && + slice_eq_cstr(slice_from_cstr(x->secs[a].segname), + x->secs[b].segname)) { seen = 1; break; } @@ -955,15 +963,14 @@ static void plan_layout(MCtx* x) { sizeofcmds += MACHO_SYMTAB_CMD_SIZE + MACHO_DYSYMTAB_CMD_SIZE; /* LC_LOAD_DYLINKER */ { - u32 ld_size = 12u + (u32)strlen("/usr/lib/dyld") + 1u; + u32 ld_size = 12u + (u32)(sizeof("/usr/lib/dyld") - 1u) + 1u; sizeofcmds += (u32)ALIGN_UP((u64)ld_size, 8u); } /* LC_UUID + LC_BUILD_VERSION + LC_MAIN */ sizeofcmds += 24u + 24u + 24u; /* LC_LOAD_DYLIB per dylib */ for (u32 i = 0; i < x->ndylibs; ++i) { - size_t nl; - pool_str(x->c->global, x->dylibs[i].install, &nl); + size_t nl = pool_slice(x->c->global, x->dylibs[i].install).len; u32 sz = 24u + (u32)nl + 1u; sizeofcmds += (u32)ALIGN_UP((u64)sz, 8u); } @@ -1026,14 +1033,16 @@ static void plan_layout(MCtx* x) { x->stubs_vaddr = 0; for (u32 j = 0; j < sg->nsects; ++j) { MSec* m = &x->secs[sg->first_sec + j]; - if (strcmp(m->sectname, "__stubs") == 0) x->stubs_vaddr = m->vaddr; + if (slice_eq_cstr(slice_from_cstr(m->sectname), "__stubs")) + x->stubs_vaddr = m->vaddr; } x->text_filesz = sg->filesize; } if (i == 2) { for (u32 j = 0; j < sg->nsects; ++j) { MSec* m = &x->secs[sg->first_sec + j]; - if (strcmp(m->sectname, "__got") == 0) x->got_vaddr = m->vaddr; + if (slice_eq_cstr(slice_from_cstr(m->sectname), "__got")) + x->got_vaddr = m->vaddr; } x->data_const_vaddr = sg->vmaddr; x->data_const_filesz = sg->filesize; @@ -1041,14 +1050,14 @@ static void plan_layout(MCtx* x) { if (i == 3) { for (u32 j = 0; j < sg->nsects; ++j) { MSec* m = &x->secs[sg->first_sec + j]; - if (strcmp(m->sectname, "__thread_ptrs") == 0) + if (slice_eq_cstr(slice_from_cstr(m->sectname), "__thread_ptrs")) x->tlv_ptrs_vaddr = m->vaddr; /* TLS storage image base: min vaddr across __thread_data and * __thread_bss sections. __thread_vars is excluded — it holds * the descriptors, not the data that maps into the per-thread * block. */ - if ((strcmp(m->sectname, "__thread_data") == 0 || - strcmp(m->sectname, "__thread_bss") == 0) && + if ((slice_eq_cstr(slice_from_cstr(m->sectname), "__thread_data") || + slice_eq_cstr(slice_from_cstr(m->sectname), "__thread_bss")) && (!x->has_tls_image || m->vaddr < x->tls_image_vaddr)) { x->tls_image_vaddr = m->vaddr; x->has_tls_image = 1; @@ -1124,14 +1133,16 @@ static void plan_layout(MCtx* x) { MSec* m = &x->secs[order[i]]; OutSec* tail = x->nouts ? &x->outs[x->nouts - 1] : NULL; int merge = tail && tail->segidx == m->segidx && - strcmp(tail->sectname, m->sectname) == 0 && - strcmp(tail->segname, m->segname) == 0; + slice_eq_cstr(slice_from_cstr(tail->sectname), + m->sectname) && + slice_eq_cstr(slice_from_cstr(tail->segname), m->segname); if (merge) { if (tail->flags != m->flags || tail->is_zerofill != m->is_zerofill) compiler_panic( x->c, no_loc(), - "link_macho: coalesce mismatch on %s,%s (flags/zerofill)", - m->segname, m->sectname); + "link_macho: coalesce mismatch on %.*s,%.*s (flags/zerofill)", + SLICE_ARG(slice_from_cstr(m->segname)), + SLICE_ARG(slice_from_cstr(m->sectname))); u64 end = m->vaddr + m->size; u64 prev_end = tail->vaddr + tail->size; if (end > prev_end) tail->size = end - tail->vaddr; @@ -1764,8 +1775,9 @@ static void build_chained_fixups(MCtx* x, FixList* fl) { mbuf_u8(out, 0); for (u32 i = 0; i < x->nimports_real; ++i) { MachImp* mi = &x->imports[i]; - size_t nl; - const char* nm = pool_str(x->c->global, mi->name, &nl); + Slice nm_s = pool_slice(x->c->global, mi->name); + const char* nm = nm_s.s; + size_t nl = nm_s.len; if (!nm || !nl || mi->dylib_ord == 0 || mi->dylib_ord > x->ndylibs) { compiler_panic(x->c, no_loc(), "link_macho: invalid chained import %u " @@ -1820,8 +1832,9 @@ static void build_exports_trie(MCtx* x) { mbuf_u8(out, 0); /* children 0 */ return; } - size_t nl; - const char* nm = pool_str(x->c->global, esym->name, &nl); + Slice nm_s = pool_slice(x->c->global, esym->name); + const char* nm = nm_s.s; + size_t nl = nm_s.len; if (!nm || nl == 0) { mbuf_u8(out, 0); mbuf_u8(out, 0); @@ -1950,8 +1963,9 @@ static void build_symtab(MCtx* x) { break; } } - size_t nl; - const char* nm = pool_str(x->c->global, s->name, &nl); + Slice nm_s = pool_slice(x->c->global, s->name); + const char* nm = nm_s.s; + size_t nl = nm_s.len; u32 strx = x->strtab.len; if (nm && nl) mbuf_str(&x->strtab, nm, (u32)nl); @@ -1974,8 +1988,9 @@ static void build_symtab(MCtx* x) { u32 imp_first_symtab_idx = n_extdef; for (u32 i = 0; i < x->nimports_real; ++i) { MachImp* mi = &x->imports[i]; - size_t nl; - const char* nm = pool_str(x->c->global, mi->name, &nl); + Slice nm_s = pool_slice(x->c->global, mi->name); + const char* nm = nm_s.s; + size_t nl = nm_s.len; u32 strx = x->strtab.len; if (nm && nl) mbuf_str(&x->strtab, nm, (u32)nl); @@ -2002,7 +2017,7 @@ static void build_symtab(MCtx* x) { * so a sectname match identifies them unambiguously. */ for (u32 i = 0; i < x->nouts; ++i) { OutSec* o = &x->outs[i]; - if (strcmp(o->sectname, "__stubs") == 0 && o->size) { + if (slice_eq_cstr(slice_from_cstr(o->sectname), "__stubs") && o->size) { o->reserved1 = indirect_start; for (u32 k = 0; k < x->nimports; ++k) { MachImp* mi = &x->imports[k]; @@ -2015,7 +2030,7 @@ static void build_symtab(MCtx* x) { } for (u32 i = 0; i < x->nouts; ++i) { OutSec* o = &x->outs[i]; - if (strcmp(o->sectname, "__got") == 0 && o->size) { + if (slice_eq_cstr(slice_from_cstr(o->sectname), "__got") && o->size) { o->reserved1 = indirect_start; for (u32 k = 0; k < x->nimports; ++k) { MachImp* mi = &x->imports[k]; @@ -2136,7 +2151,7 @@ static void build_codesig_skeleton(MCtx* x, u32 code_limit, const char* ident) { * identifier (ident_len + 1) * hashes (nslots * 32) */ - u32 ident_len = (u32)strlen(ident) + 1u; + u32 ident_len = (u32)slice_from_cstr(ident).len + 1u; u32 cd_hdr = 88u; u32 cd_size = cd_hdr + ident_len + nslots * CS_SHA256_LEN; /* SuperBlob: 12 hdr + 8 slot + cd. */ @@ -2191,7 +2206,7 @@ static void compute_codesig(MCtx* x, const u8* full_file, u32 file_len_excl_cs, const char* ident) { u32 code_page = 1u << CS_PAGE_SIZE_LOG2; u32 nslots = (file_len_excl_cs + code_page - 1u) / code_page; - u32 ident_len = (u32)strlen(ident) + 1u; + u32 ident_len = (u32)slice_from_cstr(ident).len + 1u; u8* cd = x->codesig.data + 12 + 8; u8* hashes = cd + 88u + ident_len; @@ -2220,7 +2235,7 @@ static void emit_load_command_segment(MByte* lc, MCtx* x, u32 segidx) { /* segname: 16 bytes zero-padded */ u8 nm[16]; memset(nm, 0, 16); - size_t nlen = strlen(sg->name); + size_t nlen = slice_from_cstr(sg->name).len; if (nlen > 16) nlen = 16; memcpy(nm, sg->name, nlen); mbuf_append(lc, nm, 16); @@ -2238,10 +2253,10 @@ static void emit_load_command_segment(MByte* lc, MCtx* x, u32 segidx) { u8 sname[16], gname[16]; memset(sname, 0, 16); memset(gname, 0, 16); - size_t sl = o->sectname ? strlen(o->sectname) : 0; + size_t sl = o->sectname ? slice_from_cstr(o->sectname).len : 0; if (sl > 16) sl = 16; if (sl) memcpy(sname, o->sectname, sl); - size_t gl = strlen(sg->name); /* segname must match */ + size_t gl = slice_from_cstr(sg->name).len; /* segname must match */ if (gl > 16) gl = 16; memcpy(gname, sg->name, gl); mbuf_append(lc, sname, 16); @@ -2384,11 +2399,12 @@ void link_emit_macho(LinkImage* img, Writer* w) { /* LC_LOAD_DYLINKER */ { const char* dyld = "/usr/lib/dyld"; - u32 cmd_size = (u32)ALIGN_UP((u64)(12u + (u32)strlen(dyld) + 1u), 8u); + u32 dyld_len = (u32)slice_from_cstr(dyld).len; + u32 cmd_size = (u32)ALIGN_UP((u64)(12u + dyld_len + 1u), 8u); mbuf_u32(&lc, LC_LOAD_DYLINKER); mbuf_u32(&lc, cmd_size); mbuf_u32(&lc, 12u); /* name offset within cmd */ - u32 wrote = mbuf_str(&lc, dyld, (u32)strlen(dyld)); + u32 wrote = mbuf_str(&lc, dyld, dyld_len); (void)wrote; /* Pad to cmd_size. */ while (lc.len < (u32)((u64)mbuf_align(&lc, 1) + 0)) { @@ -2398,7 +2414,7 @@ void link_emit_macho(LinkImage* img, Writer* w) { /* Re-align to cmd_size. */ u32 want = (u32)(lc.len); /* Walk back: lc grew by 12 + (strlen+1). Pad to cmd_size. */ - u32 cmd_start_back = lc.len - (12u + (u32)strlen(dyld) + 1u); + u32 cmd_start_back = lc.len - (12u + dyld_len + 1u); u32 pad_needed = cmd_size - (lc.len - cmd_start_back); while (pad_needed-- > 0) mbuf_u8(&lc, 0); (void)want; @@ -2426,8 +2442,9 @@ void link_emit_macho(LinkImage* img, Writer* w) { /* LC_LOAD_DYLIB per dylib. */ for (u32 i = 0; i < x.ndylibs; ++i) { - size_t nl; - const char* nm = pool_str(x.c->global, x.dylibs[i].install, &nl); + Slice nm_s = pool_slice(x.c->global, x.dylibs[i].install); + const char* nm = nm_s.s; + size_t nl = nm_s.len; u32 cmd_size = (u32)ALIGN_UP((u64)(24u + (u32)nl + 1u), 8u); u32 cmd_start = lc.len; mbuf_u32(&lc, LC_LOAD_DYLIB); diff --git a/src/link/link_reloc_layout.c b/src/link/link_reloc_layout.c @@ -17,6 +17,7 @@ #include "core/bytes.h" #include "core/heap.h" #include "core/pool.h" +#include "core/slice.h" #include "core/util.h" #include "core/vec.h" #include "link/link.h" @@ -173,7 +174,7 @@ void link_emit_tls_boundaries(Linker* l, LinkImage* img) { u64 tdata_start = img->tls_vaddr; u64 tdata_end = img->tls_vaddr + img->tls_filesz; u64 tbss_size = img->tls_memsz - img->tls_filesz; - Sym sym_size = pool_intern_cstr(l->c->global, "__tbss_size"); + Sym sym_size = pool_intern_slice(l->c->global, SLICE_LIT("__tbss_size")); LinkSymId id; LinkSymbol rec; @@ -209,10 +210,14 @@ void link_emit_encoding_section_boundaries(Linker* l, LinkImage* img) { int found = 0; if (sym->defined) continue; if (sym->name == 0) continue; - nm = pool_str(l->c->global, sym->name, &namelen); + { + Slice nm_s = pool_slice(l->c->global, sym->name); + nm = nm_s.s; + namelen = nm_s.len; + } if (!link_gc_split_start_stop(nm, namelen, &off, &ilen, &is_start)) continue; - secname = pool_intern(l->c->global, nm + off, ilen); + secname = pool_intern_slice(l->c->global, (Slice){ .s = nm + off, .len = ilen }); for (ii = 0; ii < LinkInputs_count(&l->inputs); ++ii) { ObjBuilder* ob = LinkInputs_at(&l->inputs, ii)->obj; InputMap* m = &img->input_maps[ii]; @@ -520,7 +525,7 @@ void link_layout_jit_stubs(Linker* l, LinkImage* img, u32 map_size, stubs_sec->size = stubs_size; stubs_sec->flags = SF_ALLOC | SF_EXEC; stubs_sec->align = 4; - stubs_sec->name = pool_intern_cstr(l->c->global, ".cfree_jit_call_stubs"); + stubs_sec->name = pool_intern_slice(l->c->global, SLICE_LIT(".cfree_jit_call_stubs")); stubs_sec->sem = SSEM_PROGBITS; slots_sec = &img->sections[sec_base + 1u]; @@ -535,7 +540,7 @@ void link_layout_jit_stubs(Linker* l, LinkImage* img, u32 map_size, slots_sec->size = slots_size; slots_sec->flags = SF_ALLOC | SF_WRITE; slots_sec->align = 8; - slots_sec->name = pool_intern_cstr(l->c->global, ".cfree_jit_call_slots"); + slots_sec->name = pool_intern_slice(l->c->global, SLICE_LIT(".cfree_jit_call_slots")); slots_sec->sem = SSEM_PROGBITS; img->nsections += 2u; @@ -741,7 +746,7 @@ void link_layout_got(Linker* l, LinkImage* img, u32 map_size, gotsec->size = got_size; gotsec->flags = SF_ALLOC | SF_WRITE; gotsec->align = 8; - gotsec->name = pool_intern_cstr(img->c->global, ".got"); + gotsec->name = pool_intern_slice(img->c->global, SLICE_LIT(".got")); gotsec->sem = SSEM_PROGBITS; img->nsections++; @@ -842,7 +847,7 @@ void link_layout_iplt(Linker* l, LinkImage* img) { pairs_size = (u64)nifunc * 16u; if (emit_init_array) { - ifunc_init_name = pool_intern_cstr(l->c->global, "__cfree_ifunc_init"); + ifunc_init_name = pool_intern_slice(l->c->global, SLICE_LIT("__cfree_ifunc_init")); ifunc_init_sym = symhash_get(&img->globals, ifunc_init_name); if (ifunc_init_sym == LINK_SYM_NONE || !LinkSyms_at(&img->syms, ifunc_init_sym - 1)->defined) { @@ -936,7 +941,7 @@ void link_layout_iplt(Linker* l, LinkImage* img) { sec_base = link_iplt_alloc_sections(img, nsec); } - pairs_section_name = pool_intern_cstr(l->c->global, ".iplt.pairs"); + pairs_section_name = pool_intern_slice(l->c->global, SLICE_LIT(".iplt.pairs")); init_section_name = obj_secname_preinit_array(l->c); iplt_sec = &img->sections[sec_base + 0u]; @@ -951,7 +956,7 @@ void link_layout_iplt(Linker* l, LinkImage* img) { iplt_sec->size = iplt_size; iplt_sec->flags = SF_ALLOC | SF_EXEC; iplt_sec->align = 4; - iplt_sec->name = pool_intern_cstr(l->c->global, ".iplt"); + iplt_sec->name = pool_intern_slice(l->c->global, SLICE_LIT(".iplt")); iplt_sec->sem = SSEM_PROGBITS; igot_sec = &img->sections[sec_base + 1u]; @@ -966,7 +971,7 @@ void link_layout_iplt(Linker* l, LinkImage* img) { igot_sec->size = igot_size; igot_sec->flags = SF_ALLOC | SF_WRITE; igot_sec->align = 8; - igot_sec->name = pool_intern_cstr(l->c->global, ".igot.plt"); + igot_sec->name = pool_intern_slice(l->c->global, SLICE_LIT(".igot.plt")); igot_sec->sem = SSEM_PROGBITS; pairs_sec = &img->sections[sec_base + 2u]; @@ -1170,15 +1175,17 @@ void link_resolve_entry(Linker* l, LinkImage* img) { if (l->entry_name == 0) return; id = symhash_get(&img->globals, l->entry_name); if (id == LINK_SYM_NONE) { - size_t namelen; - const char* nm = pool_str(l->c->global, l->entry_name, &namelen); + Slice nm_s = pool_slice(l->c->global, l->entry_name); + const char* nm = nm_s.s; + size_t namelen = nm_s.len; compiler_panic(l->c, no_loc(), "link: entry symbol '%.*s' not defined", (int)namelen, nm); } s = LinkSyms_at(&img->syms, id - 1); if (!s->defined) { - size_t namelen; - const char* nm = pool_str(l->c->global, l->entry_name, &namelen); + Slice nm_s = pool_slice(l->c->global, l->entry_name); + const char* nm = nm_s.s; + size_t namelen = nm_s.len; compiler_panic(l->c, no_loc(), "link: entry symbol '%.*s' is undefined", (int)namelen, nm); } diff --git a/src/link/link_relocatable.c b/src/link/link_relocatable.c @@ -12,6 +12,7 @@ #include "core/buf.h" #include "core/heap.h" #include "core/pool.h" +#include "core/slice.h" #include "core/vec.h" #include "link/link.h" #include "link/link_internal.h" @@ -171,8 +172,9 @@ static void rel_record_global(Linker* l, RelGlobal** globals, u32* nglobals, g->def_sym = id; } else if (new_strength == old_strength && new_strength == rel_bind_strength(SB_GLOBAL)) { - size_t namelen; - const char* nm = pool_str(l->c->global, s->name, &namelen); + Slice nm_s = pool_slice(l->c->global, s->name); + const char* nm = nm_s.s; + size_t namelen = nm_s.len; obj_format_demangle_c(l->c, &nm, &namelen); compiler_panic(l->c, no_loc(), "link -r: duplicate definition of global symbol '%.*s'", diff --git a/src/link/link_resolve.c b/src/link/link_resolve.c @@ -15,6 +15,7 @@ #include "core/bytes.h" #include "core/heap.h" #include "core/pool.h" +#include "core/slice.h" #include "core/util.h" #include "core/vec.h" #include "link/link.h" @@ -177,8 +178,9 @@ void link_resolve_symbols(Linker* l, LinkImage* img) { if (s->section_id < m->nsection) m->comdat_discarded[s->section_id] = 1; } else { - size_t namelen; - const char* nm = pool_str(l->c->global, s->name, &namelen); + Slice nm_s = pool_slice(l->c->global, s->name); + const char* nm = nm_s.s; + size_t namelen = nm_s.len; compiler_panic(l->c, no_loc(), "link: duplicate definition of " "global symbol '%.*s'", @@ -248,10 +250,8 @@ void link_resolve_undefs(Linker* l, LinkImage* img) { } } if (l->resolver && s->name != 0) { - size_t namelen; - const char* nm = pool_str(l->c->global, s->name, &namelen); - (void)namelen; - void* p = l->resolver(l->resolver_user, nm); + Slice nm_s = pool_slice(l->c->global, s->name); + void* p = l->resolver(l->resolver_user, nm_s); if (p) { s->kind = SK_ABS; s->vaddr = (u64)(uintptr_t)p; @@ -274,19 +274,20 @@ void link_resolve_undefs(Linker* l, LinkImage* img) { * the mingw CRT — losing the aux TagIndex means we can't tell * which side is the alias declarator. */ if (l->c->target.obj == CFREE_OBJ_COFF && s->name != 0) { - size_t nlen; - const char* nm = pool_str(l->c->global, s->name, &nlen); + Slice nm_s = pool_slice(l->c->global, s->name); + const char* nm = nm_s.s; + size_t nlen = nm_s.len; Sym candidates[2] = {0, 0}; u32 ncand = 0; if (nm && nlen >= 2 && nm[0] == '_') { candidates[ncand++] = - pool_intern(l->c->global, nm + 1, (u32)(nlen - 1u)); + pool_intern_slice(l->c->global, (Slice){ .s = nm + 1, .len = (u32)(nlen - 1u) }); } if (nm && nlen > 0) { char* buf = (char*)arena_array(l->c->scratch, char, nlen + 1u); buf[0] = '_'; memcpy(buf + 1, nm, nlen); - candidates[ncand++] = pool_intern(l->c->global, buf, (u32)(nlen + 1u)); + candidates[ncand++] = pool_intern_slice(l->c->global, (Slice){ .s = buf, .len = (u32)(nlen + 1u) }); } int resolved = 0; for (u32 ci = 0; !resolved && ci < ncand; ++ci) { @@ -338,8 +339,9 @@ void link_resolve_undefs(Linker* l, LinkImage* img) { * (vaddr = 0, SK_ABS) in JIT mode only; AOT lanes keep the strict * "undefined external" semantics. */ if (l->jit_mode && s->name != 0) { - size_t nlen; - const char* nm = pool_str(l->c->global, s->name, &nlen); + Slice nm_s = pool_slice(l->c->global, s->name); + const char* nm = nm_s.s; + size_t nlen = nm_s.len; if (nm && nlen == 15u && memcmp(nm, "__tlv_bootstrap", 15u) == 0) { s->kind = SK_ABS; s->vaddr = 0; @@ -348,9 +350,9 @@ void link_resolve_undefs(Linker* l, LinkImage* img) { } } { - size_t namelen; - const char* nm = s->name ? pool_str(l->c->global, s->name, &namelen) - : (namelen = 0, ""); + Slice nm_s = s->name ? pool_slice(l->c->global, s->name) : SLICE_NULL; + const char* nm = nm_s.s ? nm_s.s : ""; + size_t namelen = nm_s.len; obj_format_demangle_c(l->c, &nm, &namelen); compiler_panic(l->c, no_loc(), "link: undefined reference to '%.*s'", (int)namelen, nm); @@ -558,10 +560,12 @@ void link_gc_compute(Linker* l, LinkImage* img, GcLive* g) { tsym = LinkSyms_at(&img->syms, target - 1); if (tsym->name != 0) { - size_t namelen, off, ilen; - const char* nm = pool_str(l->c->global, tsym->name, &namelen); + size_t off, ilen; + Slice nm_s = pool_slice(l->c->global, tsym->name); + const char* nm = nm_s.s; + size_t namelen = nm_s.len; if (link_gc_split_start_stop(nm, namelen, &off, &ilen, NULL)) { - Sym secname = pool_intern(l->c->global, nm + off, ilen); + Sym secname = pool_intern_slice(l->c->global, (Slice){ .s = nm + off, .len = ilen }); gc_promote_by_section_name(l, g, &q, h, secname); } } @@ -749,28 +753,28 @@ void link_synth_coff_ctor_dtor_list(Linker* l) { if (!l || l->c->target.obj != CFREE_OBJ_COFF) return; ob = obj_new(l->c); if (!ob) return; - sid = obj_section_ex(ob, pool_intern_cstr(l->c->global, ".rdata$ctors"), + sid = obj_section_ex(ob, pool_intern_slice(l->c->global, SLICE_LIT(".rdata$ctors")), SEC_RODATA, SSEM_PROGBITS, SF_ALLOC | SF_RETAIN, 16, 0u, 0u, 0u); obj_section_replace_bytes(ob, sid, kZeros, sizeof(kZeros)); - obj_symbol_ex(ob, pool_intern_cstr(l->c->global, "__CTOR_LIST__"), + obj_symbol_ex(ob, pool_intern_slice(l->c->global, SLICE_LIT("__CTOR_LIST__")), SB_GLOBAL, SV_DEFAULT, SK_OBJ, sid, 0, 0, 0); - obj_symbol_ex(ob, pool_intern_cstr(l->c->global, "__CTOR_END__"), + obj_symbol_ex(ob, pool_intern_slice(l->c->global, SLICE_LIT("__CTOR_END__")), SB_GLOBAL, SV_DEFAULT, SK_OBJ, sid, 0, 0, 0); - obj_symbol_ex(ob, pool_intern_cstr(l->c->global, "__DTOR_LIST__"), + obj_symbol_ex(ob, pool_intern_slice(l->c->global, SLICE_LIT("__DTOR_LIST__")), SB_GLOBAL, SV_DEFAULT, SK_OBJ, sid, 0, 0, 0); - obj_symbol_ex(ob, pool_intern_cstr(l->c->global, "__DTOR_END__"), + obj_symbol_ex(ob, pool_intern_slice(l->c->global, SLICE_LIT("__DTOR_END__")), SB_GLOBAL, SV_DEFAULT, SK_OBJ, sid, 0, 0, 0); /* __chkstk: only the aa64 variant is synthesized here; x64 codegen * already emits inline probes (or links libmingwex's __chkstk * which is a plain object, not an ARM64EC alias). */ if (l->c->target.arch == CFREE_ARCH_ARM_64) { ObjSecId tsid = - obj_section_ex(ob, pool_intern_cstr(l->c->global, ".text$chkstk"), + obj_section_ex(ob, pool_intern_slice(l->c->global, SLICE_LIT(".text$chkstk")), SEC_TEXT, SSEM_PROGBITS, SF_ALLOC | SF_EXEC | SF_RETAIN, 4, 0u, 0u, 0u); obj_section_replace_bytes(ob, tsid, kAa64Chkstk, sizeof(kAa64Chkstk)); - obj_symbol_ex(ob, pool_intern_cstr(l->c->global, "__chkstk"), SB_GLOBAL, + obj_symbol_ex(ob, pool_intern_slice(l->c->global, SLICE_LIT("__chkstk")), SB_GLOBAL, SV_DEFAULT, SK_FUNC, tsid, 0, sizeof(kAa64Chkstk), 0); } obj_finalize(ob); @@ -780,7 +784,7 @@ void link_synth_coff_ctor_dtor_list(Linker* l) { in->kind = LINK_INPUT_OBJ_BYTES; in->order = l->next_input_order++; in->obj = ob; - in->name = pool_intern_cstr(l->c->global, "<cfree-synth-coff-runtime>"); + in->name = pool_intern_slice(l->c->global, SLICE_LIT("<cfree-synth-coff-runtime>")); in->soname = 0; } @@ -804,7 +808,7 @@ void link_ingest_archives(Linker* l) { Sym want_ifunc_init = 0; if (ar->whole_archive) continue; if (l->emit_static_exe && inputs_have_defined_ifunc_before(l, ar->order)) - want_ifunc_init = pool_intern_cstr(l->c->global, "__cfree_ifunc_init"); + want_ifunc_init = pool_intern_slice(l->c->global, SLICE_LIT("__cfree_ifunc_init")); for (;;) { SymHash defined, undefs; int changed = 0; diff --git a/src/link/link_script.c b/src/link/link_script.c @@ -26,7 +26,7 @@ * - An output section's `: ALIGN(N)` header is encoded as the first * entry in its asns[]: a dot-assignment whose expr is ALIGN(., N). * - `*(p1 p2 ...)` produces one CfreeLinkInputMatch per pattern with - * file_pattern = NULL (implicit `*`) and section_pattern set. + * file_pattern = empty slice (implicit `*`) and section_pattern set. * COMMON is parsed as a literal pattern "COMMON". * * Allocation: every node and string is owned by the compiler's tu arena. @@ -48,6 +48,7 @@ #include "core/core.h" #include "core/diag.h" #include "core/heap.h" +#include "core/slice.h" /* The public CfreeLinkScript has no place to carry its backing-arena * pointer, so we allocate a fixed-shape owner block via heap and arena- @@ -111,6 +112,16 @@ static char* lsp_strdup(LSP* p, const char* s, size_t n) { return arena_strdup(p->arena, s, n); } +/* Arena-copy a span of the script text and return a CfreeSlice over the + * copy. The copy is NUL-terminated (arena_strdup), so consumers that hit + * a host boundary can use .s directly. */ +static CfreeSlice lsp_slice(LSP* p, const char* s, size_t n) { + CfreeSlice out; + out.s = lsp_strdup(p, s, n); + out.len = out.s ? n : 0; + return out; +} + static CfreeLinkExpr* lsp_new_expr(LSP* p) { return arena_znew(p->arena, CfreeLinkExpr); } @@ -235,7 +246,7 @@ static int lex_ident(LSP* p, const char** out, size_t* out_len) { /* Match a literal keyword. Caller must have already peeked. */ static int match_kw(LSP* p, const char* kw) { - size_t klen = strlen(kw); + size_t klen = slice_from_cstr(kw).len; size_t save; skip_ws(p); if (p->err) return 0; @@ -377,7 +388,7 @@ static CfreeLinkExpr* parse_atom(LSP* p) { e = lsp_new_expr(p); if (!e) return NULL; e->kind = CFREE_LE_SYM; - e->v.name = lsp_strdup(p, s, n); + e->v.name = lsp_slice(p, s, n); return e; } } @@ -497,7 +508,7 @@ static int push_dot_align(LSP* p, VecAsn* asns, CfreeLinkExpr* align_n) { aln->v.align.val = dot; aln->v.align.align = align_n; a.kind = CFREE_LAS_DOT; - a.sym = NULL; + a.sym = CFREE_SLICE_NULL; a.expr = aln; return VEC_PUSH(p, *asns, a); } @@ -540,8 +551,8 @@ static int parse_input_matchers(LSP* p, VecMatch* out) { return 1; } s = p->src + start; - m.file_pattern = NULL; - m.section_pattern = lsp_strdup(p, s, n); + m.file_pattern = CFREE_SLICE_NULL; + m.section_pattern = lsp_slice(p, s, n); m.keep = 0; if (VEC_PUSH(p, *out, m)) return 1; } @@ -585,7 +596,7 @@ static int parse_section_body(LSP* p, VecMatch* inputs, VecAsn* asns) { if (!match_ch(p, ';')) { /* ; is optional but encouraged */ } a.kind = CFREE_LAS_DOT; - a.sym = NULL; + a.sym = CFREE_SLICE_NULL; a.expr = e; if (VEC_PUSH(p, *asns, a)) return 1; } @@ -612,7 +623,7 @@ static int parse_section_body(LSP* p, VecMatch* inputs, VecAsn* asns) { if (!e) return 1; (void)match_ch(p, ';'); a.kind = CFREE_LAS_SYM; - a.sym = lsp_strdup(p, s, n); + a.sym = lsp_slice(p, s, n); a.expr = e; if (VEC_PUSH(p, *asns, a)) return 1; continue; @@ -679,7 +690,7 @@ static int parse_output_section(LSP* p, const char* name_buf, size_t name_len, memcpy(arr_as, asns.p, sizeof(*arr_as) * asns.n); } memset(&sec, 0, sizeof(sec)); - sec.name = lsp_strdup(p, name_buf, name_len); + sec.name = lsp_slice(p, name_buf, name_len); sec.inputs = arr_in; sec.ninputs = inputs.n; sec.asns = arr_as; @@ -749,7 +760,7 @@ static int parse_sections_block(LSP* p, VecAsn* top_asns, VecSec* sections) { if (!e) return 1; (void)match_ch(p, ';'); a.kind = CFREE_LAS_DOT; - a.sym = NULL; + a.sym = CFREE_SLICE_NULL; a.expr = e; if (VEC_PUSH(p, *top_asns, a)) return 1; } @@ -781,7 +792,7 @@ static int parse_sections_block(LSP* p, VecAsn* top_asns, VecSec* sections) { if (!e) return 1; (void)match_ch(p, ';'); a.kind = CFREE_LAS_SYM; - a.sym = lsp_strdup(p, s, n); + a.sym = lsp_slice(p, s, n); a.expr = e; if (VEC_PUSH(p, *top_asns, a)) return 1; continue; @@ -802,7 +813,7 @@ static int parse_sections_block(LSP* p, VecAsn* top_asns, VecSec* sections) { static int parse_top(LSP* p, CfreeLinkScript* out) { VecAsn top_asns = {0}; VecSec sections = {0}; - const char* entry_name = NULL; + CfreeSlice entry_name = CFREE_SLICE_NULL; int saw_sections = 0; int rc = 1; @@ -821,8 +832,8 @@ static int parse_top(LSP* p, CfreeLinkScript* out) { if (lex_ident(p, &s, &n)) goto done; if (expect_ch(p, ')')) goto done; (void)match_ch(p, ';'); - entry_name = lsp_strdup(p, s, n); - if (!entry_name) goto done; + entry_name = lsp_slice(p, s, n); + if (!entry_name.s) goto done; continue; } if (match_kw(p, "SECTIONS")) { @@ -886,8 +897,8 @@ done: /* ---- public API ---- */ -CfreeStatus cfree_link_script_parse(const CfreeContext* ctx, const char* text, - size_t len, CfreeLinkScript** out) { +CfreeStatus cfree_link_script_parse(const CfreeContext* ctx, CfreeSlice text, + CfreeLinkScript** out) { ScriptOwner* owner; LSP p; int rc; @@ -895,7 +906,7 @@ CfreeStatus cfree_link_script_parse(const CfreeContext* ctx, const char* text, if (!out) return CFREE_INVALID; *out = NULL; - if (!ctx || !ctx->heap || !text) return CFREE_INVALID; + if (!ctx || !ctx->heap || !text.s) return CFREE_INVALID; h = ctx->heap; owner = (ScriptOwner*)h->alloc(h, sizeof(*owner), _Alignof(ScriptOwner)); @@ -909,8 +920,8 @@ CfreeStatus cfree_link_script_parse(const CfreeContext* ctx, const char* text, p.arena = &owner->arena; p.heap = h; p.diag = ctx->diag; - p.src = text; - p.len = len; + p.src = text.s; + p.len = text.len; rc = parse_top(&p, &owner->script); if (rc != 0 || p.err) { diff --git a/src/obj/coff_emit.c b/src/obj/coff_emit.c @@ -40,6 +40,7 @@ #include "core/buf.h" #include "core/heap.h" #include "core/pool.h" +#include "core/slice.h" #include "core/util.h" #include "obj/coff.h" @@ -240,13 +241,13 @@ static void wr_aux_weak(u8* dst, u32 TagIndex, u32 Characteristics) { /* Look up the pool-interned string for a Sym. */ static const char* sym_to_str(Compiler* c, Sym n, u32* len_out) { - size_t len; - const char* s = pool_str(c->global, n, &len); + Slice sl = pool_slice(c->global, n); + const char* s = sl.s; if (!s) { *len_out = 0; return ""; } - *len_out = (u32)len; + *len_out = (u32)sl.len; return s; } diff --git a/src/obj/coff_read.c b/src/obj/coff_read.c @@ -20,6 +20,7 @@ #include "core/arena.h" #include "core/heap.h" #include "core/pool.h" +#include "core/slice.h" #include "obj/coff.h" static SrcLoc no_loc(void) { @@ -205,10 +206,11 @@ static ObjBuilder* read_coff_short_import(Compiler* c, const char* name, if (name_type == IMPORT_OBJECT_ORDINAL) compiler_panic(c, no_loc(), "read_coff: short-import by ordinal not implemented " - "(archive member \"%s\", ordinal %u). cfree links " + "(archive member \"%.*s\", ordinal %u). cfree links " "imports by name only; rebuild the consumer to import " "by name, or omit this archive from the link.", - name ? name : "<unnamed>", + SLICE_ARG(name ? slice_from_cstr(name) + : SLICE_LIT("<unnamed>")), (unsigned)ordinal_or_hint); /* Symbol name: NUL-terminated starting at data + 20. */ @@ -243,7 +245,8 @@ static ObjBuilder* read_coff_short_import(Compiler* c, const char* name, * shape read_coff_dso would produce for a DLL export. */ SymKind k = (import_type == IMPORT_OBJECT_CODE) ? SK_FUNC : SK_OBJ; - Sym sn = pool_intern(c->global, (const char*)body, sym_name_len); + Sym sn = pool_intern_slice( + c->global, (Slice){ .s = (const char*)body, .len = sym_name_len }); ObjSymId id = obj_symbol_ex(ob, sn, SB_GLOBAL, SV_DEFAULT, k, OBJ_SEC_NONE, 0, 0, 0); obj_sym_mark_referenced(ob, id); @@ -257,14 +260,16 @@ static ObjBuilder* read_coff_short_import(Compiler* c, const char* name, char* imp_buf = arena_array(c->scratch, char, imp_len); memcpy(imp_buf, kImpPrefix, sizeof kImpPrefix - 1u); memcpy(imp_buf + (sizeof kImpPrefix - 1u), body, sym_name_len); - Sym imp_sn = pool_intern(c->global, imp_buf, imp_len); + Sym imp_sn = + pool_intern_slice(c->global, (Slice){ .s = imp_buf, .len = imp_len }); ObjSymId imp_id = obj_symbol_ex(ob, imp_sn, SB_GLOBAL, SV_DEFAULT, SK_OBJ, OBJ_SEC_NONE, 0, 0, 0); obj_sym_mark_referenced(ob, imp_id); /* Stash the DLL name so the archive-ingestion layer (Phase 4.3) can * route this builder as a DSO with the DLL as soname. */ - Sym dll_sn = pool_intern(c->global, (const char*)dll_p, dll_name_len); + Sym dll_sn = pool_intern_slice( + c->global, (Slice){ .s = (const char*)dll_p, .len = dll_name_len }); obj_set_coff_import_dll(ob, dll_sn); (void)name_type; @@ -361,7 +366,7 @@ ObjBuilder* read_coff(Compiler* c, const char* name, const u8* data, const char* nm; u32 nlen; resolve_section_name(s->raw_name, strtab, strtab_size, &nm, &nlen); - Sym sn = pool_intern(c->global, nm, nlen); + Sym sn = pool_intern_slice(c->global, (Slice){ .s = nm, .len = nlen }); u16 kind = coff_sec_kind(nm, nlen, s->characteristics); u16 flags = coff_sec_flags(nm, nlen, s->characteristics); @@ -448,7 +453,9 @@ ObjBuilder* read_coff(Compiler* c, const char* name, const u8* data, fnm = (const char*)aux; fnlen = n; } - Sym fsn = fnlen ? pool_intern(c->global, fnm, fnlen) : 0; + Sym fsn = fnlen ? pool_intern_slice( + c->global, (Slice){ .s = fnm, .len = fnlen }) + : 0; ObjSymId id = obj_symbol_ex(ob, fsn, SB_LOCAL, SV_DEFAULT, SK_FILE, OBJ_SEC_NONE, 0, 0, 0); obj_sym_mark_referenced(ob, id); @@ -561,7 +568,8 @@ ObjBuilder* read_coff(Compiler* c, const char* name, const u8* data, * resolution by name and we drop the explicit index. */ if (sclass == IMAGE_SYM_CLASS_WEAK_EXTERNAL) bind = SB_WEAK; - Sym sn = nlen ? pool_intern(c->global, nm, nlen) : 0; + Sym sn = nlen ? pool_intern_slice(c->global, (Slice){ .s = nm, .len = nlen }) + : 0; ObjSymId id = obj_symbol_ex(ob, sn, bind, vis, kind, target_sec, sym_value, sym_size, cmnalign); obj_sym_mark_referenced(ob, id); diff --git a/src/obj/coff_read_dso.c b/src/obj/coff_read_dso.c @@ -24,6 +24,7 @@ #include "core/arena.h" #include "core/heap.h" #include "core/pool.h" +#include "core/slice.h" #include "obj/coff.h" static SrcLoc no_loc(void) { @@ -180,7 +181,7 @@ ObjBuilder* read_coff_dso(Compiler* c, const char* name, const u8* data, const char* dll_name; u32 nlen = read_cstr(data, len, name_off, &dll_name); if (nlen && soname_out) - *soname_out = pool_intern(c->global, dll_name, nlen); + *soname_out = pool_intern_slice(c->global, (Slice){ .s = dll_name, .len = nlen }); } /* ---- resolve EAT / ENT / ordinal table once ---- */ @@ -224,7 +225,7 @@ ObjBuilder* read_coff_dso(Compiler* c, const char* name, const u8* data, u32 nlen = read_cstr(data, len, name_off, &nm); if (!nlen) continue; - Sym sn = pool_intern(c->global, nm, nlen); + Sym sn = pool_intern_slice(c->global, (Slice){ .s = nm, .len = nlen }); ObjSymId id = obj_symbol(ob, sn, SB_GLOBAL, SK_FUNC, OBJ_SEC_NONE, 0, 0); obj_sym_mark_referenced(ob, id); diff --git a/src/obj/elf_emit.c b/src/obj/elf_emit.c @@ -32,6 +32,7 @@ #include "core/buf.h" #include "core/heap.h" #include "core/pool.h" +#include "core/slice.h" #include "core/util.h" #include "obj/elf.h" @@ -187,13 +188,13 @@ static u16 sym_shndx(const ObjSym* s, const u32* obj_to_elf, u32 nsec) { } static const char* sym_to_str(Compiler* c, Sym n, u32* len_out) { - size_t len; - const char* s = pool_str(c->global, n, &len); + Slice sl = pool_slice(c->global, n); + const char* s = sl.s; if (!s) { *len_out = 0; return ""; } - *len_out = (u32)len; + *len_out = (u32)sl.len; return s; } diff --git a/src/obj/elf_read.c b/src/obj/elf_read.c @@ -13,6 +13,7 @@ #include "arch/arch.h" #include "core/heap.h" #include "core/pool.h" +#include "core/slice.h" #include "obj/elf.h" static SrcLoc no_loc(void) { @@ -181,7 +182,7 @@ static u8 elf_other_to_vis(u32 other) { /* Bounds-checked C-string slice from a strtab section. Returns "" on * out-of-range so callers don't have to special-case it. `len_out` is - * set to strlen(result). */ + * set to the result's byte length. */ static const char* strtab_lookup(const u8* tab, u64 tab_size, u32 off, u32* len_out) { if (off >= tab_size) { @@ -286,7 +287,7 @@ ObjBuilder* read_elf(Compiler* c, const char* name, const u8* data, u32 nlen; const char* nm = strtab_lookup(shstrtab, shstrtab_sz, sh->sh_name, &nlen); - Sym sym = pool_intern(c->global, nm, nlen); + Sym sym = pool_intern_slice(c->global, (Slice){ .s = nm, .len = nlen }); u16 sec_kind = elf_kind_from_name(nm, nlen, sh->sh_flags, sh->sh_type); int type_known; @@ -298,8 +299,8 @@ ObjBuilder* read_elf(Compiler* c, const char* name, const u8* data, obj_section_ex(ob, sym, (SecKind)sec_kind, (SecSem)sec_sem, flags, align, (u32)sh->sh_entsize, sh->sh_link, sh->sh_info); if (id == OBJ_SEC_NONE) - compiler_panic(c, no_loc(), "read_elf: obj_section_ex failed for '%s'", - nm); + compiler_panic(c, no_loc(), "read_elf: obj_section_ex failed for '%.*s'", + SLICE_ARG(((Slice){.s = nm, .len = nlen}))); elf_to_obj[i] = id; /* Preserve format-specific bits the canonical SecSem/SecFlag @@ -317,8 +318,9 @@ ObjBuilder* read_elf(Compiler* c, const char* name, const u8* data, obj_reserve_bss(ob, id, (u32)sh->sh_size, align); } else if (sh->sh_size) { if (sh->sh_offset + sh->sh_size > len) - compiler_panic(c, no_loc(), "read_elf: section '%s' bytes out of range", - nm); + compiler_panic(c, no_loc(), + "read_elf: section '%.*s' bytes out of range", + SLICE_ARG(((Slice){.s = nm, .len = nlen}))); /* For SYMTAB/STRTAB/RELA we still copy the raw bytes — the * post-finalize shape contract says these sections are * present; emit_elf will regenerate them on re-emit, so the @@ -375,7 +377,7 @@ ObjBuilder* read_elf(Compiler* c, const char* name, const u8* data, u32 nlen; const char* nm = strtab_lookup(strtab, strtab_sz, st_name, &nlen); - Sym sn = nlen ? pool_intern(c->global, nm, nlen) : 0; + Sym sn = nlen ? pool_intern_slice(c->global, (Slice){ .s = nm, .len = nlen }) : 0; u32 e_bind = ELF64_ST_BIND(st_info); u32 e_type = ELF64_ST_TYPE(st_info); @@ -468,7 +470,7 @@ ObjBuilder* read_elf(Compiler* c, const char* name, const u8* data, u32 nm_len; const char* gnm = strtab_lookup(shstrtab, shstrtab_sz, sh->sh_name, &nm_len); - Sym gname = pool_intern(c->global, gnm, nm_len); + Sym gname = pool_intern_slice(c->global, (Slice){ .s = gnm, .len = nm_len }); ObjSymId signature = OBJ_SYM_NONE; if (sym_elf_to_obj && sh->sh_info < nsyms) @@ -607,7 +609,7 @@ ObjBuilder* read_elf_dso(Compiler* c, const char* name, const u8* data, if (tag == DT_SONAME) { u32 nlen; const char* nm = strtab_lookup(dynstr, dynstr_sz, (u32)val, &nlen); - if (nlen) soname = pool_intern(c->global, nm, nlen); + if (nlen) soname = pool_intern_slice(c->global, (Slice){ .s = nm, .len = nlen }); break; } } @@ -660,7 +662,7 @@ ObjBuilder* read_elf_dso(Compiler* c, const char* name, const u8* data, u32 nlen; const char* nm = strtab_lookup(strtab, strtab_sz, st_name, &nlen); if (!nlen) continue; - Sym sn = pool_intern(c->global, nm, nlen); + Sym sn = pool_intern_slice(c->global, (Slice){ .s = nm, .len = nlen }); u32 e_type_field = ELF64_ST_TYPE(st_info); u16 bind = elf_bind_to_obj(e_bind); diff --git a/src/obj/macho_emit.c b/src/obj/macho_emit.c @@ -31,6 +31,7 @@ #include "core/bytes.h" #include "core/heap.h" #include "core/pool.h" +#include "core/slice.h" #include "core/util.h" #include "obj/macho.h" @@ -122,7 +123,8 @@ static void name_to_seg_sect(const char* name, u32 nlen, u16 sec_kind, /* Strip a leading `.` from the input name (".debug_info" → * "__debug_info") so the dwarf section names round-trip. */ sect = (nlen && name[0] == '.') ? name + 1 : name; - copy_fixed16(out->segname, &out->seg_len, seg, (u32)strlen(seg)); + copy_fixed16(out->segname, &out->seg_len, seg, + (u32)slice_from_cstr(seg).len); copy_fixed16(out->sectname, &out->sect_len, sect, (u32)((nlen && name[0] == '.') ? nlen - 1 : nlen)); return; @@ -131,8 +133,9 @@ static void name_to_seg_sect(const char* name, u32 nlen, u16 sec_kind, sect = "__data"; break; } - copy_fixed16(out->segname, &out->seg_len, seg, (u32)strlen(seg)); - copy_fixed16(out->sectname, &out->sect_len, sect, (u32)strlen(sect)); + copy_fixed16(out->segname, &out->seg_len, seg, (u32)slice_from_cstr(seg).len); + copy_fixed16(out->sectname, &out->sect_len, sect, + (u32)slice_from_cstr(sect).len); } /* ---- per-section plan ---- */ @@ -265,8 +268,9 @@ void emit_macho(Compiler* c, ObjBuilder* ob, Writer* w) { s->sem == SSEM_GROUP) { continue; } - size_t nlen; - const char* nm = pool_str(c->global, s->name, &nlen); + Slice nm_s = pool_slice(c->global, s->name); + const char* nm = nm_s.s; + size_t nlen = nm_s.len; MSec* m = &secs[nsecs]; name_to_seg_sect(nm ? nm : "", (u32)nlen, s->kind, &m->ns); m->obj_sec = i; @@ -369,8 +373,9 @@ void emit_macho(Compiler* c, ObjBuilder* ob, Writer* w) { MSym* ms = &msyms[nmsyms]; ms->obj_id = e.id; - size_t nlen; - const char* nm = pool_str(c->global, s->name, &nlen); + Slice nm_s = pool_slice(c->global, s->name); + const char* nm = nm_s.s; + size_t nlen = nm_s.len; /* Mach-O symbol names are stored on disk verbatim — including * the leading `_` Apple toolchains use for C-source-level * symbols ("_main" for `int main()`). cfree treats the prefix diff --git a/src/obj/macho_read.c b/src/obj/macho_read.c @@ -16,6 +16,7 @@ #include "core/bytes.h" #include "core/heap.h" #include "core/pool.h" +#include "core/slice.h" #include "core/util.h" #include "obj/macho.h" @@ -194,7 +195,7 @@ ObjBuilder* read_macho(Compiler* c, const char* name, const u8* data, nmbuf[nlen++] = ','; memcpy(nmbuf + nlen, m->sectname, m->sect_len); nlen += m->sect_len; - Sym sn = pool_intern(c->global, nmbuf, nlen); + Sym sn = pool_intern_slice(c->global, (Slice){ .s = nmbuf, .len = nlen }); u16 kind = sec_kind_from_seg_sect(m->segname, m->seg_len, m->sectname, m->sect_len, m->flags); @@ -249,7 +250,7 @@ ObjBuilder* read_macho(Compiler* c, const char* name, const u8* data, * `test_main` ↔ `_test_main` mapping for API callers) happens * one layer up at the linker API boundary (link_c_name_intern * in link.c); the on-disk shape stays byte-for-byte stable. */ - Sym sn = nlen ? pool_intern(c->global, nm, nlen) : 0; + Sym sn = nlen ? pool_intern_slice(c->global, (Slice){ .s = nm, .len = nlen }) : 0; u8 type_field = (u8)(n_type & N_TYPE); u8 ext = (u8)(n_type & N_EXT); @@ -473,7 +474,7 @@ ObjBuilder* read_macho(Compiler* c, const char* name, const u8* data, } while (v); for (u32 k = 0; k < dn; ++k) nmbuf[nlen + k] = dec[dn - 1 - k]; nlen += dn; - Sym sn = pool_intern(c->global, nmbuf, nlen); + Sym sn = pool_intern_slice(c->global, (Slice){ .s = nmbuf, .len = nlen }); u16 sk = (tm->flags & S_ATTR_PURE_INSTRUCTIONS) ? SK_FUNC : SK_OBJ; sec_start_sym[sec_idx] = obj_symbol(ob, sn, SB_LOCAL, (SymKind)sk, tm->obj_sec, 0, 0); @@ -573,7 +574,7 @@ ObjBuilder* read_macho_dso(Compiler* c, const char* name, const u8* data, u32 maxlen = cmdsize - nm_off; u32 nlen = 0; while (nlen < maxlen && p[nlen]) ++nlen; - if (nlen) install_name = pool_intern(c->global, p, nlen); + if (nlen) install_name = pool_intern_slice(c->global, (Slice){ .s = p, .len = nlen }); } else if (cmd == LC_SYMTAB) { symoff = rd_u32_le(data + pos + 8); nsyms = rd_u32_le(data + pos + 12); @@ -614,7 +615,7 @@ ObjBuilder* read_macho_dso(Compiler* c, const char* name, const u8* data, u32 nlen = 0; while (strx + nlen < strsize && nm[nlen]) ++nlen; if (!nlen) continue; - Sym sn = pool_intern(c->global, nm, nlen); + Sym sn = pool_intern_slice(c->global, (Slice){ .s = nm, .len = nlen }); SymBind bind = (n_desc & (N_WEAK_DEF | N_WEAK_REF)) ? SB_WEAK : SB_GLOBAL; SymKind kind = SK_NOTYPE; diff --git a/src/obj/obj_secnames.c b/src/obj/obj_secnames.c @@ -24,26 +24,27 @@ #include "core/core.h" #include "core/heap.h" #include "core/pool.h" +#include "core/slice.h" static Sym secname_panic_unimpl(Compiler* c, const char* which) { SrcLoc l = {0, 0, 0}; compiler_panic(c, l, - "obj section name '%s' for target obj=%u not yet " + "obj section name '%.*s' for target obj=%u not yet " "implemented", - which, (unsigned)c->target.obj); + SLICE_ARG(slice_from_cstr(which)), (unsigned)c->target.obj); return 0; } Sym obj_secname_init_array(Compiler* c) { switch (c->target.obj) { case CFREE_OBJ_ELF: - return pool_intern_cstr(c->global, ".init_array"); + return pool_intern_slice(c->global, SLICE_LIT(".init_array")); case CFREE_OBJ_MACHO: - return pool_intern_cstr(c->global, "__DATA,__mod_init_func"); + return pool_intern_slice(c->global, SLICE_LIT("__DATA,__mod_init_func")); case CFREE_OBJ_COFF: /* CRT runtime scans `.CRT$X[A-Z]` for ctor/dtor tables; XCU is * the user-constructor bucket. See doc/WINDOWS.md §1.6. */ - return pool_intern_cstr(c->global, ".CRT$XCU"); + return pool_intern_slice(c->global, SLICE_LIT(".CRT$XCU")); default: return secname_panic_unimpl(c, ".init_array"); } @@ -52,13 +53,13 @@ Sym obj_secname_init_array(Compiler* c) { Sym obj_secname_fini_array(Compiler* c) { switch (c->target.obj) { case CFREE_OBJ_ELF: - return pool_intern_cstr(c->global, ".fini_array"); + return pool_intern_slice(c->global, SLICE_LIT(".fini_array")); case CFREE_OBJ_MACHO: - return pool_intern_cstr(c->global, "__DATA,__mod_term_func"); + return pool_intern_slice(c->global, SLICE_LIT("__DATA,__mod_term_func")); case CFREE_OBJ_COFF: /* `.CRT$XPA`/`XPZ` are markers; XPU is the user-destructor * bucket. See doc/WINDOWS.md §1.6. */ - return pool_intern_cstr(c->global, ".CRT$XPU"); + return pool_intern_slice(c->global, SLICE_LIT(".CRT$XPU")); default: return secname_panic_unimpl(c, ".fini_array"); } @@ -67,7 +68,7 @@ Sym obj_secname_fini_array(Compiler* c) { Sym obj_secname_preinit_array(Compiler* c) { switch (c->target.obj) { case CFREE_OBJ_ELF: - return pool_intern_cstr(c->global, ".preinit_array"); + return pool_intern_slice(c->global, SLICE_LIT(".preinit_array")); case CFREE_OBJ_MACHO: /* Mach-O has no direct `.preinit_array` analogue — dyld runs * S_MOD_INIT_FUNC_POINTERS only. Phase 3 of the linker will @@ -78,7 +79,7 @@ Sym obj_secname_preinit_array(Compiler* c) { case CFREE_OBJ_COFF: /* CRT's own setup runs in `.CRT$XI*`; user pre-init lives at * XIA just after the CRT. See doc/WINDOWS.md §1.6. */ - return pool_intern_cstr(c->global, ".CRT$XIA"); + return pool_intern_slice(c->global, SLICE_LIT(".CRT$XIA")); default: return secname_panic_unimpl(c, ".preinit_array"); } @@ -87,13 +88,13 @@ Sym obj_secname_preinit_array(Compiler* c) { Sym obj_secname_tdata(Compiler* c) { switch (c->target.obj) { case CFREE_OBJ_ELF: - return pool_intern_cstr(c->global, ".tdata"); + return pool_intern_slice(c->global, SLICE_LIT(".tdata")); case CFREE_OBJ_MACHO: - return pool_intern_cstr(c->global, "__DATA,__thread_data"); + return pool_intern_slice(c->global, SLICE_LIT("__DATA,__thread_data")); case CFREE_OBJ_COFF: /* MSVC `.tls$` convention; linker concatenates `.tls$*` sorted * by suffix. See doc/WINDOWS.md §1.6. */ - return pool_intern_cstr(c->global, ".tls$"); + return pool_intern_slice(c->global, SLICE_LIT(".tls$")); default: return secname_panic_unimpl(c, ".tdata"); } @@ -102,13 +103,13 @@ Sym obj_secname_tdata(Compiler* c) { Sym obj_secname_tbss(Compiler* c) { switch (c->target.obj) { case CFREE_OBJ_ELF: - return pool_intern_cstr(c->global, ".tbss"); + return pool_intern_slice(c->global, SLICE_LIT(".tbss")); case CFREE_OBJ_MACHO: - return pool_intern_cstr(c->global, "__DATA,__thread_bss"); + return pool_intern_slice(c->global, SLICE_LIT("__DATA,__thread_bss")); case CFREE_OBJ_COFF: /* sorted-alphabetically-last so it falls at the tail of the TLS * image's zero-fill region. See doc/WINDOWS.md §1.6. */ - return pool_intern_cstr(c->global, ".tls$ZZZ"); + return pool_intern_slice(c->global, SLICE_LIT(".tls$ZZZ")); default: return secname_panic_unimpl(c, ".tbss"); } @@ -155,16 +156,17 @@ Sym obj_format_c_mangle(Compiler* c, const char* name) { SrcLoc loc = {0, 0, 0}; if (!c || !name) return 0; if (c->target.obj != CFREE_OBJ_MACHO) - return pool_intern_cstr(c->global, name); - n = strlen(name); + return pool_intern_slice(c->global, slice_from_cstr(name)); + n = slice_from_cstr(name).len; h = (Heap*)c->ctx->heap; buf = (char*)h->alloc(h, n + 2u, 1); if (!buf) - compiler_panic(c, loc, "obj_format_c_mangle: oom prefixing '%s'", name); + compiler_panic(c, loc, "obj_format_c_mangle: oom prefixing '%.*s'", + SLICE_ARG(slice_from_cstr(name))); buf[0] = '_'; memcpy(buf + 1, name, n); buf[n + 1] = 0; - s = pool_intern(c->global, buf, (u32)(n + 1u)); + s = pool_intern_slice(c->global, (Slice){ .s = buf, .len = (u32)(n + 1u) }); h->free(h, buf, n + 2u); return s; } diff --git a/src/obj/obj_tls.c b/src/obj/obj_tls.c @@ -35,6 +35,7 @@ #include "core/core.h" #include "core/heap.h" #include "core/pool.h" +#include "core/slice.h" /* ObjBuilder is opaque outside obj.c; obj_tls.c reaches the bootstrap * cache via these accessors defined in obj.c. Declared here to avoid @@ -80,15 +81,16 @@ static ObjSymId tlv_bootstrap(ObjBuilder* ob, Compiler* c) { if (s != OBJ_SYM_NONE) return s; /* On-disk name carries the Mach-O leading underscore: source-level * `_tlv_bootstrap` becomes `__tlv_bootstrap`. */ - Sym name = pool_intern_cstr(c->global, "__tlv_bootstrap"); + Sym name = pool_intern_slice(c->global, SLICE_LIT("__tlv_bootstrap")); s = obj_symbol(ob, name, SB_GLOBAL, SK_UNDEF, OBJ_SEC_NONE, 0, 0); obj_tlv_bootstrap_set(ob, s); return s; } static ObjSymId mint_init_sym(ObjBuilder* ob, Compiler* c, Sym desc_name) { - size_t nlen = 0; - const char* nm = pool_str(c->global, desc_name, &nlen); + Slice nm_s = pool_slice(c->global, desc_name); + const char* nm = nm_s.s; + size_t nlen = nm_s.len; static const char suffix[] = "$tlv$init"; size_t slen = sizeof(suffix) - 1u; Heap* h = (Heap*)c->ctx->heap; @@ -98,7 +100,7 @@ static ObjSymId mint_init_sym(ObjBuilder* ob, Compiler* c, Sym desc_name) { if (nlen) memcpy(buf, nm, nlen); memcpy(buf + nlen, suffix, slen); buf[nlen + slen] = 0; - Sym n = pool_intern(c->global, buf, (u32)(nlen + slen)); + Sym n = pool_intern_slice(c->global, (Slice){ .s = buf, .len = (u32)(nlen + slen) }); h->free(h, buf, nlen + slen + 1u); return obj_symbol(ob, n, SB_LOCAL, SK_TLS, OBJ_SEC_NONE, 0, 0); } @@ -143,7 +145,7 @@ static void define_tls_macho(ObjBuilder* ob, Compiler* c, ObjSymId sym, /* Descriptor in __DATA,__thread_vars: 24 bytes aligned 8. * The user-visible `sym` lives here; the TLVP relocs in code target * this symbol so the linker can route them through __thread_ptrs. */ - Sym vars_name = pool_intern_cstr(c->global, "__DATA,__thread_vars"); + Sym vars_name = pool_intern_slice(c->global, SLICE_LIT("__DATA,__thread_vars")); ObjSecId vars_sec = obj_section(ob, vars_name, SEC_DATA, SF_ALLOC | SF_WRITE | SF_TLS, 8u); u32 desc_base = obj_align_to(ob, vars_sec, 8u); diff --git a/src/obj/tbd_read.c b/src/obj/tbd_read.c @@ -41,6 +41,7 @@ #include "core/heap.h" #include "core/pool.h" +#include "core/slice.h" #include "obj/obj.h" static SrcLoc no_loc(void) { @@ -84,8 +85,7 @@ static Sym extract_install_name(Compiler* c, const u8* data, size_t len) { --end; } if (end > start) - return pool_intern(c->global, (const char*)(data + start), - (u32)(end - start)); + return pool_intern_slice(c->global, (Slice){ .s = (const char*)(data + start), .len = (u32)(end - start) }); return 0; } return 0; @@ -140,7 +140,7 @@ ObjBuilder* read_tbd(Compiler* c, const char* name, const u8* data, size_t len, * keep tokens of length >= 2. Single `_` is the throwaway-name * convention and never an exported symbol. */ if (tlen < 2u) continue; - Sym sn = pool_intern(c->global, (const char*)(data + start), (u32)tlen); + Sym sn = pool_intern_slice(c->global, (Slice){ .s = (const char*)(data + start), .len = (u32)tlen }); obj_symbol_ex(ob, sn, SB_GLOBAL, SV_DEFAULT, SK_NOTYPE, OBJ_SEC_NONE, 0, 0, 0); } diff --git a/src/opt/ir_print.c b/src/opt/ir_print.c @@ -1,10 +1,25 @@ -#include <stdio.h> -#include <string.h> - +#include "core/slice.h" +#include "core/strbuf.h" #include "opt/opt.h" static void dump_write(Writer* w, const char* s) { - cfree_writer_write(w, s, strlen(s)); + cfree_writer_write(w, s, slice_from_cstr(s).len); +} + +static void dump_sb(Writer* w, const StrBuf* sb) { + cfree_writer_write(w, strbuf_cstr(sb), strbuf_len(sb)); +} + +/* Append a signed value with an explicit leading sign, matching printf's + * "%+lld"/"%+d" formatting (forced '+' on non-negative values). */ +static void strbuf_put_i64_plus(StrBuf* sb, i64 v) { + if (v < 0) { + strbuf_putc(sb, '-'); + strbuf_put_u64(sb, (u64)(-(v + 1)) + 1u); + } else { + strbuf_putc(sb, '+'); + strbuf_put_u64(sb, (u64)v); + } } static const char* op_name(IROp op) { @@ -125,23 +140,29 @@ static const char* alias_name(u8 kind) { static void dump_alias(Writer* w, const AliasRoot* a) { char buf[64]; + StrBuf sb; dump_write(w, alias_name(a->kind)); + strbuf_init(&sb, buf, sizeof buf); switch ((AliasKind)a->kind) { case ALIAS_LOCAL: - snprintf(buf, sizeof buf, "#%d", (int)a->v.local_id); - dump_write(w, buf); + strbuf_putc(&sb, '#'); + strbuf_put_i64(&sb, (i64)(int)a->v.local_id); + dump_sb(w, &sb); break; case ALIAS_GLOBAL: - snprintf(buf, sizeof buf, "#%u", (unsigned)a->v.global); - dump_write(w, buf); + strbuf_putc(&sb, '#'); + strbuf_put_u64(&sb, (u64)(unsigned)a->v.global); + dump_sb(w, &sb); break; case ALIAS_PARAM: - snprintf(buf, sizeof buf, "#%u", (unsigned)a->v.param_idx); - dump_write(w, buf); + strbuf_putc(&sb, '#'); + strbuf_put_u64(&sb, (u64)(unsigned)a->v.param_idx); + dump_sb(w, &sb); break; case ALIAS_STRING: - snprintf(buf, sizeof buf, "#%u", (unsigned)a->v.string_id); - dump_write(w, buf); + strbuf_putc(&sb, '#'); + strbuf_put_u64(&sb, (u64)(unsigned)a->v.string_id); + dump_sb(w, &sb); break; default: break; @@ -150,32 +171,41 @@ static void dump_alias(Writer* w, const AliasRoot* a) { static void dump_operand(Writer* w, const Operand* op) { char buf[96]; + StrBuf sb; if (!op) { dump_write(w, "-"); return; } + strbuf_init(&sb, buf, sizeof buf); switch ((OpKind)op->kind) { case OPK_IMM: - snprintf(buf, sizeof buf, "imm:%lld", (long long)op->v.imm); - dump_write(w, buf); + strbuf_puts(&sb, "imm:"); + strbuf_put_i64(&sb, (i64)op->v.imm); + dump_sb(w, &sb); break; case OPK_REG: - snprintf(buf, sizeof buf, "v%u", (unsigned)op->v.reg); - dump_write(w, buf); + strbuf_putc(&sb, 'v'); + strbuf_put_u64(&sb, (u64)(unsigned)op->v.reg); + dump_sb(w, &sb); break; case OPK_LOCAL: - snprintf(buf, sizeof buf, "local#%u", (unsigned)op->v.frame_slot); - dump_write(w, buf); + strbuf_puts(&sb, "local#"); + strbuf_put_u64(&sb, (u64)(unsigned)op->v.frame_slot); + dump_sb(w, &sb); break; case OPK_GLOBAL: - snprintf(buf, sizeof buf, "global#%u%+lld", (unsigned)op->v.global.sym, - (long long)op->v.global.addend); - dump_write(w, buf); + strbuf_puts(&sb, "global#"); + strbuf_put_u64(&sb, (u64)(unsigned)op->v.global.sym); + strbuf_put_i64_plus(&sb, (i64)op->v.global.addend); + dump_sb(w, &sb); break; case OPK_INDIRECT: - snprintf(buf, sizeof buf, "[v%u%+d]", (unsigned)op->v.ind.base, - (int)op->v.ind.ofs); - dump_write(w, buf); + strbuf_putc(&sb, '['); + strbuf_putc(&sb, 'v'); + strbuf_put_u64(&sb, (u64)(unsigned)op->v.ind.base); + strbuf_put_i64_plus(&sb, (i64)(int)op->v.ind.ofs); + strbuf_putc(&sb, ']'); + dump_sb(w, &sb); break; default: dump_write(w, "op?"); @@ -194,24 +224,37 @@ static void dump_operands(Writer* w, const Inst* in) { static void dump_mem(Writer* w, const MemAccess* m) { char buf[128]; - snprintf(buf, sizeof buf, - " mem=size%u align%u flags=0x%x alias=", (unsigned)m->size, - (unsigned)m->align, (unsigned)m->flags); - dump_write(w, buf); + StrBuf sb; + strbuf_init(&sb, buf, sizeof buf); + strbuf_puts(&sb, " mem=size"); + strbuf_put_u64(&sb, (u64)(unsigned)m->size); + strbuf_puts(&sb, " align"); + strbuf_put_u64(&sb, (u64)(unsigned)m->align); + strbuf_puts(&sb, " flags="); + strbuf_put_hex_u64(&sb, (u64)(unsigned)m->flags); + strbuf_puts(&sb, " alias="); + dump_sb(w, &sb); dump_alias(w, &m->alias); } static void dump_phi(Writer* w, const Inst* in) { char buf[96]; + StrBuf sb; IRPhiAux* aux = (IRPhiAux*)in->extra.aux; - snprintf(buf, sizeof buf, " slot=%u preds=[", - aux ? (unsigned)aux->slot_id : 0u); - dump_write(w, buf); + strbuf_init(&sb, buf, sizeof buf); + strbuf_puts(&sb, " slot="); + strbuf_put_u64(&sb, aux ? (u64)(unsigned)aux->slot_id : 0u); + strbuf_puts(&sb, " preds=["); + dump_sb(w, &sb); if (aux) { for (u32 p = 0; p < aux->npreds; ++p) { - snprintf(buf, sizeof buf, "%sb%u:v%u", p ? "," : "", - (unsigned)aux->pred_blocks[p], (unsigned)aux->pred_vals[p]); - dump_write(w, buf); + strbuf_reset(&sb); + if (p) strbuf_putc(&sb, ','); + strbuf_putc(&sb, 'b'); + strbuf_put_u64(&sb, (u64)(unsigned)aux->pred_blocks[p]); + strbuf_puts(&sb, ":v"); + strbuf_put_u64(&sb, (u64)(unsigned)aux->pred_vals[p]); + dump_sb(w, &sb); } } dump_write(w, "]"); @@ -230,39 +273,64 @@ static void dump_ret(Writer* w, const Inst* in) { void opt_ir_dump(Func* f, Writer* w) { if (!f || !w) return; char buf[160]; - snprintf(buf, sizeof buf, "ir blocks=%u vals=%u\n", (unsigned)f->nblocks, - (unsigned)f->nvals); - dump_write(w, buf); + StrBuf sb; + strbuf_init(&sb, buf, sizeof buf); + strbuf_puts(&sb, "ir blocks="); + strbuf_put_u64(&sb, (u64)(unsigned)f->nblocks); + strbuf_puts(&sb, " vals="); + strbuf_put_u64(&sb, (u64)(unsigned)f->nvals); + strbuf_putc(&sb, '\n'); + dump_sb(w, &sb); for (u32 b = 0; b < f->nblocks; ++b) { Block* bl = &f->blocks[b]; - snprintf(buf, sizeof buf, "block %u preds=[", (unsigned)b); - dump_write(w, buf); + strbuf_reset(&sb); + strbuf_puts(&sb, "block "); + strbuf_put_u64(&sb, (u64)(unsigned)b); + strbuf_puts(&sb, " preds=["); + dump_sb(w, &sb); for (u32 p = 0; p < bl->npreds; ++p) { - snprintf(buf, sizeof buf, "%sb%u", p ? "," : "", (unsigned)bl->preds[p]); - dump_write(w, buf); + strbuf_reset(&sb); + if (p) strbuf_putc(&sb, ','); + strbuf_putc(&sb, 'b'); + strbuf_put_u64(&sb, (u64)(unsigned)bl->preds[p]); + dump_sb(w, &sb); } dump_write(w, "] succs=["); for (u32 s = 0; s < bl->nsucc; ++s) { - snprintf(buf, sizeof buf, "%sb%u", s ? "," : "", (unsigned)bl->succ[s]); - dump_write(w, buf); + strbuf_reset(&sb); + if (s) strbuf_putc(&sb, ','); + strbuf_putc(&sb, 'b'); + strbuf_put_u64(&sb, (u64)(unsigned)bl->succ[s]); + dump_sb(w, &sb); } - snprintf(buf, sizeof buf, "] insts=%u\n", (unsigned)bl->ninsts); - dump_write(w, buf); + strbuf_reset(&sb); + strbuf_puts(&sb, "] insts="); + strbuf_put_u64(&sb, (u64)(unsigned)bl->ninsts); + strbuf_putc(&sb, '\n'); + dump_sb(w, &sb); for (u32 i = 0; i < bl->ninsts; ++i) { Inst* in = &bl->insts[i]; - snprintf(buf, sizeof buf, " %u %s", (unsigned)i, op_name((IROp)in->op)); - dump_write(w, buf); + strbuf_reset(&sb); + strbuf_puts(&sb, " "); + strbuf_put_u64(&sb, (u64)(unsigned)i); + strbuf_putc(&sb, ' '); + strbuf_puts(&sb, op_name((IROp)in->op)); + dump_sb(w, &sb); if (in->def != VAL_NONE) { - snprintf(buf, sizeof buf, " def=v%u", (unsigned)in->def); - dump_write(w, buf); + strbuf_reset(&sb); + strbuf_puts(&sb, " def=v"); + strbuf_put_u64(&sb, (u64)(unsigned)in->def); + dump_sb(w, &sb); } if (in->ndefs) { dump_write(w, " defs=["); for (u32 d = 0; d < in->ndefs; ++d) { - snprintf(buf, sizeof buf, "%sv%u", d ? "," : "", - (unsigned)in->defs[d]); - dump_write(w, buf); + strbuf_reset(&sb); + if (d) strbuf_putc(&sb, ','); + strbuf_putc(&sb, 'v'); + strbuf_put_u64(&sb, (u64)(unsigned)in->defs[d]); + dump_sb(w, &sb); } dump_write(w, "]"); } @@ -270,8 +338,10 @@ void opt_ir_dump(Func* f, Writer* w) { if ((IROp)in->op == IR_LOAD || (IROp)in->op == IR_STORE) dump_mem(w, &in->extra.mem); if ((IROp)in->op == IR_LOAD_IMM || (IROp)in->op == IR_CONST_I) { - snprintf(buf, sizeof buf, " imm=%lld", (long long)in->extra.imm); - dump_write(w, buf); + strbuf_reset(&sb); + strbuf_puts(&sb, " imm="); + strbuf_put_i64(&sb, (i64)in->extra.imm); + dump_sb(w, &sb); } if ((IROp)in->op == IR_PHI) dump_phi(w, in); if ((IROp)in->op == IR_RET) dump_ret(w, in); diff --git a/src/opt/opt.c b/src/opt/opt.c @@ -20,6 +20,7 @@ #include "core/arena.h" #include "core/core.h" #include "core/metrics.h" +#include "core/slice.h" #include "opt/ir.h" #include "opt/opt_internal.h" @@ -44,8 +45,9 @@ static OptImpl* impl_of(CGTarget* t) { return (OptImpl*)t; } static _Noreturn void panic_unsupported(OptImpl* o, const char* what) { SrcLoc loc = {0, 0, 0}; - compiler_panic(o->c, loc, "opt_cgtarget: %s called under unbounded virtuals", - what); + compiler_panic(o->c, loc, + "opt_cgtarget: %.*s called under unbounded virtuals", + SLICE_ARG(slice_from_cstr(what))); } /* ---- recording helpers ---- */ diff --git a/src/opt/pass_analysis.c b/src/opt/pass_analysis.c @@ -2,6 +2,7 @@ #include "core/arena.h" #include "core/core.h" +#include "core/slice.h" #include "opt/opt_internal.h" #define OPT_BLK_NONE 0xffffffffu @@ -15,13 +16,27 @@ static SrcLoc opt_no_loc(void) { static void opt_fail(Func* f, const char* stage, const char* msg, u32 a, u32 b) { - compiler_panic(f->c, opt_no_loc(), "opt verify[%s]: %s (%u, %u)", - stage ? stage : "?", msg, (unsigned)a, (unsigned)b); + compiler_panic(f->c, opt_no_loc(), "opt verify[%.*s]: %.*s (%u, %u)", + SLICE_ARG(slice_from_cstr(stage ? stage : "?")), + SLICE_ARG(slice_from_cstr(msg)), (unsigned)a, (unsigned)b); +} + +/* Does `hay` contain the bytes of NUL-terminated `needle`? Length-explicit + * substring search; no strstr. */ +static int slice_contains_cstr(Slice hay, const char* needle) { + Slice n = slice_from_cstr(needle); + size_t i; + if (n.len == 0) return 1; + if (hay.len < n.len) return 0; + for (i = 0; i + n.len <= hay.len; ++i) + if (memcmp(hay.s + i, n.s, n.len) == 0) return 1; + return 0; } static int verify_stage_is_ssa(const char* stage) { - return stage && strstr(stage, "ssa") != NULL && - strstr(stage, "pre-ssa") == NULL; + Slice s = slice_from_cstr(stage); + return stage && slice_contains_cstr(s, "ssa") && + !slice_contains_cstr(s, "pre-ssa"); } #endif diff --git a/src/opt/pass_emit.c b/src/opt/pass_emit.c @@ -4,6 +4,7 @@ #include "core/arena.h" #include "core/core.h" #include "core/metrics.h" +#include "core/slice.h" #include "opt/ir.h" #include "opt/opt_internal.h" @@ -639,9 +640,10 @@ static void replay_inst(ReplayCtx* r, u32 b, Inst* in) { replay_planned_call(r, aux); break; } - compiler_panic(r->c, in->loc, - "opt replay: call has no supported call plan%s%s", - plan_reason ? ": " : "", plan_reason ? plan_reason : ""); + compiler_panic( + r->c, in->loc, "opt replay: call has no supported call plan%.*s%.*s", + SLICE_ARG(plan_reason ? SLICE_LIT(": ") : SLICE_NULL), + SLICE_ARG(plan_reason ? slice_from_cstr(plan_reason) : SLICE_NULL)); break; } case IR_BR: { diff --git a/src/opt/pass_live.c b/src/opt/pass_live.c @@ -1,8 +1,9 @@ -#include <stdio.h> #include <stdlib.h> #include <string.h> #include "core/arena.h" +#include "core/slice.h" +#include "core/strbuf.h" #include "opt/opt.h" #include "opt/opt_internal.h" @@ -253,14 +254,21 @@ void opt_live_blocks(Func* f, OptLiveInfo* live) { } static void dump_write(Writer* w, const char* s) { - cfree_writer_write(w, s, strlen(s)); + cfree_writer_write(w, s, slice_from_cstr(s).len); +} + +static void dump_sb(Writer* w, const StrBuf* sb) { + cfree_writer_write(w, strbuf_cstr(sb), strbuf_len(sb)); } static void dump_bit(PReg r, void* arg) { Writer* w = (Writer*)arg; char buf[32]; - snprintf(buf, sizeof buf, " r%u", (unsigned)r); - dump_write(w, buf); + StrBuf sb; + strbuf_init(&sb, buf, sizeof buf); + strbuf_puts(&sb, " r"); + strbuf_put_u64(&sb, (u64)(unsigned)r); + dump_sb(w, &sb); } static void dump_set(Writer* w, const char* name, const OptBitset* bs) { @@ -276,8 +284,12 @@ void opt_live_dump_blocks(Func* f, const OptLiveInfo* live, Writer* w) { if (!live || !w) return; for (u32 b = 0; b < live->f->nblocks; ++b) { char buf[64]; - snprintf(buf, sizeof buf, "block %u\n", (unsigned)b); - dump_write(w, buf); + StrBuf sb; + strbuf_init(&sb, buf, sizeof buf); + strbuf_puts(&sb, "block "); + strbuf_put_u64(&sb, (u64)(unsigned)b); + strbuf_putc(&sb, '\n'); + dump_sb(w, &sb); dump_set(w, "use", &live->blocks[b].live_use); dump_set(w, "def", &live->blocks[b].live_def); dump_set(w, "in", &live->blocks[b].live_in); @@ -794,25 +806,41 @@ void opt_live_dump_ranges(Func* f, const OptLiveRangeSet* ranges, Writer* w) { (void)f; if (!ranges || !w) return; char buf[160]; - snprintf(buf, sizeof buf, - "ranges total=%u points=%u raw_points=%u whole_block=%u\n", - (unsigned)ranges->nranges, (unsigned)ranges->point_count, - (unsigned)ranges->raw_point_count, - (unsigned)ranges->whole_block_spans); - dump_write(w, buf); + StrBuf sb; + strbuf_init(&sb, buf, sizeof buf); + strbuf_puts(&sb, "ranges total="); + strbuf_put_u64(&sb, (u64)(unsigned)ranges->nranges); + strbuf_puts(&sb, " points="); + strbuf_put_u64(&sb, (u64)(unsigned)ranges->point_count); + strbuf_puts(&sb, " raw_points="); + strbuf_put_u64(&sb, (u64)(unsigned)ranges->raw_point_count); + strbuf_puts(&sb, " whole_block="); + strbuf_put_u64(&sb, (u64)(unsigned)ranges->whole_block_spans); + strbuf_putc(&sb, '\n'); + dump_sb(w, &sb); for (PReg r = 1; r < opt_reg_count(ranges->f); ++r) { if (ranges->first_range_by_preg[r] == OPT_RANGE_NONE) continue; - snprintf(buf, sizeof buf, "r%u len=%u spill=%u:", (unsigned)r, - (unsigned)ranges->live_length_by_preg[r], - (unsigned)ranges->spill_cost_by_preg[r]); - dump_write(w, buf); + strbuf_reset(&sb); + strbuf_putc(&sb, 'r'); + strbuf_put_u64(&sb, (u64)(unsigned)r); + strbuf_puts(&sb, " len="); + strbuf_put_u64(&sb, (u64)(unsigned)ranges->live_length_by_preg[r]); + strbuf_puts(&sb, " spill="); + strbuf_put_u64(&sb, (u64)(unsigned)ranges->spill_cost_by_preg[r]); + strbuf_putc(&sb, ':'); + dump_sb(w, &sb); for (u32 ri = ranges->first_range_by_preg[r]; ri != OPT_RANGE_NONE; ri = ranges->ranges[ri].next) { const OptLiveRange* lr = &ranges->ranges[ri]; - snprintf(buf, sizeof buf, " [%u,%u)b%u%s", (unsigned)lr->start, - (unsigned)lr->end, (unsigned)lr->block, - lr->whole_block ? "*" : ""); - dump_write(w, buf); + strbuf_reset(&sb); + strbuf_puts(&sb, " ["); + strbuf_put_u64(&sb, (u64)(unsigned)lr->start); + strbuf_putc(&sb, ','); + strbuf_put_u64(&sb, (u64)(unsigned)lr->end); + strbuf_puts(&sb, ")b"); + strbuf_put_u64(&sb, (u64)(unsigned)lr->block); + if (lr->whole_block) strbuf_putc(&sb, '*'); + dump_sb(w, &sb); } dump_write(w, "\n"); } diff --git a/src/opt/pass_lower.c b/src/opt/pass_lower.c @@ -1,4 +1,3 @@ -#include <stdio.h> #include <stdlib.h> #include <string.h> @@ -6,6 +5,8 @@ #include "core/core.h" #include "core/metrics.h" #include "core/pool.h" +#include "core/slice.h" +#include "core/strbuf.h" #include "opt/opt_internal.h" enum { @@ -1480,27 +1481,43 @@ static void rewrite_func(Func* f, const OptLiveInfo* live_info) { f->opt_rewritten = 1; } -static void rewrite_dump_write(Writer* w, const char* s) { - cfree_writer_write(w, s, strlen(s)); +static void rewrite_dump_sb(Writer* w, const StrBuf* sb) { + cfree_writer_write(w, strbuf_cstr(sb), strbuf_len(sb)); } void opt_rewrite_dump(Func* f, Writer* w) { if (!f || !w) return; char buf[96]; - snprintf(buf, sizeof buf, "rewrite blocks=%u pregs=%u rewritten=%u\n", - (unsigned)f->nblocks, (unsigned)opt_reg_count(f), - (unsigned)f->opt_rewritten); - rewrite_dump_write(w, buf); + StrBuf sb; + strbuf_init(&sb, buf, sizeof buf); + strbuf_puts(&sb, "rewrite blocks="); + strbuf_put_u64(&sb, (u64)(unsigned)f->nblocks); + strbuf_puts(&sb, " pregs="); + strbuf_put_u64(&sb, (u64)(unsigned)opt_reg_count(f)); + strbuf_puts(&sb, " rewritten="); + strbuf_put_u64(&sb, (u64)(unsigned)f->opt_rewritten); + strbuf_putc(&sb, '\n'); + rewrite_dump_sb(w, &sb); for (u32 b = 0; b < f->nblocks; ++b) { Block* bl = &f->blocks[b]; - snprintf(buf, sizeof buf, "block %u insts=%u\n", (unsigned)b, - (unsigned)bl->ninsts); - rewrite_dump_write(w, buf); + strbuf_reset(&sb); + strbuf_puts(&sb, "block "); + strbuf_put_u64(&sb, (u64)(unsigned)b); + strbuf_puts(&sb, " insts="); + strbuf_put_u64(&sb, (u64)(unsigned)bl->ninsts); + strbuf_putc(&sb, '\n'); + rewrite_dump_sb(w, &sb); for (u32 i = 0; i < bl->ninsts; ++i) { Inst* in = &bl->insts[i]; - snprintf(buf, sizeof buf, " %u op=%u operands=%u\n", (unsigned)i, - (unsigned)in->op, (unsigned)in->nopnds); - rewrite_dump_write(w, buf); + strbuf_reset(&sb); + strbuf_puts(&sb, " "); + strbuf_put_u64(&sb, (u64)(unsigned)i); + strbuf_puts(&sb, " op="); + strbuf_put_u64(&sb, (u64)(unsigned)in->op); + strbuf_puts(&sb, " operands="); + strbuf_put_u64(&sb, (u64)(unsigned)in->nopnds); + strbuf_putc(&sb, '\n'); + rewrite_dump_sb(w, &sb); } } } diff --git a/src/opt/pass_machinize.c b/src/opt/pass_machinize.c @@ -3,6 +3,7 @@ #include "core/arena.h" #include "core/core.h" #include "core/pool.h" +#include "core/slice.h" #include "opt/opt_internal.h" static const char* asm_constraint_body(const char* s) { @@ -21,7 +22,9 @@ static int asm_resolve_fixed_constraint(Func* f, CGTarget* target, const char* end = body + 1; while (*end && *end != '}') ++end; if (*end != '}' || end == body + 1) return 0; - Sym name = pool_intern(f->c->global, body + 1, (size_t)(end - body - 1)); + Sym name = pool_intern_slice( + f->c->global, + (Slice){ .s = body + 1, .len = (size_t)(end - body - 1) }); return target->resolve_reg_name(target, name, reg_out, cls_out) == 0; } diff --git a/src/opt/pass_ssa.c b/src/opt/pass_ssa.c @@ -1,10 +1,11 @@ /* pass_ssa.c - mem2reg SSA construction and phi destruction for O2. */ -#include <stdio.h> #include <string.h> #include "core/arena.h" #include "core/core.h" +#include "core/slice.h" +#include "core/strbuf.h" #include "opt/opt_internal.h" typedef struct SlotStack { @@ -975,7 +976,11 @@ void opt_undo_ssa(Func* f) { } static void ssa_dump_write(Writer* w, const char* s) { - cfree_writer_write(w, s, strlen(s)); + cfree_writer_write(w, s, slice_from_cstr(s).len); +} + +static void ssa_dump_sb(Writer* w, const StrBuf* sb) { + cfree_writer_write(w, strbuf_cstr(sb), strbuf_len(sb)); } typedef struct SsaDumpUseCtx { @@ -990,8 +995,12 @@ static void ssa_dump_use(Func* f, Inst* in, Operand* op, int is_def, if (is_def || op->kind != OPK_REG) return; SsaDumpUseCtx* ctx = (SsaDumpUseCtx*)arg; char buf[32]; - snprintf(buf, sizeof buf, "%sv%u", ctx->any ? "," : "", (unsigned)op->v.reg); - ssa_dump_write(ctx->w, buf); + StrBuf sb; + strbuf_init(&sb, buf, sizeof buf); + if (ctx->any) strbuf_putc(&sb, ','); + strbuf_putc(&sb, 'v'); + strbuf_put_u64(&sb, (u64)(unsigned)op->v.reg); + ssa_dump_sb(ctx->w, &sb); ctx->any = 1; } @@ -999,34 +1008,57 @@ void opt_ssa_dump(Func* f, Writer* w) { if (!f || !w) return; opt_rebuild_def_use(f); char buf[160]; - snprintf(buf, sizeof buf, "ssa blocks=%u vals=%u uses=%u\n", - (unsigned)f->nblocks, (unsigned)f->nvals, (unsigned)f->opt_nuses); - ssa_dump_write(w, buf); + StrBuf sb; + strbuf_init(&sb, buf, sizeof buf); + strbuf_puts(&sb, "ssa blocks="); + strbuf_put_u64(&sb, (u64)(unsigned)f->nblocks); + strbuf_puts(&sb, " vals="); + strbuf_put_u64(&sb, (u64)(unsigned)f->nvals); + strbuf_puts(&sb, " uses="); + strbuf_put_u64(&sb, (u64)(unsigned)f->opt_nuses); + strbuf_putc(&sb, '\n'); + ssa_dump_sb(w, &sb); for (u32 b = 0; b < f->nblocks; ++b) { Block* bl = &f->blocks[b]; - snprintf(buf, sizeof buf, "block %u preds=%u succs=%u\n", (unsigned)b, - (unsigned)bl->npreds, (unsigned)bl->nsucc); - ssa_dump_write(w, buf); + strbuf_reset(&sb); + strbuf_puts(&sb, "block "); + strbuf_put_u64(&sb, (u64)(unsigned)b); + strbuf_puts(&sb, " preds="); + strbuf_put_u64(&sb, (u64)(unsigned)bl->npreds); + strbuf_puts(&sb, " succs="); + strbuf_put_u64(&sb, (u64)(unsigned)bl->nsucc); + strbuf_putc(&sb, '\n'); + ssa_dump_sb(w, &sb); for (u32 i = 0; i < bl->ninsts; ++i) { Inst* in = &bl->insts[i]; - snprintf(buf, sizeof buf, " i%u op=%u", (unsigned)in->id, - (unsigned)in->op); - ssa_dump_write(w, buf); + strbuf_reset(&sb); + strbuf_puts(&sb, " i"); + strbuf_put_u64(&sb, (u64)(unsigned)in->id); + strbuf_puts(&sb, " op="); + strbuf_put_u64(&sb, (u64)(unsigned)in->op); + ssa_dump_sb(w, &sb); if (in->def != VAL_NONE) { - snprintf(buf, sizeof buf, " def=v%u", (unsigned)in->def); - ssa_dump_write(w, buf); + strbuf_reset(&sb); + strbuf_puts(&sb, " def=v"); + strbuf_put_u64(&sb, (u64)(unsigned)in->def); + ssa_dump_sb(w, &sb); } if ((IROp)in->op == IR_PHI) { IRPhiAux* aux = (IRPhiAux*)in->extra.aux; - snprintf(buf, sizeof buf, - " phi slot=%u preds=", aux ? (unsigned)aux->slot_id : 0u); - ssa_dump_write(w, buf); + strbuf_reset(&sb); + strbuf_puts(&sb, " phi slot="); + strbuf_put_u64(&sb, aux ? (u64)(unsigned)aux->slot_id : 0u); + strbuf_puts(&sb, " preds="); + ssa_dump_sb(w, &sb); if (aux) { for (u32 p = 0; p < aux->npreds; ++p) { - snprintf(buf, sizeof buf, "%sb%u:v%u", p ? "," : "", - (unsigned)aux->pred_blocks[p], - (unsigned)aux->pred_vals[p]); - ssa_dump_write(w, buf); + strbuf_reset(&sb); + if (p) strbuf_putc(&sb, ','); + strbuf_putc(&sb, 'b'); + strbuf_put_u64(&sb, (u64)(unsigned)aux->pred_blocks[p]); + strbuf_puts(&sb, ":v"); + strbuf_put_u64(&sb, (u64)(unsigned)aux->pred_vals[p]); + ssa_dump_sb(w, &sb); } } } else { diff --git a/test/api/abi_classify_test.c b/test/api/abi_classify_test.c @@ -339,10 +339,10 @@ static CfreeCgTypeId make_i8_record(CfreeCompiler* c, const char* tag_name, if (nfields > 16) exit(2); memset(fields, 0, sizeof fields); for (u32 i = 0; i < nfields; ++i) { - fields[i].name = cfree_sym_intern(c, names[i]); + fields[i].name = cfree_sym_intern(c, cfree_slice_cstr(names[i])); fields[i].type = i8; } - return cfree_cg_type_record(c, cfree_sym_intern(c, tag_name), fields, + return cfree_cg_type_record(c, cfree_sym_intern(c, cfree_slice_cstr(tag_name)), fields, nfields); } @@ -352,11 +352,11 @@ static CfreeCgTypeId make_two_i64_record(CfreeCompiler* c, const char* tag_n) { CfreeCgTypeId i64 = bi.id[CFREE_CG_BUILTIN_I64]; CfreeCgField fields[2]; memset(fields, 0, sizeof fields); - fields[0].name = cfree_sym_intern(c, "a"); + fields[0].name = cfree_sym_intern(c, CFREE_SLICE_LIT("a")); fields[0].type = i64; - fields[1].name = cfree_sym_intern(c, "b"); + fields[1].name = cfree_sym_intern(c, CFREE_SLICE_LIT("b")); fields[1].type = i64; - return cfree_cg_type_record(c, cfree_sym_intern(c, tag_n), fields, 2); + return cfree_cg_type_record(c, cfree_sym_intern(c, cfree_slice_cstr(tag_n)), fields, 2); } /* Classify a function `ret_ty fn(p0, p1, ..., pN-1)` and return its info. */ diff --git a/test/api/cg_switch_test.c b/test/api/cg_switch_test.c @@ -135,7 +135,7 @@ static void build_switch_fn(CfreeCompiler* c, CfreeCgTypeId i32_ty, snprintf(fn_name, sizeof fn_name, "switch_%s_o%d", sh->name, opt_level); memset(&decl, 0, sizeof decl); decl.kind = CFREE_CG_DECL_FUNC; - decl.linkage_name = cfree_sym_intern(c, fn_name); + decl.linkage_name = cfree_sym_intern(c, cfree_slice_cstr(fn_name)); decl.display_name = decl.linkage_name; decl.type = cfree_cg_type_func(c, sig); decl.sym.bind = CFREE_SB_GLOBAL; @@ -146,7 +146,7 @@ static void build_switch_fn(CfreeCompiler* c, CfreeCgTypeId i32_ty, cfree_cg_func_begin(cg, sym); memset(&attrs, 0, sizeof attrs); - attrs.name = cfree_sym_intern(c, "x"); + attrs.name = cfree_sym_intern(c, CFREE_SLICE_LIT("x")); param = cfree_cg_param(cg, 0, sh->selector_type, attrs); EXPECT(param != CFREE_CG_LOCAL_NONE, "[%s/O%d] param failed", sh->name, opt_level); diff --git a/test/api/cg_type_test.c b/test/api/cg_type_test.c @@ -118,7 +118,7 @@ static void exercise_cg_handles(CfreeCompiler* c, CfreeCgTypeId i32_ty, snprintf(name_buf, sizeof(name_buf), "cg_handles_o%d", opt_level); memset(&decl, 0, sizeof(decl)); decl.kind = CFREE_CG_DECL_FUNC; - decl.linkage_name = cfree_sym_intern(c, name_buf); + decl.linkage_name = cfree_sym_intern(c, cfree_slice_cstr(name_buf)); decl.display_name = decl.linkage_name; decl.type = cfree_cg_type_func(c, sig); decl.sym.bind = CFREE_SB_GLOBAL; @@ -128,9 +128,9 @@ static void exercise_cg_handles(CfreeCompiler* c, CfreeCgTypeId i32_ty, cfree_cg_func_begin(cg, sym); memset(&attrs, 0, sizeof(attrs)); - attrs.name = cfree_sym_intern(c, "p"); + attrs.name = cfree_sym_intern(c, CFREE_SLICE_LIT("p")); param = cfree_cg_param(cg, 0, i32_ty, attrs); - attrs.name = cfree_sym_intern(c, "x"); + attrs.name = cfree_sym_intern(c, CFREE_SLICE_LIT("x")); local = cfree_cg_local(cg, i32_ty, attrs); EXPECT(local != CFREE_CG_LOCAL_NONE, "local handle is none"); EXPECT(param != CFREE_CG_LOCAL_NONE, "param handle is none"); @@ -192,7 +192,7 @@ static void exercise_cg_scalar_local(CfreeCompiler* c, CfreeCgTypeId i32_ty, snprintf(name_buf, sizeof name_buf, "cg_scalar_local_o%d", opt_level); memset(&decl, 0, sizeof decl); decl.kind = CFREE_CG_DECL_FUNC; - decl.linkage_name = cfree_sym_intern(c, name_buf); + decl.linkage_name = cfree_sym_intern(c, cfree_slice_cstr(name_buf)); decl.display_name = decl.linkage_name; decl.type = cfree_cg_type_func(c, sig); decl.sym.bind = CFREE_SB_GLOBAL; @@ -202,7 +202,7 @@ static void exercise_cg_scalar_local(CfreeCompiler* c, CfreeCgTypeId i32_ty, cfree_cg_func_begin(cg, sym); memset(&attrs, 0, sizeof attrs); - attrs.name = cfree_sym_intern(c, "x"); + attrs.name = cfree_sym_intern(c, CFREE_SLICE_LIT("x")); local = cfree_cg_local(cg, i32_ty, attrs); EXPECT(local != CFREE_CG_LOCAL_NONE, "scalar local handle is none"); @@ -258,7 +258,7 @@ static void exercise_cg_late_local_addr(CfreeCompiler* c, CfreeCgTypeId i32_ty, snprintf(name_buf, sizeof name_buf, "cg_late_local_addr_o%d", opt_level); memset(&decl, 0, sizeof decl); decl.kind = CFREE_CG_DECL_FUNC; - decl.linkage_name = cfree_sym_intern(c, name_buf); + decl.linkage_name = cfree_sym_intern(c, cfree_slice_cstr(name_buf)); decl.display_name = decl.linkage_name; decl.type = cfree_cg_type_func(c, sig); decl.sym.bind = CFREE_SB_GLOBAL; @@ -268,7 +268,7 @@ static void exercise_cg_late_local_addr(CfreeCompiler* c, CfreeCgTypeId i32_ty, cfree_cg_func_begin(cg, sym); memset(&attrs, 0, sizeof attrs); - attrs.name = cfree_sym_intern(c, "x"); + attrs.name = cfree_sym_intern(c, CFREE_SLICE_LIT("x")); local = cfree_cg_local(cg, i32_ty, attrs); EXPECT(local != CFREE_CG_LOCAL_NONE, "late addr local handle is none"); @@ -330,7 +330,7 @@ static void exercise_cg_data_entsize(CfreeCompiler* c, CfreeCgTypeId i8_ty) { memset(&decl, 0, sizeof decl); decl.kind = CFREE_CG_DECL_OBJECT; - decl.linkage_name = cfree_sym_intern(c, "cg_entsize_string"); + decl.linkage_name = cfree_sym_intern(c, CFREE_SLICE_LIT("cg_entsize_string")); decl.display_name = decl.linkage_name; decl.type = array_ty; decl.sym.bind = CFREE_SB_GLOBAL; @@ -341,7 +341,7 @@ static void exercise_cg_data_entsize(CfreeCompiler* c, CfreeCgTypeId i8_ty) { EXPECT(sym != CFREE_CG_SYM_NONE, "entsize object decl failed"); memset(&data_attrs, 0, sizeof data_attrs); - data_attrs.section = cfree_sym_intern(c, ".rodata.cfree.merge"); + data_attrs.section = cfree_sym_intern(c, CFREE_SLICE_LIT(".rodata.cfree.merge")); data_attrs.align = 1; data_attrs.entsize = 1; data_attrs.flags = CFREE_CG_DATADEF_READONLY | CFREE_CG_DATADEF_MERGE | @@ -375,7 +375,7 @@ static CfreeCgSym begin_i32_func(CfreeCompiler* c, CfreeCg* cg, memset(&decl, 0, sizeof decl); decl.kind = CFREE_CG_DECL_FUNC; - decl.linkage_name = cfree_sym_intern(c, name); + decl.linkage_name = cfree_sym_intern(c, cfree_slice_cstr(name)); decl.display_name = decl.linkage_name; decl.type = cfree_cg_type_func(c, sig); decl.sym.bind = CFREE_SB_GLOBAL; @@ -489,7 +489,7 @@ static uint32_t cg_emit_delayed_chain(CfreeCompiler* c, CfreeCgTypeId i32_ty, memset(&decl, 0, sizeof decl); decl.kind = CFREE_CG_DECL_FUNC; - decl.linkage_name = cfree_sym_intern(c, name); + decl.linkage_name = cfree_sym_intern(c, cfree_slice_cstr(name)); decl.display_name = decl.linkage_name; decl.type = cfree_cg_type_func(c, sig); decl.sym.bind = CFREE_SB_GLOBAL; @@ -499,7 +499,7 @@ static uint32_t cg_emit_delayed_chain(CfreeCompiler* c, CfreeCgTypeId i32_ty, cfree_cg_func_begin(cg, sym); memset(&attrs, 0, sizeof attrs); - attrs.name = cfree_sym_intern(c, "p"); + attrs.name = cfree_sym_intern(c, CFREE_SLICE_LIT("p")); param = cfree_cg_param(cg, 0, i32_ty, attrs); EXPECT(param != CFREE_CG_LOCAL_NONE, "delayed chain param failed"); memset(&mem, 0, sizeof mem); @@ -558,7 +558,7 @@ static uint32_t cg_emit_unary_chain(CfreeCompiler* c, CfreeCgTypeId i32_ty, memset(&decl, 0, sizeof decl); decl.kind = CFREE_CG_DECL_FUNC; - decl.linkage_name = cfree_sym_intern(c, name); + decl.linkage_name = cfree_sym_intern(c, cfree_slice_cstr(name)); decl.display_name = decl.linkage_name; decl.type = cfree_cg_type_func(c, sig); decl.sym.bind = CFREE_SB_GLOBAL; @@ -568,7 +568,7 @@ static uint32_t cg_emit_unary_chain(CfreeCompiler* c, CfreeCgTypeId i32_ty, cfree_cg_func_begin(cg, sym); memset(&attrs, 0, sizeof attrs); - attrs.name = cfree_sym_intern(c, "p"); + attrs.name = cfree_sym_intern(c, CFREE_SLICE_LIT("p")); param = cfree_cg_param(cg, 0, i32_ty, attrs); EXPECT(param != CFREE_CG_LOCAL_NONE, "unary chain param failed"); memset(&mem, 0, sizeof mem); @@ -620,7 +620,7 @@ static uint32_t cg_emit_local_shadow(CfreeCompiler* c, CfreeCgTypeId i32_ty, memset(&decl, 0, sizeof decl); decl.kind = CFREE_CG_DECL_FUNC; - decl.linkage_name = cfree_sym_intern(c, name); + decl.linkage_name = cfree_sym_intern(c, cfree_slice_cstr(name)); decl.display_name = decl.linkage_name; decl.type = cfree_cg_type_func(c, sig); decl.sym.bind = CFREE_SB_GLOBAL; @@ -630,7 +630,7 @@ static uint32_t cg_emit_local_shadow(CfreeCompiler* c, CfreeCgTypeId i32_ty, cfree_cg_func_begin(cg, sym); memset(&attrs, 0, sizeof attrs); - attrs.name = cfree_sym_intern(c, "x"); + attrs.name = cfree_sym_intern(c, CFREE_SLICE_LIT("x")); local = cfree_cg_local(cg, i32_ty, attrs); EXPECT(local != CFREE_CG_LOCAL_NONE, "local shadow local failed"); memset(&mem, 0, sizeof mem); @@ -690,7 +690,7 @@ static uint32_t cg_emit_delayed_cmp(CfreeCompiler* c, CfreeCgTypeId i32_ty, memset(&decl, 0, sizeof decl); decl.kind = CFREE_CG_DECL_FUNC; - decl.linkage_name = cfree_sym_intern(c, name); + decl.linkage_name = cfree_sym_intern(c, cfree_slice_cstr(name)); decl.display_name = decl.linkage_name; decl.type = cfree_cg_type_func(c, sig); decl.sym.bind = CFREE_SB_GLOBAL; @@ -700,7 +700,7 @@ static uint32_t cg_emit_delayed_cmp(CfreeCompiler* c, CfreeCgTypeId i32_ty, cfree_cg_func_begin(cg, sym); memset(&attrs, 0, sizeof attrs); - attrs.name = cfree_sym_intern(c, "p"); + attrs.name = cfree_sym_intern(c, CFREE_SLICE_LIT("p")); param = cfree_cg_param(cg, 0, i32_ty, attrs); EXPECT(param != CFREE_CG_LOCAL_NONE, "delayed cmp param failed"); memset(&mem, 0, sizeof mem); @@ -762,7 +762,7 @@ static uint32_t cg_emit_delayed_store(CfreeCompiler* c, CfreeCgTypeId i32_ty, memset(&decl, 0, sizeof decl); decl.kind = CFREE_CG_DECL_FUNC; - decl.linkage_name = cfree_sym_intern(c, name); + decl.linkage_name = cfree_sym_intern(c, cfree_slice_cstr(name)); decl.display_name = decl.linkage_name; decl.type = cfree_cg_type_func(c, sig); decl.sym.bind = CFREE_SB_GLOBAL; @@ -772,9 +772,9 @@ static uint32_t cg_emit_delayed_store(CfreeCompiler* c, CfreeCgTypeId i32_ty, cfree_cg_func_begin(cg, sym); memset(&attrs, 0, sizeof attrs); - attrs.name = cfree_sym_intern(c, "p"); + attrs.name = cfree_sym_intern(c, CFREE_SLICE_LIT("p")); param = cfree_cg_param(cg, 0, i32_ty, attrs); - attrs.name = cfree_sym_intern(c, "x"); + attrs.name = cfree_sym_intern(c, CFREE_SLICE_LIT("x")); local = cfree_cg_local(cg, i32_ty, attrs); EXPECT(param != CFREE_CG_LOCAL_NONE, "delayed store param failed"); EXPECT(local != CFREE_CG_LOCAL_NONE, "delayed store local failed"); @@ -839,7 +839,7 @@ static uint32_t cg_emit_delayed_pressure(CfreeCompiler* c, CfreeCgTypeId i32_ty, memset(&decl, 0, sizeof decl); decl.kind = CFREE_CG_DECL_FUNC; - decl.linkage_name = cfree_sym_intern(c, name); + decl.linkage_name = cfree_sym_intern(c, cfree_slice_cstr(name)); decl.display_name = decl.linkage_name; decl.type = cfree_cg_type_func(c, sig); decl.sym.bind = CFREE_SB_GLOBAL; @@ -855,7 +855,7 @@ static uint32_t cg_emit_delayed_pressure(CfreeCompiler* c, CfreeCgTypeId i32_ty, for (uint32_t i = 0; i < NPARAMS; ++i) { char pname[8]; snprintf(pname, sizeof pname, "p%u", (unsigned)i); - attrs.name = cfree_sym_intern(c, pname); + attrs.name = cfree_sym_intern(c, cfree_slice_cstr(pname)); params[i] = cfree_cg_param(cg, i, i32_ty, attrs); EXPECT(params[i] != CFREE_CG_LOCAL_NONE, "delayed pressure param failed"); } @@ -923,7 +923,7 @@ static uint32_t cg_emit_local_shadow_boundary(CfreeCompiler* c, memset(&decl, 0, sizeof decl); decl.kind = CFREE_CG_DECL_FUNC; - decl.linkage_name = cfree_sym_intern(c, name); + decl.linkage_name = cfree_sym_intern(c, cfree_slice_cstr(name)); decl.display_name = decl.linkage_name; decl.type = cfree_cg_type_func(c, sig); decl.sym.bind = CFREE_SB_GLOBAL; @@ -933,7 +933,7 @@ static uint32_t cg_emit_local_shadow_boundary(CfreeCompiler* c, cfree_cg_func_begin(cg, sym); memset(&attrs, 0, sizeof attrs); - attrs.name = cfree_sym_intern(c, "x"); + attrs.name = cfree_sym_intern(c, CFREE_SLICE_LIT("x")); local = cfree_cg_local(cg, i32_ty, attrs); EXPECT(local != CFREE_CG_LOCAL_NONE, "local shadow boundary local failed"); memset(&mem, 0, sizeof mem); @@ -1025,7 +1025,7 @@ static uint32_t cg_emit_local_shadow_partial_store(CfreeCompiler* c, memset(&decl, 0, sizeof decl); decl.kind = CFREE_CG_DECL_FUNC; - decl.linkage_name = cfree_sym_intern(c, name); + decl.linkage_name = cfree_sym_intern(c, cfree_slice_cstr(name)); decl.display_name = decl.linkage_name; decl.type = cfree_cg_type_func(c, sig); decl.sym.bind = CFREE_SB_GLOBAL; @@ -1035,7 +1035,7 @@ static uint32_t cg_emit_local_shadow_partial_store(CfreeCompiler* c, cfree_cg_func_begin(cg, sym); memset(&attrs, 0, sizeof attrs); - attrs.name = cfree_sym_intern(c, "x"); + attrs.name = cfree_sym_intern(c, CFREE_SLICE_LIT("x")); local = cfree_cg_local(cg, i32_ty, attrs); EXPECT(local != CFREE_CG_LOCAL_NONE, "partial shadow local failed"); memset(&mem_i32, 0, sizeof mem_i32); @@ -1158,7 +1158,7 @@ static CfreeCg* cg_begin_bad_store_func(CfreeCompiler* c, const char* name) { sig.call_conv = CFREE_CG_CC_TARGET_C; memset(&decl, 0, sizeof decl); decl.kind = CFREE_CG_DECL_FUNC; - decl.linkage_name = cfree_sym_intern(c, name); + decl.linkage_name = cfree_sym_intern(c, cfree_slice_cstr(name)); decl.display_name = decl.linkage_name; decl.type = cfree_cg_type_func(c, sig); decl.sym.bind = CFREE_SB_LOCAL; @@ -1238,7 +1238,7 @@ static void exercise_compile_session_two_deltas(CfreeCompiler* c) { sopts.lang = CFREE_LANG_ASM; sopts.compile.language_options = &aopts; memset(&in, 0, sizeof(in)); - in.bytes.name = "<api-session-asm>"; + in.name = CFREE_SLICE_LIT("<api-session-asm>"); in.bytes.data = empty; in.bytes.len = 0; in.lang = CFREE_LANG_ASM; @@ -1358,7 +1358,7 @@ int main(void) { "array elem mismatch"); EXPECT(cfree_cg_type_array_count(c, array_i32) == 4, "array count mismatch"); - alias = cfree_cg_type_alias(c, cfree_sym_intern(c, "I"), i32_ty); + alias = cfree_cg_type_alias(c, cfree_sym_intern(c, CFREE_SLICE_LIT("I")), i32_ty); EXPECT(alias != CFREE_CG_TYPE_NONE && alias != i32_ty, "alias id should be fresh"); EXPECT(cfree_cg_type_kind(c, alias) == CFREE_CG_TYPE_ALIAS, @@ -1367,15 +1367,15 @@ int main(void) { "alias size mismatch"); memset(fields, 0, sizeof fields); - fields[0].name = cfree_sym_intern(c, "a"); + fields[0].name = cfree_sym_intern(c, CFREE_SLICE_LIT("a")); fields[0].type = i32_ty; fields[0].align_override = 0; - fields[1].name = cfree_sym_intern(c, "b"); + fields[1].name = cfree_sym_intern(c, CFREE_SLICE_LIT("b")); fields[1].type = ptr_i32; fields[1].align_override = 1; - rec = cfree_cg_type_record(c, cfree_sym_intern(c, "R"), fields, 2); + rec = cfree_cg_type_record(c, cfree_sym_intern(c, CFREE_SLICE_LIT("R")), fields, 2); EXPECT(rec != CFREE_CG_TYPE_NONE, "record type failed"); - EXPECT(cfree_cg_type_record(c, cfree_sym_intern(c, "Bad"), fields, 0) != + EXPECT(cfree_cg_type_record(c, cfree_sym_intern(c, CFREE_SLICE_LIT("Bad")), fields, 0) != CFREE_CG_TYPE_NONE, "empty record type failed"); EXPECT(cfree_cg_type_kind(c, rec) == CFREE_CG_TYPE_RECORD, @@ -1389,15 +1389,15 @@ int main(void) { EXPECT(field_off == 4, "record field offset mismatch"); memset(fields, 0, sizeof fields); - fields[0].name = cfree_sym_intern(c, "lo"); + fields[0].name = cfree_sym_intern(c, CFREE_SLICE_LIT("lo")); fields[0].type = i32_ty; fields[0].flags = CFREE_CG_FIELD_BITFIELD; fields[0].bit_width = 5; - fields[1].name = cfree_sym_intern(c, "hi"); + fields[1].name = cfree_sym_intern(c, CFREE_SLICE_LIT("hi")); fields[1].type = i32_ty; fields[1].flags = CFREE_CG_FIELD_BITFIELD; fields[1].bit_width = 3; - rec_ex = cfree_cg_type_record(c, cfree_sym_intern(c, "BF"), fields, 2); + rec_ex = cfree_cg_type_record(c, cfree_sym_intern(c, CFREE_SLICE_LIT("BF")), fields, 2); EXPECT(rec_ex != CFREE_CG_TYPE_NONE, "bit-field record type failed"); EXPECT(cfree_cg_type_size(c, rec_ex) == 4, "bit-field record size mismatch"); EXPECT(cfree_cg_type_record_field(c, rec_ex, 1, &field_out, &field_off) == 0, @@ -1407,13 +1407,13 @@ int main(void) { "bit-field metadata mismatch"); memset(fields, 0, sizeof fields); - fields[0].name = cfree_sym_intern(c, "a"); + fields[0].name = cfree_sym_intern(c, CFREE_SLICE_LIT("a")); fields[0].type = i32_ty; - fields[1].name = cfree_sym_intern(c, "b"); + fields[1].name = cfree_sym_intern(c, CFREE_SLICE_LIT("b")); fields[1].type = ptr_i32; fields[1].align_override = 1; memset(&rdesc, 0, sizeof rdesc); - rdesc.tag = cfree_sym_intern(c, "U"); + rdesc.tag = cfree_sym_intern(c, CFREE_SLICE_LIT("U")); rdesc.fields = fields; rdesc.nfields = 2; rdesc.is_union = 1; @@ -1426,11 +1426,11 @@ int main(void) { "record desc field query failed"); EXPECT(field_off == 0, "union field offset mismatch"); - vals[0].name = cfree_sym_intern(c, "A"); + vals[0].name = cfree_sym_intern(c, CFREE_SLICE_LIT("A")); vals[0].value = 1; - vals[1].name = cfree_sym_intern(c, "B"); + vals[1].name = cfree_sym_intern(c, CFREE_SLICE_LIT("B")); vals[1].value = 2; - enm = cfree_cg_type_enum(c, cfree_sym_intern(c, "E"), CFREE_CG_TYPE_NONE, + enm = cfree_cg_type_enum(c, cfree_sym_intern(c, CFREE_SLICE_LIT("E")), CFREE_CG_TYPE_NONE, vals, 2); EXPECT(enm != CFREE_CG_TYPE_NONE, "enum type failed"); diff --git a/test/ar_test.c b/test/ar_test.c @@ -132,19 +132,19 @@ static uint64_t ar_date_field(const uint8_t* hdr) { /* ===== tests ===== */ static int test_basic_roundtrip(void) { - CfreeBytes ms[2]; + CfreeArInput ms[2]; BufW bw; - CfreeBytes in; + CfreeSlice in; CfreeArIter* it = NULL; CfreeArMember m; int rc; - ms[0].name = "a.o"; - ms[0].data = (const uint8_t*)"AAAA"; - ms[0].len = 4; - ms[1].name = "b.o"; - ms[1].data = (const uint8_t*)"BBBBB"; - ms[1].len = 5; + ms[0].name = CFREE_SLICE_LIT("a.o"); + ms[0].bytes.data = (const uint8_t*)"AAAA"; + ms[0].bytes.len = 4; + ms[1].name = CFREE_SLICE_LIT("b.o"); + ms[1].bytes.data = (const uint8_t*)"BBBBB"; + ms[1].bytes.len = 5; bufw_init(&bw); rc = cfree_ar_write(&bw.base, ms, 2, NULL); @@ -153,17 +153,16 @@ static int test_basic_roundtrip(void) { EXPECT(bw.len >= 8, "archive too short"); EXPECT(memcmp(bw.data, "!<arch>\n", 8) == 0, "magic"); - in.name = "test"; in.data = bw.data; in.len = bw.len; EXPECT(cfree_ar_iter_new(&g_ctx, &in, &it) == CFREE_OK, "iter_init"); EXPECT(cfree_ar_iter_next(it, &m), "first member"); - EXPECT(strcmp(m.name, "a.o") == 0, "name 0 = %s", m.name); + EXPECT(cfree_slice_eq_cstr(m.name, "a.o"), "name 0 = %.*s", CFREE_SLICE_ARG(m.name)); EXPECT(m.size == 4 && memcmp(m.data, "AAAA", 4) == 0, "data 0"); EXPECT(cfree_ar_iter_next(it, &m), "second member"); - EXPECT(strcmp(m.name, "b.o") == 0, "name 1 = %s", m.name); + EXPECT(cfree_slice_eq_cstr(m.name, "b.o"), "name 1 = %.*s", CFREE_SLICE_ARG(m.name)); EXPECT(m.size == 5 && memcmp(m.data, "BBBBB", 5) == 0, "data 1"); EXPECT(!cfree_ar_iter_next(it, &m), "iter end"); @@ -175,35 +174,34 @@ static int test_basic_roundtrip(void) { static int test_long_name_table(void) { /* >15 chars triggers the // long-name table. */ - CfreeBytes ms[2]; + CfreeArInput ms[2]; BufW bw; - CfreeBytes in; + CfreeSlice in; CfreeArIter* it = NULL; CfreeArMember m; CfreeArWriteOptions opts = {0}; int rc; opts.long_names = 1; - ms[0].name = "short.o"; - ms[0].data = (const uint8_t*)"x"; - ms[0].len = 1; - ms[1].name = "this_name_is_long_enough.o"; - ms[1].data = (const uint8_t*)"yy"; - ms[1].len = 2; + ms[0].name = CFREE_SLICE_LIT("short.o"); + ms[0].bytes.data = (const uint8_t*)"x"; + ms[0].bytes.len = 1; + ms[1].name = CFREE_SLICE_LIT("this_name_is_long_enough.o"); + ms[1].bytes.data = (const uint8_t*)"yy"; + ms[1].bytes.len = 2; bufw_init(&bw); rc = cfree_ar_write(&bw.base, ms, 2, &opts); EXPECT(rc == 0, "write rc=%d", rc); - in.name = "test"; in.data = bw.data; in.len = bw.len; EXPECT(cfree_ar_iter_new(&g_ctx, &in, &it) == CFREE_OK, "iter_init"); EXPECT(cfree_ar_iter_next(it, &m), "first member"); - EXPECT(strcmp(m.name, "short.o") == 0, "name 0 = %s", m.name); + EXPECT(cfree_slice_eq_cstr(m.name, "short.o"), "name 0 = %.*s", CFREE_SLICE_ARG(m.name)); EXPECT(cfree_ar_iter_next(it, &m), "second member"); - EXPECT(strcmp(m.name, "this_name_is_long_enough.o") == 0, "long name = %s", - m.name); + EXPECT(cfree_slice_eq_cstr(m.name, "this_name_is_long_enough.o"), "long name = %.*s", + CFREE_SLICE_ARG(m.name)); EXPECT(!cfree_ar_iter_next(it, &m), "iter end"); cfree_ar_iter_free(it); @@ -212,9 +210,9 @@ static int test_long_name_table(void) { } static int test_symbol_index_empty(void) { - CfreeBytes ms[1]; + CfreeArInput ms[1]; BufW bw; - CfreeBytes in; + CfreeSlice in; CfreeArIter* it = NULL; CfreeArMember m; CfreeArWriteOptions opts = {0}; @@ -222,9 +220,9 @@ static int test_symbol_index_empty(void) { uint32_t nsyms; opts.symbol_index = 1; - ms[0].name = "lonely.o"; - ms[0].data = (const uint8_t*)"P"; - ms[0].len = 1; + ms[0].name = CFREE_SLICE_LIT("lonely.o"); + ms[0].bytes.data = (const uint8_t*)"P"; + ms[0].bytes.len = 1; bufw_init(&bw); rc = cfree_ar_write(&bw.base, ms, 1, &opts); @@ -238,12 +236,11 @@ static int test_symbol_index_empty(void) { EXPECT(nsyms == 0, "nsyms = %u", nsyms); /* Iterator should skip the `/` and yield only the user member. */ - in.name = "test"; in.data = bw.data; in.len = bw.len; EXPECT(cfree_ar_iter_new(&g_ctx, &in, &it) == CFREE_OK, "iter_init"); EXPECT(cfree_ar_iter_next(it, &m), "first user member"); - EXPECT(strcmp(m.name, "lonely.o") == 0, "name = %s", m.name); + EXPECT(cfree_slice_eq_cstr(m.name, "lonely.o"), "name = %.*s", CFREE_SLICE_ARG(m.name)); EXPECT(!cfree_ar_iter_next(it, &m), "iter end"); cfree_ar_iter_free(it); @@ -253,10 +250,10 @@ static int test_symbol_index_empty(void) { static int test_symbol_index_basic(void) { /* 2 members with symbol lists; verify count, offsets, and names. */ - const char* a_syms[] = {"foo", "bar"}; - const char* b_syms[] = {"baz"}; + CfreeSlice a_syms[] = {CFREE_SLICE_LIT("foo"), CFREE_SLICE_LIT("bar")}; + CfreeSlice b_syms[] = {CFREE_SLICE_LIT("baz")}; CfreeArMemberSymbols msyms[2]; - CfreeBytes ms[2]; + CfreeArInput ms[2]; BufW bw; CfreeArWriteOptions opts = {0}; int rc; @@ -270,18 +267,18 @@ static int test_symbol_index_basic(void) { opts.symbol_index = 1; opts.long_names = 1; - msyms[0].names = (const char* const*)a_syms; + msyms[0].names = a_syms; msyms[0].count = 2; - msyms[1].names = (const char* const*)b_syms; + msyms[1].names = b_syms; msyms[1].count = 1; opts.member_symbols = msyms; - ms[0].name = "a.o"; - ms[0].data = (const uint8_t*)"AAAA"; - ms[0].len = 4; - ms[1].name = "b.o"; - ms[1].data = (const uint8_t*)"BBBBB"; - ms[1].len = 5; + ms[0].name = CFREE_SLICE_LIT("a.o"); + ms[0].bytes.data = (const uint8_t*)"AAAA"; + ms[0].bytes.len = 4; + ms[1].name = CFREE_SLICE_LIT("b.o"); + ms[1].bytes.data = (const uint8_t*)"BBBBB"; + ms[1].bytes.len = 5; bufw_init(&bw); rc = cfree_ar_write(&bw.base, ms, 2, &opts); @@ -338,12 +335,12 @@ static int test_symbol_index_basic(void) { static int test_symbol_index_with_long_names(void) { /* `/` member must come BEFORE `//` long-name table, and offsets must * still point at correct member-header positions. */ - const char* syms0[] = {"alpha"}; - const char* syms1[] = {"beta"}; + CfreeSlice syms0[] = {CFREE_SLICE_LIT("alpha")}; + CfreeSlice syms1[] = {CFREE_SLICE_LIT("beta")}; CfreeArMemberSymbols msyms[2]; - CfreeBytes ms[2]; + CfreeArInput ms[2]; BufW bw; - CfreeBytes in; + CfreeSlice in; CfreeArIter* it = NULL; CfreeArMember m; CfreeArWriteOptions opts = {0}; @@ -356,18 +353,18 @@ static int test_symbol_index_with_long_names(void) { opts.symbol_index = 1; opts.long_names = 1; - msyms[0].names = (const char* const*)syms0; + msyms[0].names = syms0; msyms[0].count = 1; - msyms[1].names = (const char* const*)syms1; + msyms[1].names = syms1; msyms[1].count = 1; opts.member_symbols = msyms; - ms[0].name = "this_name_is_long_enough.o"; /* 26 chars → // */ - ms[0].data = (const uint8_t*)"X"; - ms[0].len = 1; - ms[1].name = "short.o"; - ms[1].data = (const uint8_t*)"YY"; - ms[1].len = 2; + ms[0].name = CFREE_SLICE_LIT("this_name_is_long_enough.o"); /* 26 chars → // */ + ms[0].bytes.data = (const uint8_t*)"X"; + ms[0].bytes.len = 1; + ms[1].name = CFREE_SLICE_LIT("short.o"); + ms[1].bytes.data = (const uint8_t*)"YY"; + ms[1].bytes.len = 2; bufw_init(&bw); rc = cfree_ar_write(&bw.base, ms, 2, &opts); @@ -407,15 +404,14 @@ static int test_symbol_index_with_long_names(void) { EXPECT(memcmp(bw.data + m1_hdr, "short.o/", 8) == 0, "m1 hdr"); /* Iterator should walk past both /, // and yield 2 members. */ - in.name = "test"; in.data = bw.data; in.len = bw.len; EXPECT(cfree_ar_iter_new(&g_ctx, &in, &it) == CFREE_OK, "iter_init"); EXPECT(cfree_ar_iter_next(it, &m), "m0"); - EXPECT(strcmp(m.name, "this_name_is_long_enough.o") == 0, "m0 name = %s", - m.name); + EXPECT(cfree_slice_eq_cstr(m.name, "this_name_is_long_enough.o"), "m0 name = %.*s", + CFREE_SLICE_ARG(m.name)); EXPECT(cfree_ar_iter_next(it, &m), "m1"); - EXPECT(strcmp(m.name, "short.o") == 0, "m1 name = %s", m.name); + EXPECT(cfree_slice_eq_cstr(m.name, "short.o"), "m1 name = %.*s", CFREE_SLICE_ARG(m.name)); EXPECT(!cfree_ar_iter_next(it, &m), "iter end"); /* Optional host cross-check. */ @@ -439,10 +435,10 @@ static int test_symbol_index_with_long_names(void) { static int test_iter_skips_index(void) { /* Make sure the iterator never surfaces the `/` member as a user member. */ - const char* s[] = {"only_sym"}; + CfreeSlice s[] = {CFREE_SLICE_LIT("only_sym")}; CfreeArMemberSymbols msyms[1]; - CfreeBytes ms[1]; - CfreeBytes in; + CfreeArInput ms[1]; + CfreeSlice in; CfreeArIter* it = NULL; CfreeArMember m; BufW bw; @@ -450,22 +446,21 @@ static int test_iter_skips_index(void) { int seen = 0; opts.symbol_index = 1; - msyms[0].names = (const char* const*)s; + msyms[0].names = s; msyms[0].count = 1; opts.member_symbols = msyms; - ms[0].name = "only.o"; - ms[0].data = (const uint8_t*)"Z"; - ms[0].len = 1; + ms[0].name = CFREE_SLICE_LIT("only.o"); + ms[0].bytes.data = (const uint8_t*)"Z"; + ms[0].bytes.len = 1; bufw_init(&bw); EXPECT(cfree_ar_write(&bw.base, ms, 1, &opts) == 0, "write"); - in.name = "test"; in.data = bw.data; in.len = bw.len; EXPECT(cfree_ar_iter_new(&g_ctx, &in, &it) == CFREE_OK, "iter_init"); while (cfree_ar_iter_next(it, &m)) { - EXPECT(m.name[0] != '/' || m.name[1] != '\0', + EXPECT(!cfree_slice_eq_cstr(m.name, "/"), "iter surfaced raw `/` member"); seen++; } @@ -479,7 +474,7 @@ static int test_iter_skips_index(void) { static int test_empty_archive(void) { /* nmembers == 0 with NULL members should produce a magic-only archive. */ BufW bw; - CfreeBytes in; + CfreeSlice in; CfreeArIter* it = NULL; CfreeArMember m; int rc; @@ -490,7 +485,6 @@ static int test_empty_archive(void) { EXPECT(bw.len == 8, "size = %zu", bw.len); EXPECT(memcmp(bw.data, "!<arch>\n", 8) == 0, "magic only"); - in.name = "test"; in.data = bw.data; in.len = bw.len; EXPECT(cfree_ar_iter_new(&g_ctx, &in, &it) == CFREE_OK, "iter_init"); @@ -503,14 +497,14 @@ static int test_empty_archive(void) { static int test_epoch_field(void) { /* opts.epoch is written into ar_date for every member. */ - CfreeBytes ms[1]; + CfreeArInput ms[1]; BufW bw; CfreeArWriteOptions opts = {0}; int rc; - ms[0].name = "x.o"; - ms[0].data = (const uint8_t*)"q"; - ms[0].len = 1; + ms[0].name = CFREE_SLICE_LIT("x.o"); + ms[0].bytes.data = (const uint8_t*)"q"; + ms[0].bytes.len = 1; opts.epoch = 1234567890u; bufw_init(&bw); @@ -534,25 +528,24 @@ static int test_epoch_field(void) { static int test_path_basename(void) { /* Member name with path components is stored as basename only. */ - CfreeBytes ms[1]; + CfreeArInput ms[1]; BufW bw; - CfreeBytes in; + CfreeSlice in; CfreeArIter* it = NULL; CfreeArMember m; - ms[0].name = "src/sub/foo.o"; - ms[0].data = (const uint8_t*)"D"; - ms[0].len = 1; + ms[0].name = CFREE_SLICE_LIT("src/sub/foo.o"); + ms[0].bytes.data = (const uint8_t*)"D"; + ms[0].bytes.len = 1; bufw_init(&bw); EXPECT(cfree_ar_write(&bw.base, ms, 1, NULL) == 0, "write"); - in.name = "test"; in.data = bw.data; in.len = bw.len; EXPECT(cfree_ar_iter_new(&g_ctx, &in, &it) == CFREE_OK, "iter_init"); EXPECT(cfree_ar_iter_next(it, &m), "first"); - EXPECT(strcmp(m.name, "foo.o") == 0, "basename = %s", m.name); + EXPECT(cfree_slice_eq_cstr(m.name, "foo.o"), "basename = %.*s", CFREE_SLICE_ARG(m.name)); cfree_ar_iter_free(it); bufw_fini(&bw); @@ -561,25 +554,24 @@ static int test_path_basename(void) { static int test_truncate_when_long_names_off(void) { /* >15 chars without long_names: name is truncated to 15. */ - CfreeBytes ms[1]; + CfreeArInput ms[1]; BufW bw; - CfreeBytes in; + CfreeSlice in; CfreeArIter* it = NULL; CfreeArMember m; - ms[0].name = "abcdefghijklmnopqrst.o"; /* 22 chars */ - ms[0].data = (const uint8_t*)"D"; - ms[0].len = 1; + ms[0].name = CFREE_SLICE_LIT("abcdefghijklmnopqrst.o"); /* 22 chars */ + ms[0].bytes.data = (const uint8_t*)"D"; + ms[0].bytes.len = 1; bufw_init(&bw); EXPECT(cfree_ar_write(&bw.base, ms, 1, NULL) == 0, "write"); - in.name = "test"; in.data = bw.data; in.len = bw.len; EXPECT(cfree_ar_iter_new(&g_ctx, &in, &it) == CFREE_OK, "iter_init"); EXPECT(cfree_ar_iter_next(it, &m), "first"); - EXPECT(strcmp(m.name, "abcdefghijklmno") == 0, "truncated = %s", m.name); + EXPECT(cfree_slice_eq_cstr(m.name, "abcdefghijklmno"), "truncated = %.*s", CFREE_SLICE_ARG(m.name)); cfree_ar_iter_free(it); bufw_fini(&bw); @@ -588,17 +580,17 @@ static int test_truncate_when_long_names_off(void) { static int test_name_15_char_boundary(void) { /* Exactly 15 chars: fits in-header even with long_names enabled. */ - CfreeBytes ms[1]; + CfreeArInput ms[1]; BufW bw; - CfreeBytes in; + CfreeSlice in; CfreeArIter* it = NULL; CfreeArMember m; CfreeArWriteOptions opts = {0}; opts.long_names = 1; - ms[0].name = "abcdefghijklmno"; /* 15 chars */ - ms[0].data = (const uint8_t*)"X"; - ms[0].len = 1; + ms[0].name = CFREE_SLICE_LIT("abcdefghijklmno"); /* 15 chars */ + ms[0].bytes.data = (const uint8_t*)"X"; + ms[0].bytes.len = 1; bufw_init(&bw); EXPECT(cfree_ar_write(&bw.base, ms, 1, &opts) == 0, "write"); @@ -607,12 +599,11 @@ static int test_name_15_char_boundary(void) { EXPECT(memcmp(bw.data + 8, "abcdefghijklmno/", 16) == 0, "name field = %.16s", (const char*)(bw.data + 8)); - in.name = "test"; in.data = bw.data; in.len = bw.len; EXPECT(cfree_ar_iter_new(&g_ctx, &in, &it) == CFREE_OK, "iter_init"); EXPECT(cfree_ar_iter_next(it, &m), "first"); - EXPECT(strcmp(m.name, "abcdefghijklmno") == 0, "name = %s", m.name); + EXPECT(cfree_slice_eq_cstr(m.name, "abcdefghijklmno"), "name = %.*s", CFREE_SLICE_ARG(m.name)); cfree_ar_iter_free(it); bufw_fini(&bw); @@ -621,28 +612,27 @@ static int test_name_15_char_boundary(void) { static int test_name_16_char_boundary(void) { /* Exactly 16 chars: triggers // long-name table. */ - CfreeBytes ms[1]; + CfreeArInput ms[1]; BufW bw; - CfreeBytes in; + CfreeSlice in; CfreeArIter* it = NULL; CfreeArMember m; CfreeArWriteOptions opts = {0}; opts.long_names = 1; - ms[0].name = "abcdefghijklmnop"; /* 16 chars */ - ms[0].data = (const uint8_t*)"Y"; - ms[0].len = 1; + ms[0].name = CFREE_SLICE_LIT("abcdefghijklmnop"); /* 16 chars */ + ms[0].bytes.data = (const uint8_t*)"Y"; + ms[0].bytes.len = 1; bufw_init(&bw); EXPECT(cfree_ar_write(&bw.base, ms, 1, &opts) == 0, "write"); EXPECT(bw.data[8] == '/' && bw.data[9] == '/', "// header"); - in.name = "test"; in.data = bw.data; in.len = bw.len; EXPECT(cfree_ar_iter_new(&g_ctx, &in, &it) == CFREE_OK, "iter_init"); EXPECT(cfree_ar_iter_next(it, &m), "first"); - EXPECT(strcmp(m.name, "abcdefghijklmnop") == 0, "name = %s", m.name); + EXPECT(cfree_slice_eq_cstr(m.name, "abcdefghijklmnop"), "name = %.*s", CFREE_SLICE_ARG(m.name)); cfree_ar_iter_free(it); bufw_fini(&bw); @@ -651,33 +641,32 @@ static int test_name_16_char_boundary(void) { static int test_empty_member_payload(void) { /* len=0 (data=NULL): header only, no pad; followed by the next member. */ - CfreeBytes ms[2]; + CfreeArInput ms[2]; BufW bw; - CfreeBytes in; + CfreeSlice in; CfreeArIter* it = NULL; CfreeArMember m; - ms[0].name = "empty.o"; - ms[0].data = NULL; - ms[0].len = 0; - ms[1].name = "next.o"; - ms[1].data = (const uint8_t*)"N"; - ms[1].len = 1; + ms[0].name = CFREE_SLICE_LIT("empty.o"); + ms[0].bytes.data = NULL; + ms[0].bytes.len = 0; + ms[1].name = CFREE_SLICE_LIT("next.o"); + ms[1].bytes.data = (const uint8_t*)"N"; + ms[1].bytes.len = 1; bufw_init(&bw); EXPECT(cfree_ar_write(&bw.base, ms, 2, NULL) == 0, "write"); /* magic(8) + hdr(60) + 0 + hdr(60) + 1 + pad(1) = 130 */ EXPECT(bw.len == 130, "size = %zu", bw.len); - in.name = "test"; in.data = bw.data; in.len = bw.len; EXPECT(cfree_ar_iter_new(&g_ctx, &in, &it) == CFREE_OK, "iter_init"); EXPECT(cfree_ar_iter_next(it, &m), "first"); - EXPECT(strcmp(m.name, "empty.o") == 0 && m.size == 0, "empty.o size=%zu", + EXPECT(cfree_slice_eq_cstr(m.name, "empty.o") && m.size == 0, "empty.o size=%zu", m.size); EXPECT(cfree_ar_iter_next(it, &m), "second"); - EXPECT(strcmp(m.name, "next.o") == 0 && m.size == 1 && m.data[0] == 'N', + EXPECT(cfree_slice_eq_cstr(m.name, "next.o") && m.size == 1 && m.data[0] == 'N', "next.o"); EXPECT(!cfree_ar_iter_next(it, &m), "iter end"); @@ -688,18 +677,18 @@ static int test_empty_member_payload(void) { static int test_odd_payload_pad(void) { /* Odd-length payloads add a '\n' parity pad; even lengths do not. */ - CfreeBytes ms[3]; + CfreeArInput ms[3]; BufW bw; - ms[0].name = "a.o"; - ms[0].data = (const uint8_t*)"x"; - ms[0].len = 1; - ms[1].name = "b.o"; - ms[1].data = (const uint8_t*)"yy"; - ms[1].len = 2; - ms[2].name = "c.o"; - ms[2].data = (const uint8_t*)"z"; - ms[2].len = 1; + ms[0].name = CFREE_SLICE_LIT("a.o"); + ms[0].bytes.data = (const uint8_t*)"x"; + ms[0].bytes.len = 1; + ms[1].name = CFREE_SLICE_LIT("b.o"); + ms[1].bytes.data = (const uint8_t*)"yy"; + ms[1].bytes.len = 2; + ms[2].name = CFREE_SLICE_LIT("c.o"); + ms[2].bytes.data = (const uint8_t*)"z"; + ms[2].bytes.len = 1; bufw_init(&bw); EXPECT(cfree_ar_write(&bw.base, ms, 3, NULL) == 0, "write"); @@ -716,28 +705,27 @@ static int test_odd_payload_pad(void) { static int test_ar_list_output(void) { /* cfree_ar_list emits one user member per line, skipping / and //. */ - CfreeBytes ms[3]; + CfreeArInput ms[3]; BufW bw, lw; - CfreeBytes in; + CfreeSlice in; CfreeArWriteOptions opts = {0}; const char* expected = "a.o\nlong_name_member.o\nb.o\n"; opts.symbol_index = 1; opts.long_names = 1; - ms[0].name = "a.o"; - ms[0].data = (const uint8_t*)"A"; - ms[0].len = 1; - ms[1].name = "long_name_member.o"; - ms[1].data = (const uint8_t*)"B"; - ms[1].len = 1; - ms[2].name = "b.o"; - ms[2].data = (const uint8_t*)"C"; - ms[2].len = 1; + ms[0].name = CFREE_SLICE_LIT("a.o"); + ms[0].bytes.data = (const uint8_t*)"A"; + ms[0].bytes.len = 1; + ms[1].name = CFREE_SLICE_LIT("long_name_member.o"); + ms[1].bytes.data = (const uint8_t*)"B"; + ms[1].bytes.len = 1; + ms[2].name = CFREE_SLICE_LIT("b.o"); + ms[2].bytes.data = (const uint8_t*)"C"; + ms[2].bytes.len = 1; bufw_init(&bw); EXPECT(cfree_ar_write(&bw.base, ms, 3, &opts) == 0, "write"); - in.name = "test"; in.data = bw.data; in.len = bw.len; bufw_init(&lw); @@ -755,10 +743,9 @@ static int test_ar_list_output(void) { static int test_iter_bad_magic(void) { /* iter_init must reject non-ar inputs. */ static const uint8_t bad[] = "NOT-AN-AR"; - CfreeBytes in; + CfreeSlice in; CfreeArIter* it = NULL; - in.name = "bad"; in.data = bad; in.len = sizeof(bad) - 1; EXPECT(cfree_ar_iter_new(&g_ctx, &in, &it) != CFREE_OK, @@ -777,10 +764,10 @@ static int test_iter_bad_magic(void) { static int test_write_invalid_args(void) { /* Bad argument combinations must return 1 from cfree_ar_write. */ - CfreeBytes ms[1]; + CfreeArInput ms[1]; BufW bw; CfreeArWriteOptions opts = {0}; - const char* bad_syms[1]; + CfreeSlice bad_syms[1]; CfreeArMemberSymbols msyms[1]; bufw_init(&bw); @@ -789,18 +776,18 @@ static int test_write_invalid_args(void) { EXPECT(cfree_ar_write(&bw.base, NULL, 1, NULL) != CFREE_OK, "NULL members with nmembers>0 rejected"); - ms[0].name = NULL; - ms[0].data = (const uint8_t*)"X"; - ms[0].len = 1; + ms[0].name = CFREE_SLICE_NULL; + ms[0].bytes.data = (const uint8_t*)"X"; + ms[0].bytes.len = 1; EXPECT(cfree_ar_write(&bw.base, ms, 1, NULL) != CFREE_OK, "NULL name rejected"); /* NULL symbol-name with nonzero count. */ - bad_syms[0] = NULL; - msyms[0].names = (const char* const*)bad_syms; + bad_syms[0] = CFREE_SLICE_NULL; + msyms[0].names = bad_syms; msyms[0].count = 1; opts.symbol_index = 1; opts.member_symbols = msyms; - ms[0].name = "ok.o"; + ms[0].name = CFREE_SLICE_LIT("ok.o"); EXPECT(cfree_ar_write(&bw.base, ms, 1, &opts) != CFREE_OK, "NULL symbol name rejected"); @@ -813,7 +800,7 @@ static int test_iter_skips_bsd_symdef(void) { * iterator must not surface it. (cfree_ar_write never emits BSD indexes, * but the iterator is documented to handle them on read.) */ BufW bw; - CfreeBytes in; + CfreeSlice in; CfreeArIter* it = NULL; CfreeArMember m; char hdr[60]; @@ -859,12 +846,11 @@ static int test_iter_skips_bsd_symdef(void) { bw.base.write(&bw.base, hdr, 60); bw.base.write(&bw.base, "U\n", 2); - in.name = "bsd"; in.data = bw.data; in.len = bw.len; EXPECT(cfree_ar_iter_new(&g_ctx, &in, &it) == CFREE_OK, "iter_init"); while (cfree_ar_iter_next(it, &m)) { - EXPECT(strcmp(m.name, "u.o") == 0, "unexpected name = %s", m.name); + EXPECT(cfree_slice_eq_cstr(m.name, "u.o"), "unexpected name = %.*s", CFREE_SLICE_ARG(m.name)); seen++; } EXPECT(seen == 1, "saw %d members", seen); @@ -876,20 +862,19 @@ static int test_iter_skips_bsd_symdef(void) { static int test_iter_data_aliases_archive(void) { /* CfreeArMember.data must point into the archive's own bytes. */ - CfreeBytes ms[1]; + CfreeArInput ms[1]; BufW bw; - CfreeBytes in; + CfreeSlice in; CfreeArIter* it = NULL; CfreeArMember m; - ms[0].name = "a.o"; - ms[0].data = (const uint8_t*)"PAYLOAD"; - ms[0].len = 7; + ms[0].name = CFREE_SLICE_LIT("a.o"); + ms[0].bytes.data = (const uint8_t*)"PAYLOAD"; + ms[0].bytes.len = 7; bufw_init(&bw); EXPECT(cfree_ar_write(&bw.base, ms, 1, NULL) == 0, "write"); - in.name = "test"; in.data = bw.data; in.len = bw.len; EXPECT(cfree_ar_iter_new(&g_ctx, &in, &it) == CFREE_OK, "iter_init"); @@ -906,9 +891,9 @@ static int test_iter_data_aliases_archive(void) { static int test_symbol_index_partial_members(void) { /* Members with 0 symbols mid-list: cur_offset must still advance for * every member so later offsets land on the right header. */ - const char* mid_syms[] = {"midsym"}; + CfreeSlice mid_syms[] = {CFREE_SLICE_LIT("midsym")}; CfreeArMemberSymbols msyms[3]; - CfreeBytes ms[3]; + CfreeArInput ms[3]; BufW bw; CfreeArWriteOptions opts = {0}; uint32_t nsyms, off; @@ -917,21 +902,21 @@ static int test_symbol_index_partial_members(void) { opts.symbol_index = 1; msyms[0].names = NULL; msyms[0].count = 0; - msyms[1].names = (const char* const*)mid_syms; + msyms[1].names = mid_syms; msyms[1].count = 1; msyms[2].names = NULL; msyms[2].count = 0; opts.member_symbols = msyms; - ms[0].name = "a.o"; - ms[0].data = (const uint8_t*)"AA"; - ms[0].len = 2; - ms[1].name = "b.o"; - ms[1].data = (const uint8_t*)"BB"; - ms[1].len = 2; - ms[2].name = "c.o"; - ms[2].data = (const uint8_t*)"CC"; - ms[2].len = 2; + ms[0].name = CFREE_SLICE_LIT("a.o"); + ms[0].bytes.data = (const uint8_t*)"AA"; + ms[0].bytes.len = 2; + ms[1].name = CFREE_SLICE_LIT("b.o"); + ms[1].bytes.data = (const uint8_t*)"BB"; + ms[1].bytes.len = 2; + ms[2].name = CFREE_SLICE_LIT("c.o"); + ms[2].bytes.data = (const uint8_t*)"CC"; + ms[2].bytes.len = 2; bufw_init(&bw); EXPECT(cfree_ar_write(&bw.base, ms, 3, &opts) == 0, "write"); diff --git a/test/arch/aa64_inline_test.c b/test/arch/aa64_inline_test.c @@ -119,7 +119,7 @@ int main(void) { ObjBuilder* ob = obj_new(c); Pool* pool = c->global; - ObjSecId text_sec = obj_section(ob, pool_intern_cstr(pool, ".text"), + ObjSecId text_sec = obj_section(ob, pool_intern_slice(pool, SLICE_LIT(".text")), SEC_TEXT, SF_EXEC | SF_ALLOC, 4); MCEmitter* mc = mc_new(c, ob); mc->set_section(mc, text_sec); @@ -139,7 +139,7 @@ int main(void) { in_ops[0].v.reg = 9; /* x9 */ Sym clobs[1]; - clobs[0] = pool_intern_cstr(pool, "x0"); + clobs[0] = pool_intern_slice(pool, SLICE_LIT("x0")); u32 start = mc->pos(mc); target->asm_block(target, "mov w0, %w0; svc #0", diff --git a/test/arch/aa64_isa_test.c b/test/arch/aa64_isa_test.c @@ -28,9 +28,9 @@ static void check(u32 word, const char* want_mnem, const char* want_ops_substr) ++fails; return; } - if (strcmp(d->mnemonic, want_mnem) != 0) { - fprintf(stderr, "FAIL 0x%08x: mnemonic = %s, want %s\n", word, d->mnemonic, - want_mnem); + if (!slice_eq_cstr(d->mnemonic, want_mnem)) { + fprintf(stderr, "FAIL 0x%08x: mnemonic = %.*s, want %s\n", word, + SLICE_ARG(d->mnemonic), want_mnem); ++fails; return; } @@ -175,10 +175,10 @@ int main(void) { /* ORR X1, XZR, X2 with shift=0,imm6=0 should resolve to "mov", not "orr". */ u32 w = aa64_mov_reg(1, 1, 2); const AA64InsnDesc* d = aa64_disasm_find(w); - if (d == NULL || strcmp(d->mnemonic, "mov") != 0) { + if (d == NULL || !slice_eq_cstr(d->mnemonic, "mov")) { fprintf(stderr, - "FAIL: alias precedence — ORR-as-MOV resolved to %s (want mov)\n", - d ? d->mnemonic : "(null)"); + "FAIL: alias precedence — ORR-as-MOV resolved to %.*s (want mov)\n", + SLICE_ARG(d ? d->mnemonic : SLICE_LIT("(null)"))); ++fails; } else if (!(d->flags & AA64_ASMFL_ALIAS)) { fprintf(stderr, "FAIL: alias precedence — resolved row missing ALIAS\n"); @@ -191,10 +191,10 @@ int main(void) { { u32 w = aa64_orr(1, 1, 3, 2); const AA64InsnDesc* d = aa64_disasm_find(w); - if (d == NULL || strcmp(d->mnemonic, "orr") != 0) { + if (d == NULL || !slice_eq_cstr(d->mnemonic, "orr")) { fprintf(stderr, - "FAIL: non-alias ORR resolved to %s (want orr)\n", - d ? d->mnemonic : "(null)"); + "FAIL: non-alias ORR resolved to %.*s (want orr)\n", + SLICE_ARG(d ? d->mnemonic : SLICE_LIT("(null)"))); ++fails; } ++cases; diff --git a/test/arch/rv64_inline_test.c b/test/arch/rv64_inline_test.c @@ -103,7 +103,7 @@ int main(void) { ObjBuilder* ob = obj_new(c); Pool* pool = c->global; - ObjSecId text_sec = obj_section(ob, pool_intern_cstr(pool, ".text"), + ObjSecId text_sec = obj_section(ob, pool_intern_slice(pool, SLICE_LIT(".text")), SEC_TEXT, SF_EXEC | SF_ALLOC, 4); MCEmitter* mc = mc_new(c, ob); mc->set_section(mc, text_sec); @@ -248,7 +248,7 @@ int main(void) { { AsmConstraint outs[1] = {{0}}; outs[0].str = "=r"; - outs[0].name = pool_intern_cstr(pool, "sum"); + outs[0].name = pool_intern_slice(pool, SLICE_LIT("sum")); outs[0].dir = ASM_OUT; Operand out_ops[1]; memset(out_ops, 0, sizeof out_ops); @@ -258,10 +258,10 @@ int main(void) { AsmConstraint ins[2] = {{0}, {0}}; ins[0].str = "r"; - ins[0].name = pool_intern_cstr(pool, "x"); + ins[0].name = pool_intern_slice(pool, SLICE_LIT("x")); ins[0].dir = ASM_IN; ins[1].str = "r"; - ins[1].name = pool_intern_cstr(pool, "y"); + ins[1].name = pool_intern_slice(pool, SLICE_LIT("y")); ins[1].dir = ASM_IN; Operand in_ops[2]; memset(in_ops, 0, sizeof in_ops); @@ -324,7 +324,7 @@ int main(void) { * callee-saved bookkeeping but accepted by the walker. ---- */ { Sym clobs[1]; - clobs[0] = pool_intern_cstr(pool, "memory"); + clobs[0] = pool_intern_slice(pool, SLICE_LIT("memory")); u32 start = mc->pos(mc); target->asm_block(target, "fence rw, rw", NULL, 0, NULL, NULL, 0, NULL, clobs, 1); diff --git a/test/arch/x64_inline_test.c b/test/arch/x64_inline_test.c @@ -127,7 +127,7 @@ int main(void) { ObjBuilder* ob = obj_new(c); Pool* pool = c->global; - ObjSecId text_sec = obj_section(ob, pool_intern_cstr(pool, ".text"), + ObjSecId text_sec = obj_section(ob, pool_intern_slice(pool, SLICE_LIT(".text")), SEC_TEXT, SF_EXEC | SF_ALLOC, 16); MCEmitter* mc = mc_new(c, ob); mc->set_section(mc, text_sec); @@ -399,7 +399,7 @@ int main(void) { AsmConstraint outs[1] = {{0}}; outs[0].str = "=r"; outs[0].dir = ASM_OUT; - outs[0].name = pool_intern_cstr(pool, "dst"); + outs[0].name = pool_intern_slice(pool, SLICE_LIT("dst")); Operand out_ops[1]; memset(out_ops, 0, sizeof out_ops); out_ops[0].kind = OPK_REG; @@ -410,7 +410,7 @@ int main(void) { AsmConstraint ins[1] = {{0}}; ins[0].str = "r"; ins[0].dir = ASM_IN; - ins[0].name = pool_intern_cstr(pool, "src"); + ins[0].name = pool_intern_slice(pool, SLICE_LIT("src")); Operand in_ops[1]; memset(in_ops, 0, sizeof in_ops); in_ops[0].kind = OPK_REG; diff --git a/test/asm/harness/asm_runner.c b/test/asm/harness/asm_runner.c @@ -262,7 +262,7 @@ static void target_from_env(CfreeTarget* t) { static CfreeStatus compile_asm_obj(CfreeCompiler* c, const CfreeAsmCompileOptions* opts, - const CfreeBytes* in, + CfreeSlice name, const CfreeSlice* in, CfreeObjBuilder** out) { CfreeCompileSessionOptions sopts; CfreeCompileSession* session = NULL; @@ -274,6 +274,7 @@ static CfreeStatus compile_asm_obj(CfreeCompiler* c, sopts.compile.diagnostics = opts->diagnostics; sopts.compile.language_options = opts; memset(&sin, 0, sizeof(sin)); + sin.name = name; sin.bytes = *in; sin.lang = CFREE_LANG_ASM; st = cfree_compile_session_new(c, &sopts, &session); @@ -284,9 +285,10 @@ static CfreeStatus compile_asm_obj(CfreeCompiler* c, static CfreeStatus compile_asm_emit(CfreeCompiler* c, const CfreeAsmCompileOptions* opts, - const CfreeBytes* in, CfreeWriter* w) { + CfreeSlice name, const CfreeSlice* in, + CfreeWriter* w) { CfreeObjBuilder* ob = NULL; - CfreeStatus st = compile_asm_obj(c, opts, in, &ob); + CfreeStatus st = compile_asm_obj(c, opts, name, in, &ob); if (st == CFREE_OK) st = cfree_obj_builder_emit(ob, w); cfree_obj_builder_free(ob); return st; @@ -300,7 +302,7 @@ static CfreeStatus link_one_obj_jit(CfreeCompiler* c, CfreeObjBuilder* ob, CfreeStatus st; memset(&opts, 0, sizeof(opts)); opts.output_kind = CFREE_LINK_OUTPUT_JIT; - opts.entry = entry; + opts.entry = cfree_slice_cstr(entry); opts.jit_host = host; st = cfree_link_session_new(c, &opts, &link); if (st == CFREE_OK) st = cfree_link_session_add_obj(link, ob); @@ -421,13 +423,13 @@ static int mode_encode(const char* src_path, const char* out_path) { CfreeTarget tgt; CfreeContext ctx; CfreeCompiler* c = NULL; - CfreeBytes in; + CfreeSlice in; CfreeAsmCompileOptions opts; CfreeWriter* w = NULL; const uint8_t* obj_bytes; size_t obj_len = 0; CfreeObjFile* of = NULL; - CfreeBytes obj_in; + CfreeSlice obj_in; uint32_t nsec, i; uint8_t* hex = NULL; size_t hex_len = 0; @@ -445,13 +447,13 @@ static int mode_encode(const char* src_path, const char* out_path) { } memset(&in, 0, sizeof in); - in.name = src_path; in.data = src; in.len = src_len; memset(&opts, 0, sizeof opts); (void)cfree_writer_mem(&g_heap, &w); - if (compile_asm_emit(c, &opts, &in, w) != CFREE_OK) { + if (compile_asm_emit(c, &opts, cfree_slice_cstr(src_path), &in, w) != + CFREE_OK) { cfree_writer_close(w); cfree_compiler_free(c); free(src); @@ -460,10 +462,11 @@ static int mode_encode(const char* src_path, const char* out_path) { obj_bytes = cfree_writer_mem_bytes(w, &obj_len); memset(&obj_in, 0, sizeof obj_in); - obj_in.name = src_path; obj_in.data = obj_bytes; obj_in.len = obj_len; - if (cfree_obj_open(&ctx, &obj_in, &of) != CFREE_OK || !of) { + if (cfree_obj_open(&ctx, cfree_slice_cstr(src_path), &obj_in, &of) != + CFREE_OK || + !of) { cfree_writer_close(w); cfree_compiler_free(c); free(src); @@ -575,13 +578,13 @@ static int mode_decode(const char* in_path, const char* out_path) { for (;;) { CfreeIterResult r = cfree_disasm_iter_next(it, &ins); if (r != CFREE_ITER_ITEM) break; - fprintf(out, "%llx:\t%s", (unsigned long long)ins.vaddr, - ins.mnemonic ? ins.mnemonic : ""); - if (ins.operands && ins.operands[0]) { - fprintf(out, "\t%s", ins.operands); + fprintf(out, "%llx:\t%.*s", (unsigned long long)ins.vaddr, + CFREE_SLICE_ARG(ins.mnemonic)); + if (ins.operands.len) { + fprintf(out, "\t%.*s", CFREE_SLICE_ARG(ins.operands)); } - if (ins.annotation && ins.annotation[0]) { - fprintf(out, " ; %s", ins.annotation); + if (ins.annotation.len) { + fprintf(out, " ; %.*s", CFREE_SLICE_ARG(ins.annotation)); } fputc('\n', out); } @@ -603,7 +606,7 @@ static int mode_listing(const char* in_path, const char* out_path) { CfreeTarget tgt; CfreeContext ctx; CfreeCompiler* c = NULL; - CfreeBytes in; + CfreeSlice in; CfreeWriter* w = NULL; const uint8_t* data; size_t len = 0; @@ -621,7 +624,6 @@ static int mode_listing(const char* in_path, const char* out_path) { } memset(&in, 0, sizeof in); - in.name = in_path; in.data = bytes; in.len = nbytes; @@ -650,7 +652,7 @@ static int mode_emit(const char* src_path, const char* out_path) { CfreeTarget tgt; CfreeContext ctx; CfreeCompiler* c = NULL; - CfreeBytes in; + CfreeSlice in; CfreeAsmCompileOptions opts; CfreeWriter* w = NULL; int rc = 0; @@ -669,13 +671,13 @@ static int mode_emit(const char* src_path, const char* out_path) { } memset(&in, 0, sizeof in); - in.name = src_path; in.data = src; in.len = src_len; memset(&opts, 0, sizeof opts); (void)cfree_writer_mem(&g_heap, &w); - if (compile_asm_emit(c, &opts, &in, w) != CFREE_OK) { + if (compile_asm_emit(c, &opts, cfree_slice_cstr(src_path), &in, w) != + CFREE_OK) { cfree_writer_close(w); cfree_compiler_free(c); free(src); @@ -707,7 +709,7 @@ static int mode_jit(const char* src_path) { CfreeTarget tgt; CfreeContext ctx; CfreeCompiler* c = NULL; - CfreeBytes in; + CfreeSlice in; CfreeAsmCompileOptions opts; CfreeObjBuilder* ob = NULL; CfreeJitHost jhost; @@ -727,12 +729,13 @@ static int mode_jit(const char* src_path) { } memset(&in, 0, sizeof in); - in.name = src_path; in.data = src; in.len = src_len; memset(&opts, 0, sizeof opts); - if (compile_asm_obj(c, &opts, &in, &ob) != CFREE_OK || !ob) { + if (compile_asm_obj(c, &opts, cfree_slice_cstr(src_path), &in, &ob) != + CFREE_OK || + !ob) { cfree_compiler_free(c); free(src); return 1; @@ -747,14 +750,14 @@ static int mode_jit(const char* src_path) { return 1; } - fn = (int (*)(void))cfree_jit_lookup(jit, "test_main"); + fn = (int (*)(void))cfree_jit_lookup(jit, CFREE_SLICE_LIT("test_main")); #if defined(__aarch64__) || defined(__arm64__) { - char* td_start = (char*)cfree_jit_lookup(jit, "__tdata_start"); - char* td_end = (char*)cfree_jit_lookup(jit, "__tdata_end"); + char* td_start = (char*)cfree_jit_lookup(jit, CFREE_SLICE_LIT("__tdata_start")); + char* td_end = (char*)cfree_jit_lookup(jit, CFREE_SLICE_LIT("__tdata_end")); unsigned long bs_n = - (unsigned long)(unsigned long long)cfree_jit_lookup(jit, "__tbss_size"); + (unsigned long)(unsigned long long)cfree_jit_lookup(jit, CFREE_SLICE_LIT("__tbss_size")); if (td_start && td_end) { unsigned long td_n = (unsigned long)(td_end - td_start); unsigned long i; diff --git a/test/coff/cfree-roundtrip-coff.c b/test/coff/cfree-roundtrip-coff.c @@ -103,10 +103,9 @@ static void target_aa64_windows(CfreeTarget* t) { /* ---- shape helpers ------------------------------------------------- */ static int sym_eq_str(Pool* p, Sym s, const char* want) { - size_t len; - const char* got = pool_str(p, s, &len); + Slice got = pool_slice(p, s); size_t wlen = strlen(want); - return got && len == wlen && memcmp(got, want, len) == 0; + return got.s && got.len == wlen && memcmp(got.s, want, got.len) == 0; } static const Section* find_section_named(const ObjBuilder* ob, Pool* p, @@ -310,7 +309,7 @@ static void test_header_minimal_x64(void) { } ObjBuilder* ob = obj_new(c); Pool* p = c->global; - Sym text = pool_intern_cstr(p, ".text"); + Sym text = pool_intern_slice(p, SLICE_LIT(".text")); ObjSecId sec = obj_section(ob, text, SEC_TEXT, SF_ALLOC | SF_EXEC, 16); obj_write(ob, sec, TEXT_X64, sizeof TEXT_X64); obj_finalize(ob); @@ -337,7 +336,7 @@ static void test_header_minimal_aa64(void) { } ObjBuilder* ob = obj_new(c); Pool* p = c->global; - Sym text = pool_intern_cstr(p, ".text"); + Sym text = pool_intern_slice(p, SLICE_LIT(".text")); ObjSecId sec = obj_section(ob, text, SEC_TEXT, SF_ALLOC | SF_EXEC, 4); obj_write(ob, sec, TEXT_AA64, sizeof TEXT_AA64); obj_finalize(ob); @@ -380,8 +379,8 @@ static void test_text_only_x64(void) { } ObjBuilder* ob = obj_new(c); Pool* p = c->global; - Sym tn = pool_intern_cstr(p, ".text"); - Sym mn = pool_intern_cstr(p, "main"); + Sym tn = pool_intern_slice(p, SLICE_LIT(".text")); + Sym mn = pool_intern_slice(p, SLICE_LIT("main")); ObjSecId sec = obj_section(ob, tn, SEC_TEXT, SF_ALLOC | SF_EXEC, 16); obj_write(ob, sec, TEXT_X64, sizeof TEXT_X64); obj_symbol(ob, mn, SB_GLOBAL, SK_FUNC, sec, 0, sizeof TEXT_X64); @@ -410,8 +409,8 @@ static void test_text_only_aa64(void) { } ObjBuilder* ob = obj_new(c); Pool* p = c->global; - Sym tn = pool_intern_cstr(p, ".text"); - Sym mn = pool_intern_cstr(p, "main"); + Sym tn = pool_intern_slice(p, SLICE_LIT(".text")); + Sym mn = pool_intern_slice(p, SLICE_LIT("main")); ObjSecId sec = obj_section(ob, tn, SEC_TEXT, SF_ALLOC | SF_EXEC, 4); obj_write(ob, sec, TEXT_AA64, sizeof TEXT_AA64); obj_symbol(ob, mn, SB_GLOBAL, SK_FUNC, sec, 0, sizeof TEXT_AA64); @@ -455,8 +454,8 @@ static void test_rodata(void) { } ObjBuilder* ob = obj_new(c); Pool* p = c->global; - Sym rdn = pool_intern_cstr(p, ".rdata"); - Sym kn = pool_intern_cstr(p, "kMsg"); + Sym rdn = pool_intern_slice(p, SLICE_LIT(".rdata")); + Sym kn = pool_intern_slice(p, SLICE_LIT("kMsg")); ObjSecId sec = obj_section(ob, rdn, SEC_RODATA, SF_ALLOC, 8); static const uint8_t MSG[12] = "hello world\0"; obj_write(ob, sec, MSG, sizeof MSG); @@ -497,8 +496,8 @@ static void test_bss(void) { } ObjBuilder* ob = obj_new(c); Pool* p = c->global; - Sym bn = pool_intern_cstr(p, ".bss"); - Sym vn = pool_intern_cstr(p, "g_buf"); + Sym bn = pool_intern_slice(p, SLICE_LIT(".bss")); + Sym vn = pool_intern_slice(p, SLICE_LIT("g_buf")); ObjSecId sec = obj_section_ex(ob, bn, SEC_BSS, SSEM_NOBITS, SF_ALLOC | SF_WRITE, 16, 0, 0, 0); obj_reserve_bss(ob, sec, 64, 16); @@ -561,8 +560,8 @@ static void test_data_with_reloc_abs64_x64(void) { } ObjBuilder* ob = obj_new(c); Pool* p = c->global; - Sym dn = pool_intern_cstr(p, ".data"); - Sym fn = pool_intern_cstr(p, "foo_extern"); + Sym dn = pool_intern_slice(p, SLICE_LIT(".data")); + Sym fn = pool_intern_slice(p, SLICE_LIT("foo_extern")); ObjSecId sec = obj_section(ob, dn, SEC_DATA, SF_ALLOC | SF_WRITE, 8); static const uint8_t zero8[8] = {0}; obj_write(ob, sec, zero8, sizeof zero8); @@ -593,8 +592,8 @@ static void test_data_with_reloc_abs64_aa64(void) { } ObjBuilder* ob = obj_new(c); Pool* p = c->global; - Sym dn = pool_intern_cstr(p, ".data"); - Sym fn = pool_intern_cstr(p, "foo_extern"); + Sym dn = pool_intern_slice(p, SLICE_LIT(".data")); + Sym fn = pool_intern_slice(p, SLICE_LIT("foo_extern")); ObjSecId sec = obj_section(ob, dn, SEC_DATA, SF_ALLOC | SF_WRITE, 8); static const uint8_t zero8[8] = {0}; obj_write(ob, sec, zero8, sizeof zero8); @@ -646,8 +645,8 @@ static void test_data_with_reloc_rel32_x64(void) { } ObjBuilder* ob = obj_new(c); Pool* p = c->global; - Sym tn = pool_intern_cstr(p, ".text"); - Sym hn = pool_intern_cstr(p, "helper"); + Sym tn = pool_intern_slice(p, SLICE_LIT(".text")); + Sym hn = pool_intern_slice(p, SLICE_LIT("helper")); ObjSecId sec = obj_section(ob, tn, SEC_TEXT, SF_ALLOC | SF_EXEC, 16); /* call helper ; ret — e8 disp32 c3 (disp filled by reloc). */ static const uint8_t bytes[6] = {0xe8, 0, 0, 0, 0, 0xc3}; @@ -703,8 +702,8 @@ static void test_aa64_branch26(void) { } ObjBuilder* ob = obj_new(c); Pool* p = c->global; - Sym tn = pool_intern_cstr(p, ".text"); - Sym cn = pool_intern_cstr(p, "callee"); + Sym tn = pool_intern_slice(p, SLICE_LIT(".text")); + Sym cn = pool_intern_slice(p, SLICE_LIT("callee")); ObjSecId sec = obj_section(ob, tn, SEC_TEXT, SF_ALLOC | SF_EXEC, 4); /* bl callee ; ret — both 4 bytes; disp filled by reloc. */ static const uint8_t bytes[8] = {0, 0, 0, 0x94, 0xc0, 0x03, 0x5f, 0xd6}; @@ -757,9 +756,9 @@ static void test_aa64_pagebase_pageoffset(void) { } ObjBuilder* ob = obj_new(c); Pool* p = c->global; - Sym tn = pool_intern_cstr(p, ".text"); - Sym rdn = pool_intern_cstr(p, ".rdata"); - Sym kn = pool_intern_cstr(p, "kStr"); + Sym tn = pool_intern_slice(p, SLICE_LIT(".text")); + Sym rdn = pool_intern_slice(p, SLICE_LIT(".rdata")); + Sym kn = pool_intern_slice(p, SLICE_LIT("kStr")); ObjSecId tsec = obj_section(ob, tn, SEC_TEXT, SF_ALLOC | SF_EXEC, 4); ObjSecId rsec = obj_section(ob, rdn, SEC_RODATA, SF_ALLOC, 8); /* adrp x0, kStr ; add x0, x0, :lo12:kStr ; ret. */ @@ -807,7 +806,7 @@ static void test_long_section_name(void) { } ObjBuilder* ob = obj_new(c); Pool* p = c->global; - Sym nm = pool_intern_cstr(p, ".text$long_name_section"); + Sym nm = pool_intern_slice(p, SLICE_LIT(".text$long_name_section")); ObjSecId sec = obj_section(ob, nm, SEC_TEXT, SF_ALLOC | SF_EXEC, 16); obj_write(ob, sec, TEXT_X64, sizeof TEXT_X64); obj_finalize(ob); @@ -848,8 +847,8 @@ static void test_long_symbol_name(void) { } ObjBuilder* ob = obj_new(c); Pool* p = c->global; - Sym tn = pool_intern_cstr(p, ".text"); - Sym sn = pool_intern_cstr(p, "very_long_symbol_name"); + Sym tn = pool_intern_slice(p, SLICE_LIT(".text")); + Sym sn = pool_intern_slice(p, SLICE_LIT("very_long_symbol_name")); ObjSecId sec = obj_section(ob, tn, SEC_TEXT, SF_ALLOC | SF_EXEC, 16); obj_write(ob, sec, TEXT_X64, sizeof TEXT_X64); obj_symbol(ob, sn, SB_GLOBAL, SK_FUNC, sec, 0, sizeof TEXT_X64); @@ -891,8 +890,8 @@ static void test_weak_global(void) { } ObjBuilder* ob = obj_new(c); Pool* p = c->global; - Sym tn = pool_intern_cstr(p, ".text"); - Sym wn = pool_intern_cstr(p, "weak_sym"); + Sym tn = pool_intern_slice(p, SLICE_LIT(".text")); + Sym wn = pool_intern_slice(p, SLICE_LIT("weak_sym")); ObjSecId sec = obj_section(ob, tn, SEC_TEXT, SF_ALLOC | SF_EXEC, 16); obj_write(ob, sec, TEXT_X64, sizeof TEXT_X64); obj_symbol(ob, wn, SB_WEAK, SK_FUNC, sec, 0, sizeof TEXT_X64); @@ -936,7 +935,7 @@ static void test_common_symbol(void) { } ObjBuilder* ob = obj_new(c); Pool* p = c->global; - Sym cn = pool_intern_cstr(p, "common_var"); + Sym cn = pool_intern_slice(p, SLICE_LIT("common_var")); obj_symbol_ex(ob, cn, SB_GLOBAL, SV_DEFAULT, SK_COMMON, OBJ_SEC_NONE, 0, 128, 1); obj_finalize(ob); @@ -1003,9 +1002,9 @@ static void test_comdat_group(void) { * symbol's name is truncated on emit but the reader compares the * resolved long name. See CORPUS.md §10 / src/obj/coff_read.c * is_section_sym logic. */ - Sym tn = pool_intern_cstr(p, ".text$x"); - Sym dn = pool_intern_cstr(p, ".data$x"); - Sym sign = pool_intern_cstr(p, "inline_fn"); + Sym tn = pool_intern_slice(p, SLICE_LIT(".text$x")); + Sym dn = pool_intern_slice(p, SLICE_LIT(".data$x")); + Sym sign = pool_intern_slice(p, SLICE_LIT("inline_fn")); ObjSecId tsec = obj_section(ob, tn, SEC_TEXT, SF_ALLOC | SF_EXEC | SF_GROUP, 16); @@ -1060,8 +1059,8 @@ static void test_static_local_symbol(void) { } ObjBuilder* ob = obj_new(c); Pool* p = c->global; - Sym tn = pool_intern_cstr(p, ".text"); - Sym ln = pool_intern_cstr(p, "local_fn"); + Sym tn = pool_intern_slice(p, SLICE_LIT(".text")); + Sym ln = pool_intern_slice(p, SLICE_LIT("local_fn")); ObjSecId sec = obj_section(ob, tn, SEC_TEXT, SF_ALLOC | SF_EXEC, 16); obj_write(ob, sec, TEXT_X64, sizeof TEXT_X64); obj_symbol(ob, ln, SB_LOCAL, SK_FUNC, sec, 0, sizeof TEXT_X64); @@ -1113,17 +1112,17 @@ static void test_section_symbol_synthesis(void) { ObjBuilder* ob = obj_new(c); Pool* p = c->global; - ObjSecId text = obj_section(ob, pool_intern_cstr(p, ".text"), SEC_TEXT, + ObjSecId text = obj_section(ob, pool_intern_slice(p, SLICE_LIT(".text")), SEC_TEXT, SF_ALLOC | SF_EXEC, 16); obj_write(ob, text, TEXT_X64, sizeof TEXT_X64); - ObjSecId data = obj_section(ob, pool_intern_cstr(p, ".data"), SEC_DATA, + ObjSecId data = obj_section(ob, pool_intern_slice(p, SLICE_LIT(".data")), SEC_DATA, SF_ALLOC | SF_WRITE, 8); static const uint8_t z8[8] = {0}; obj_write(ob, data, z8, sizeof z8); - ObjSecId rdata = obj_section(ob, pool_intern_cstr(p, ".rdata"), SEC_RODATA, + ObjSecId rdata = obj_section(ob, pool_intern_slice(p, SLICE_LIT(".rdata")), SEC_RODATA, SF_ALLOC, 8); obj_write(ob, rdata, "hi\0", 3); - ObjSecId bss = obj_section_ex(ob, pool_intern_cstr(p, ".bss"), SEC_BSS, + ObjSecId bss = obj_section_ex(ob, pool_intern_slice(p, SLICE_LIT(".bss")), SEC_BSS, SSEM_NOBITS, SF_ALLOC | SF_WRITE, 8, 0, 0, 0); obj_reserve_bss(ob, bss, 16, 8); @@ -1164,8 +1163,8 @@ static void test_tls_section(void) { } ObjBuilder* ob = obj_new(c); Pool* p = c->global; - Sym nm = pool_intern_cstr(p, ".tls$"); - Sym vn = pool_intern_cstr(p, "tls_var"); + Sym nm = pool_intern_slice(p, SLICE_LIT(".tls$")); + Sym vn = pool_intern_slice(p, SLICE_LIT("tls_var")); ObjSecId sec = obj_section(ob, nm, SEC_DATA, SF_ALLOC | SF_WRITE | SF_TLS, 8); static const uint8_t z8[8] = {0}; obj_write(ob, sec, z8, sizeof z8); @@ -1206,7 +1205,7 @@ static void test_align_nibble(void) { } ObjBuilder* ob = obj_new(c); Pool* p = c->global; - Sym nm = pool_intern_cstr(p, ".rdata"); + Sym nm = pool_intern_slice(p, SLICE_LIT(".rdata")); ObjSecId sec = obj_section(ob, nm, SEC_RODATA, SF_ALLOC, 4096); static const uint8_t z[16] = {0}; obj_write(ob, sec, z, sizeof z); diff --git a/test/coff/pe-dso-forwarder.c b/test/coff/pe-dso-forwarder.c @@ -236,7 +236,7 @@ static void build_dso(uint8_t* buf) { /* ---- main --------------------------------------------------------- */ static int has_sym(const ObjBuilder* ob, Pool* p, const char* name) { - Sym needle = pool_intern_cstr(p, name); + Sym needle = pool_intern_slice(p, slice_from_cstr(name)); ObjSymIter* it = obj_symiter_new(ob); ObjSymEntry e; int found = 0; @@ -279,7 +279,7 @@ int main(void) { EXPECT(ob != NULL, "read_coff_dso returned NULL"); /* soname propagated from the Export Directory's Name field. */ - Sym expected_soname = pool_intern_cstr(c->global, kDllName); + Sym expected_soname = pool_intern_slice(c->global, slice_from_cstr(kDllName)); EXPECT(soname == expected_soname, "soname mismatch (expected interned \"%s\")", kDllName); diff --git a/test/coff/pe-import-mingw.c b/test/coff/pe-import-mingw.c @@ -118,9 +118,9 @@ static Compiler* make_compiler(const CfreeTarget* t) { static ObjBuilder* build_program(Compiler* c) { ObjBuilder* ob = obj_new(c); Pool* p = c->global; - Sym text_name = pool_intern_cstr(p, ".text"); - Sym main_name = pool_intern_cstr(p, "mainCRTStartup"); - Sym exit_name = pool_intern_cstr(p, MINGW_IMPORT_FN); + Sym text_name = pool_intern_slice(p, SLICE_LIT(".text")); + Sym main_name = pool_intern_slice(p, SLICE_LIT("mainCRTStartup")); + Sym exit_name = pool_intern_slice(p, SLICE_LIT(MINGW_IMPORT_FN)); ObjSecId text = obj_section(ob, text_name, SEC_TEXT, SF_ALLOC | SF_EXEC, 16); obj_write(ob, text, PROG_TEXT_X64, sizeof PROG_TEXT_X64); @@ -282,7 +282,7 @@ int main(void) { /* Sanity: ExitProcess should be present and marked imported. */ { - Sym exit_name = pool_intern_cstr(c->global, MINGW_IMPORT_FN); + Sym exit_name = pool_intern_slice(c->global, SLICE_LIT(MINGW_IMPORT_FN)); const LinkSymbol* found = NULL; for (LinkSymId i = 1;; ++i) { const LinkSymbol* s = link_symbol(img, i); diff --git a/test/coff/pe-import-smoke.c b/test/coff/pe-import-smoke.c @@ -160,9 +160,9 @@ static void build_short_import_amd64(uint8_t buf[SHIM_TOTAL_LEN]) { static ObjBuilder* build_program(Compiler* c) { ObjBuilder* ob = obj_new(c); Pool* p = c->global; - Sym text_name = pool_intern_cstr(p, ".text"); - Sym main_name = pool_intern_cstr(p, "mainCRTStartup"); - Sym exit_name = pool_intern_cstr(p, SHIM_SYM_CSTR); + Sym text_name = pool_intern_slice(p, SLICE_LIT(".text")); + Sym main_name = pool_intern_slice(p, SLICE_LIT("mainCRTStartup")); + Sym exit_name = pool_intern_slice(p, SLICE_LIT(SHIM_SYM_CSTR)); ObjSecId text = obj_section(ob, text_name, SEC_TEXT, SF_ALLOC | SF_EXEC, 16); obj_write(ob, text, PROG_TEXT_X64, sizeof PROG_TEXT_X64); @@ -274,7 +274,7 @@ int main(void) { * holds defined symbols, so link_symbol_lookup can't find an imported * undef by name — iterate the dense LinkSyms array instead. */ { - Sym exit_name = pool_intern_cstr(c->global, SHIM_SYM_CSTR); + Sym exit_name = pool_intern_slice(c->global, SLICE_LIT(SHIM_SYM_CSTR)); const LinkSymbol* found = NULL; /* link_symbol returns NULL once we walk off the end. */ for (LinkSymId i = 1;; ++i) { diff --git a/test/coff/pe-mixed-archive.c b/test/coff/pe-mixed-archive.c @@ -151,8 +151,8 @@ static void build_short_import_amd64(uint8_t buf[SHIM_TOTAL_LEN]) { static uint8_t* build_helper_object(Compiler* c, size_t* len_out) { ObjBuilder* ob = obj_new(c); Pool* p = c->global; - Sym data_name = pool_intern_cstr(p, ".data"); - Sym helper_name = pool_intern_cstr(p, HELPER_SYM_CSTR); + Sym data_name = pool_intern_slice(p, SLICE_LIT(".data")); + Sym helper_name = pool_intern_slice(p, SLICE_LIT(HELPER_SYM_CSTR)); ObjSecId data = obj_section(ob, data_name, SEC_DATA, SF_ALLOC | SF_WRITE, 4); static const uint8_t kHelperBytes[4] = {0x2A, 0x00, 0x00, 0x00}; @@ -178,10 +178,10 @@ static uint8_t* build_helper_object(Compiler* c, size_t* len_out) { static ObjBuilder* build_program(Compiler* c) { ObjBuilder* ob = obj_new(c); Pool* p = c->global; - Sym text_name = pool_intern_cstr(p, ".text"); - Sym main_name = pool_intern_cstr(p, "mainCRTStartup"); - Sym import_name = pool_intern_cstr(p, SHIM_SYM_CSTR); - Sym helper_name = pool_intern_cstr(p, HELPER_SYM_CSTR); + Sym text_name = pool_intern_slice(p, SLICE_LIT(".text")); + Sym main_name = pool_intern_slice(p, SLICE_LIT("mainCRTStartup")); + Sym import_name = pool_intern_slice(p, SLICE_LIT(SHIM_SYM_CSTR)); + Sym helper_name = pool_intern_slice(p, SLICE_LIT(HELPER_SYM_CSTR)); ObjSecId text = obj_section(ob, text_name, SEC_TEXT, SF_ALLOC | SF_EXEC, 16); obj_write(ob, text, PROG_TEXT_X64, sizeof PROG_TEXT_X64); @@ -234,13 +234,13 @@ int main(void) { * every member regardless of the symbol index, so symbol_index=0 is * sufficient — the linker rediscovers each member's exports during * scan_presence_before. */ - CfreeBytes members[2]; - members[0].name = "importfn.o"; - members[0].data = shim; - members[0].len = SHIM_TOTAL_LEN; - members[1].name = "helper.o"; - members[1].data = helper_bytes; - members[1].len = helper_len; + CfreeArInput members[2]; + members[0].name = CFREE_SLICE_LIT("importfn.o"); + members[0].bytes.data = shim; + members[0].bytes.len = SHIM_TOTAL_LEN; + members[1].name = CFREE_SLICE_LIT("helper.o"); + members[1].bytes.data = helper_bytes; + members[1].bytes.len = helper_len; CfreeWriter* aw = NULL; if (cfree_writer_mem(&g_heap, &aw) != CFREE_OK || !aw) { @@ -289,8 +289,8 @@ int main(void) { LinkImage* img = link_resolve(l); EXPECT(img != NULL, "link_resolve returned NULL"); if (img) { - Sym import_name = pool_intern_cstr(c->global, SHIM_SYM_CSTR); - Sym helper_name = pool_intern_cstr(c->global, HELPER_SYM_CSTR); + Sym import_name = pool_intern_slice(c->global, SLICE_LIT(SHIM_SYM_CSTR)); + Sym helper_name = pool_intern_slice(c->global, SLICE_LIT(HELPER_SYM_CSTR)); const LinkSymbol* importf = NULL; const LinkSymbol* helper = NULL; for (LinkSymId i = 1;; ++i) { diff --git a/test/debug/cfi_unit.c b/test/debug/cfi_unit.c @@ -71,9 +71,9 @@ static const Section* sec_by_name(const ObjBuilder* ob, Pool* pool, u32 i, n = obj_section_count(ob); for (i = 1; i < n; ++i) { const Section* s = obj_section_get(ob, i); - size_t len = 0; - const char* sn = pool_str(pool, s->name, &len); - if (sn && strlen(name) == len && memcmp(sn, name, len) == 0) return s; + Slice sn = pool_slice(pool, s->name); + if (sn.s && strlen(name) == sn.len && memcmp(sn.s, name, sn.len) == 0) + return s; } return NULL; } @@ -154,9 +154,9 @@ static void check_arch(const CfiExpect* ex) { ob = obj_new(c); pool = c->global; - text_sec = obj_section(ob, pool_intern_cstr(pool, ".text"), SEC_TEXT, + text_sec = obj_section(ob, pool_intern_slice(pool, SLICE_LIT(".text")), SEC_TEXT, SF_EXEC | SF_ALLOC, 4); - fsym = obj_symbol(ob, pool_intern_cstr(pool, "f"), SB_GLOBAL, SK_FUNC, + fsym = obj_symbol(ob, pool_intern_slice(pool, SLICE_LIT("f")), SB_GLOBAL, SK_FUNC, text_sec, 0, 16); mc = mc_new(c, ob); diff --git a/test/debug/roundtrip_unit.c b/test/debug/roundtrip_unit.c @@ -79,9 +79,9 @@ static const Section* sec_by_name(const ObjBuilder* ob, Pool* pool, u32 i, n = obj_section_count(ob); for (i = 1; i < n; ++i) { const Section* s = obj_section_get(ob, i); - size_t len = 0; - const char* sn = pool_str(pool, s->name, &len); - if (sn && strlen(name) == len && memcmp(sn, name, len) == 0) return s; + Slice sn = pool_slice(pool, s->name); + if (sn.s && strlen(name) == sn.len && memcmp(sn.s, name, sn.len) == 0) + return s; } return NULL; } @@ -140,14 +140,14 @@ static int run_one(CfreeArchKind arch, uint32_t nop_word, const char* tag) { pool = c->global; /* .text section + symbol "f". */ - text_sec = obj_section(ob, pool_intern_cstr(pool, ".text"), SEC_TEXT, + text_sec = obj_section(ob, pool_intern_slice(pool, SLICE_LIT(".text")), SEC_TEXT, SF_EXEC | SF_ALLOC, 4); /* one 4-byte arch nop */ { u32 nop = nop_word; obj_write(ob, text_sec, &nop, 4); } - fsym = obj_symbol(ob, pool_intern_cstr(pool, "f"), SB_GLOBAL, SK_FUNC, + fsym = obj_symbol(ob, pool_intern_slice(pool, SLICE_LIT("f")), SB_GLOBAL, SK_FUNC, text_sec, 0, 4); /* Drive Debug. */ @@ -164,7 +164,7 @@ static int run_one(CfreeArchKind arch, uint32_t nop_word, const char* tag) { SrcLoc decl = {fid, 1, 0}; SrcLoc l10 = {fid, 10, 0}; DebugTypeId int_tid = - debug_type_base(d, pool_intern_cstr(pool, "int"), DEBUG_BE_SIGNED, 4); + debug_type_base(d, pool_intern_slice(pool, SLICE_LIT("int")), DEBUG_BE_SIGNED, 4); DebugTypeId fn_tid = debug_type_func(d, int_tid, NULL, 0, 0); /* Pre-register the file as DWARF index 0 = primary. */ (void)debug_file(d, fid); @@ -290,12 +290,13 @@ static int run_one(CfreeArchKind arch, uint32_t nop_word, const char* tag) { * f8=fs0=40) and aa64 still resolves x0..x30/sp by their DWARF indices. */ static void check_reg(CfreeArchKind arch, const char* tag, uint32_t expect_idx, const char* expect_name) { - const char* nm = cfree_arch_register_name(arch, expect_idx); + CfreeSlice nm = cfree_arch_register_name(arch, expect_idx); uint32_t got_idx = 0u; - CfreeStatus st = cfree_arch_register_index(arch, expect_name, &got_idx); - EXPECT(nm != NULL && strcmp(nm, expect_name) == 0, - "[%s] register_name(%u) expected %s, got %s", tag, expect_idx, - expect_name, nm ? nm : "(null)"); + CfreeStatus st = + cfree_arch_register_index(arch, cfree_slice_cstr(expect_name), &got_idx); + EXPECT(nm.s != NULL && cfree_slice_eq_cstr(nm, expect_name), + "[%s] register_name(%u) expected %s, got %.*s", tag, expect_idx, + expect_name, CFREE_SLICE_ARG(nm)); EXPECT(st == CFREE_OK && got_idx == expect_idx, "[%s] register_index(%s) expected %u, got %u (status %d)", tag, expect_name, expect_idx, got_idx, (int)st); @@ -321,7 +322,8 @@ static void run_arch_register_checks(void) { /* "fp" alias for s0/x8 on rv64. */ { uint32_t idx = 0; - CfreeStatus st = cfree_arch_register_index(CFREE_ARCH_RV64, "fp", &idx); + CfreeStatus st = cfree_arch_register_index( + CFREE_ARCH_RV64, CFREE_SLICE_LIT("fp"), &idx); EXPECT(st == CFREE_OK && idx == 8, "[rv64] register_index(fp) expected 8, got %u (status %d)", idx, (int)st); @@ -351,13 +353,13 @@ static int run_x64_debug_line_check(void) { xob = obj_new(xc); xpool = xc->global; - xtext_sec = obj_section(xob, pool_intern_cstr(xpool, ".text"), SEC_TEXT, + xtext_sec = obj_section(xob, pool_intern_slice(xpool, SLICE_LIT(".text")), SEC_TEXT, SF_EXEC | SF_ALLOC, 1); { u8 code[2] = {0x90, 0xc3}; /* nop; ret */ obj_write(xob, xtext_sec, code, sizeof(code)); } - xfsym = obj_symbol(xob, pool_intern_cstr(xpool, "xf"), SB_GLOBAL, SK_FUNC, + xfsym = obj_symbol(xob, pool_intern_slice(xpool, SLICE_LIT("xf")), SB_GLOBAL, SK_FUNC, xtext_sec, 0, 2); xd = debug_new(xc, xob); @@ -369,7 +371,7 @@ static int run_x64_debug_line_check(void) { SrcLoc l10 = {fid, 10, 0}; SrcLoc l11 = {fid, 11, 0}; DebugTypeId int_tid = debug_type_base( - xd, pool_intern_cstr(xpool, "int"), DEBUG_BE_SIGNED, 4); + xd, pool_intern_slice(xpool, SLICE_LIT("int")), DEBUG_BE_SIGNED, 4); DebugTypeId fn_tid = debug_type_func(xd, int_tid, NULL, 0, 0); (void)debug_file(xd, fid); diff --git a/test/dwarf/dwarf_test.c b/test/dwarf/dwarf_test.c @@ -711,27 +711,28 @@ static void build_debug_sections(ByteBuf* abbrev, ByteBuf* info, ByteBuf* line, static void run_tests(CfreeDebugInfo* di) { /* 1. addr_to_line at func_low. */ - const char* file = NULL; + CfreeSlice file = CFREE_SLICE_NULL; uint32_t line = 0, col = 0; if (cfree_dwarf_addr_to_line(di, 0x1000, &file, &line, &col) == 0) { - EXPECT(line == 10, "expected line 10 at 0x1000, got %u (file=%s)", line, - file ? file : "(null)"); - EXPECT(file && strstr(file, "test.c") != NULL, - "file should contain test.c, got %s", file ? file : "(null)"); + EXPECT(line == 10, "expected line 10 at 0x1000, got %u (file=%.*s)", line, + CFREE_SLICE_ARG(file)); + EXPECT(file.s && strstr(file.s, "test.c") != NULL, + "file should contain test.c, got %.*s", CFREE_SLICE_ARG(file)); } else { g_fail++; fprintf(stderr, "FAIL: addr_to_line(0x1000) returned no entry\n"); } /* 2. line_to_addr round trip. */ uint64_t pc = 0; - if (cfree_dwarf_line_to_addr(di, "/proj/test.c", 10, &pc) == 0) { + if (cfree_dwarf_line_to_addr(di, CFREE_SLICE_LIT("/proj/test.c"), 10, &pc) == + 0) { EXPECT(pc == 0x1000, "expected pc 0x1000 for /proj/test.c:10, got 0x%llx", (unsigned long long)pc); } else { fprintf(stderr, "NOTE: line_to_addr looked up by absolute path failed; " "trying relative\n"); - if (cfree_dwarf_line_to_addr(di, "test.c", 10, &pc) == 0) { + if (cfree_dwarf_line_to_addr(di, CFREE_SLICE_LIT("test.c"), 10, &pc) == 0) { EXPECT(pc == 0x1000, "expected pc 0x1000 for test.c:10, got 0x%llx", (unsigned long long)pc); } else { @@ -743,15 +744,15 @@ static void run_tests(CfreeDebugInfo* di) { CfreeDwarfSubprogram sp; EXPECT(cfree_dwarf_subprogram_at(di, 0x1000, &sp) == 0, "subprogram_at(0x1000) should succeed"); - if (sp.name) { - EXPECT(strcmp(sp.name, "test_main") == 0, - "subprogram name '%s' != test_main", sp.name); + if (sp.name.s) { + EXPECT(cfree_slice_eq_cstr(sp.name, "test_main"), + "subprogram name '%.*s' != test_main", CFREE_SLICE_ARG(sp.name)); } EXPECT(sp.high_pc > sp.low_pc, "subprogram pc range empty"); /* 4. var_at "x" should be FRAME_OFS. */ CfreeDwarfVarLoc loc; - EXPECT(cfree_dwarf_var_at(di, 0x1000, "x", &loc) == 0, + EXPECT(cfree_dwarf_var_at(di, 0x1000, CFREE_SLICE_LIT("x"), &loc) == 0, "var_at(0x1000, x) failed"); if (g_fail == 0) { EXPECT(loc.kind == CFREE_DLOC_FRAME_OFS, @@ -764,7 +765,7 @@ static void run_tests(CfreeDebugInfo* di) { } /* 5. var_at "arg" (param) should be REG. */ - EXPECT(cfree_dwarf_var_at(di, 0x1000, "arg", &loc) == 0, + EXPECT(cfree_dwarf_var_at(di, 0x1000, CFREE_SLICE_LIT("arg"), &loc) == 0, "var_at(0x1000, arg) failed"); EXPECT(loc.kind == CFREE_DLOC_REG, "expected arg.kind=REG, got %d", (int)loc.kind); @@ -778,7 +779,8 @@ static void run_tests(CfreeDebugInfo* di) { EXPECT(ti.kind == CFREE_DT_SINT, "expected SINT, got kind=%d", (int)ti.kind); EXPECT(ti.byte_size == 4, "expected byte_size=4, got %u", ti.byte_size); - EXPECT(strcmp(ti.name, "int") == 0, "expected name=int, got %s", ti.name); + EXPECT(cfree_slice_eq_cstr(ti.name, "int"), "expected name=int, got %.*s", + CFREE_SLICE_ARG(ti.name)); } /* 7. param_iter — should yield arg. */ @@ -792,7 +794,8 @@ static void run_tests(CfreeDebugInfo* di) { CfreeIterResult r = cfree_dwarf_param_iter_next(pi, &v); if (r != CFREE_ITER_ITEM) break; n++; - EXPECT(strcmp(v.name, "arg") == 0, "param name %s != arg", v.name); + EXPECT(cfree_slice_eq_cstr(v.name, "arg"), "param name %.*s != arg", + CFREE_SLICE_ARG(v.name)); } EXPECT(n == 1, "expected 1 param, got %d", n); cfree_dwarf_param_iter_free(pi); @@ -800,7 +803,7 @@ static void run_tests(CfreeDebugInfo* di) { /* 8. addr_to_line at second row (0x1004) → line 11. */ { - const char* f2 = NULL; + CfreeSlice f2 = CFREE_SLICE_NULL; uint32_t l2 = 0, c2 = 0; if (cfree_dwarf_addr_to_line(di, 0x1004, &f2, &l2, &c2) == 0) { EXPECT(l2 == 11, "expected line 11 at 0x1004, got %u", l2); @@ -825,11 +828,11 @@ static void run_tests(CfreeDebugInfo* di) { if (r != CFREE_ITER_ITEM) break; if (v.role == CFREE_DVR_LOCAL) { n_local++; - if (strcmp(v.name, "x") == 0) saw_x = 1; - if (strcmp(v.name, "y") == 0) saw_y = 1; + if (cfree_slice_eq_cstr(v.name, "x")) saw_x = 1; + if (cfree_slice_eq_cstr(v.name, "y")) saw_y = 1; } else if (v.role == CFREE_DVR_ARG) { n_arg++; - if (strcmp(v.name, "arg") == 0) saw_arg = 1; + if (cfree_slice_eq_cstr(v.name, "arg")) saw_arg = 1; } } /* The fixture has 6 locals total (x, y, my_int, Point, x_field, @@ -844,7 +847,7 @@ static void run_tests(CfreeDebugInfo* di) { /* 10. loc_read REG fast path: pull arg via a fake unwind frame. */ { CfreeDwarfVarLoc varg; - if (cfree_dwarf_var_at(di, 0x1000, "arg", &varg) == CFREE_OK) { + if (cfree_dwarf_var_at(di, 0x1000, CFREE_SLICE_LIT("arg"), &varg) == CFREE_OK) { CfreeUnwindFrame fr; uint32_t v32 = 0; size_t got = 0; @@ -863,7 +866,7 @@ static void run_tests(CfreeDebugInfo* di) { /* 11. type_info: pointer (var "my_int" carries pointer_type → int). */ { CfreeDwarfVarLoc lp; - if (cfree_dwarf_var_at(di, 0x1000, "my_int", &lp) == 0) { + if (cfree_dwarf_var_at(di, 0x1000, CFREE_SLICE_LIT("my_int"), &lp) == 0) { CfreeDwarfTypeInfo ti = cfree_dwarf_type_info(lp.type); EXPECT(ti.kind == CFREE_DT_PTR, "expected PTR, got kind=%d", (int)ti.kind); @@ -883,12 +886,12 @@ static void run_tests(CfreeDebugInfo* di) { /* 12. type_info: typedef (var "Point" carries typedef → int). */ { CfreeDwarfVarLoc lp; - if (cfree_dwarf_var_at(di, 0x1000, "Point", &lp) == 0) { + if (cfree_dwarf_var_at(di, 0x1000, CFREE_SLICE_LIT("Point"), &lp) == 0) { CfreeDwarfTypeInfo ti = cfree_dwarf_type_info(lp.type); EXPECT(ti.kind == CFREE_DT_TYPEDEF, "expected TYPEDEF, got kind=%d", (int)ti.kind); - EXPECT(strcmp(ti.name, "my_int") == 0, "typedef name=%s != my_int", - ti.name); + EXPECT(cfree_slice_eq_cstr(ti.name, "my_int"), + "typedef name=%.*s != my_int", CFREE_SLICE_ARG(ti.name)); EXPECT(ti.inner != NULL, "typedef inner missing"); } } @@ -896,7 +899,7 @@ static void run_tests(CfreeDebugInfo* di) { /* 13. type_info: array of int [4]. */ { CfreeDwarfVarLoc lp; - if (cfree_dwarf_var_at(di, 0x1000, "x_field", &lp) == 0) { + if (cfree_dwarf_var_at(di, 0x1000, CFREE_SLICE_LIT("x_field"), &lp) == 0) { CfreeDwarfTypeInfo ti = cfree_dwarf_type_info(lp.type); EXPECT(ti.kind == CFREE_DT_ARRAY, "expected ARRAY, got kind=%d", (int)ti.kind); @@ -907,12 +910,13 @@ static void run_tests(CfreeDebugInfo* di) { /* 14. type_info: struct Point with two int fields. */ { CfreeDwarfVarLoc lp; - if (cfree_dwarf_var_at(di, 0x1000, "y_field", &lp) == 0) { + if (cfree_dwarf_var_at(di, 0x1000, CFREE_SLICE_LIT("y_field"), &lp) == 0) { CfreeDwarfTypeInfo ti = cfree_dwarf_type_info(lp.type); EXPECT(ti.kind == CFREE_DT_STRUCT, "expected STRUCT, got kind=%d", (int)ti.kind); EXPECT(ti.byte_size == 8, "struct byte_size=%u", ti.byte_size); - EXPECT(strcmp(ti.name, "Point") == 0, "struct name=%s", ti.name); + EXPECT(cfree_slice_eq_cstr(ti.name, "Point"), "struct name=%.*s", + CFREE_SLICE_ARG(ti.name)); CfreeDwarfFieldIter* fi = NULL; EXPECT(cfree_dwarf_field_iter_new(di, lp.type, &fi) == CFREE_OK && fi != NULL, @@ -925,8 +929,10 @@ static void run_tests(CfreeDebugInfo* di) { CfreeIterResult r = cfree_dwarf_field_iter_next(fi, &f); if (r != CFREE_ITER_ITEM) break; count++; - if (strcmp(f.name, "x_field") == 0 && f.byte_offset == 0) saw_x = 1; - if (strcmp(f.name, "y_field") == 0 && f.byte_offset == 4) saw_y = 1; + if (cfree_slice_eq_cstr(f.name, "x_field") && f.byte_offset == 0) + saw_x = 1; + if (cfree_slice_eq_cstr(f.name, "y_field") && f.byte_offset == 4) + saw_y = 1; } EXPECT(count == 2, "expected 2 fields, got %d", count); EXPECT(saw_x && saw_y, "missing x_field or y_field"); @@ -974,8 +980,8 @@ int main(void) { /* Build an ObjBuilder via internal API. */ ObjBuilder* ob = obj_new(cc); - Sym text_name = pool_intern_cstr(cc->global, ".text"); - Sym func_name = pool_intern_cstr(cc->global, "test_main"); + Sym text_name = pool_intern_slice(cc->global, SLICE_LIT(".text")); + Sym func_name = pool_intern_slice(cc->global, SLICE_LIT("test_main")); ObjSecId text_sec = obj_section(ob, text_name, SEC_TEXT, SF_EXEC | SF_ALLOC, 4); /* 8 bytes of nop-like text. */ @@ -983,11 +989,11 @@ int main(void) { obj_write(ob, text_sec, text_bytes, 8); obj_symbol(ob, func_name, SB_GLOBAL, SK_FUNC, text_sec, 0, 8); - Sym n_abbrev = pool_intern_cstr(cc->global, ".debug_abbrev"); - Sym n_info = pool_intern_cstr(cc->global, ".debug_info"); - Sym n_line = pool_intern_cstr(cc->global, ".debug_line"); - Sym n_str = pool_intern_cstr(cc->global, ".debug_str"); - Sym n_line_str = pool_intern_cstr(cc->global, ".debug_line_str"); + Sym n_abbrev = pool_intern_slice(cc->global, SLICE_LIT(".debug_abbrev")); + Sym n_info = pool_intern_slice(cc->global, SLICE_LIT(".debug_info")); + Sym n_line = pool_intern_slice(cc->global, SLICE_LIT(".debug_line")); + Sym n_str = pool_intern_slice(cc->global, SLICE_LIT(".debug_str")); + Sym n_line_str = pool_intern_slice(cc->global, SLICE_LIT(".debug_line_str")); ObjSecId s_abbrev = obj_section(ob, n_abbrev, SEC_DEBUG, 0, 1); ObjSecId s_info = obj_section(ob, n_info, SEC_DEBUG, 0, 1); ObjSecId s_line = obj_section(ob, n_line, SEC_DEBUG, 0, 1); @@ -1009,13 +1015,12 @@ int main(void) { fprintf(stderr, "built obj: %zu bytes\n", obj_len); /* Re-open via the public API. */ - CfreeBytes in; + CfreeSlice in; memset(&in, 0, sizeof in); - in.name = "test.o"; in.data = obj_bytes; in.len = obj_len; CfreeObjFile* obj = NULL; - EXPECT(cfree_obj_open(&ctx, &in, &obj) == CFREE_OK && obj != NULL, + EXPECT(cfree_obj_open(&ctx, CFREE_SLICE_LIT("test.o"), &in, &obj) == CFREE_OK && obj != NULL, "cfree_obj_open failed"); if (obj) { CfreeDebugInfo* di = NULL; diff --git a/test/elf/unit/align_4k.c b/test/elf/unit/align_4k.c @@ -88,11 +88,11 @@ int main(void) { } ObjBuilder* in = obj_new(c); - Sym text_nm = pool_intern_cstr(c->global, ".text"); + Sym text_nm = pool_intern_slice(c->global, SLICE_LIT(".text")); ObjSecId sec = obj_section(in, text_nm, SEC_TEXT, SF_ALLOC | SF_EXEC, WANT_ALIGN); obj_write(in, sec, TEXT_BYTES, sizeof TEXT_BYTES); - obj_symbol(in, pool_intern_cstr(c->global, "f"), SB_GLOBAL, SK_FUNC, sec, 0, + obj_symbol(in, pool_intern_slice(c->global, SLICE_LIT("f")), SB_GLOBAL, SK_FUNC, sec, 0, sizeof TEXT_BYTES); obj_finalize(in); @@ -114,9 +114,8 @@ int main(void) { u32 n = obj_section_count(back); for (u32 i = 1; i < n; ++i) { const Section* s = obj_section_get(back, i); - size_t l; - const char* nm = pool_str(c->global, s->name, &l); - if (l == 5 && memcmp(nm, ".text", 5) == 0) { + Slice nm = pool_slice(c->global, s->name); + if (nm.len == 5 && memcmp(nm.s, ".text", 5) == 0) { found = 1; CHECK(s->align == WANT_ALIGN, ".text align=%u after roundtrip, want %u", s->align, WANT_ALIGN); diff --git a/test/elf/unit/groupiter.c b/test/elf/unit/groupiter.c @@ -66,8 +66,8 @@ static const uint8_t TEXT_BYTES[8] = { 0x20, 0x00, 0x80, 0x52, 0xc0, 0x03, 0x5f, 0xd6, }; -static int name_eq(const char* s, const char* want) { - return s && strcmp(s, want) == 0; +static int name_eq(CfreeSlice s, const char* want) { + return s.s && cfree_slice_eq_cstr(s, want); } int main(void) { @@ -99,9 +99,9 @@ int main(void) { ObjBuilder* in = obj_new(c); Pool* p = c->global; - Sym sig_nm = pool_intern_cstr(p, "comdat_sig"); - Sym text_nm = pool_intern_cstr(p, ".text.comdat_fn"); - Sym data_nm = pool_intern_cstr(p, ".data.comdat_fn"); + Sym sig_nm = pool_intern_slice(p, SLICE_LIT("comdat_sig")); + Sym text_nm = pool_intern_slice(p, SLICE_LIT(".text.comdat_fn")); + Sym data_nm = pool_intern_slice(p, SLICE_LIT(".data.comdat_fn")); ObjSecId sec_text = obj_section(in, text_nm, SEC_TEXT, SF_ALLOC | SF_EXEC | SF_GROUP, 4); @@ -155,19 +155,19 @@ int main(void) { memcpy(roundtrip, out_data, out_len); cfree_writer_close(w); - CfreeBytes input = {.name = "groupiter", .data = roundtrip, .len = out_len}; + CfreeSlice input = {.data = roundtrip, .len = out_len}; CfreeObjFile* f = NULL; - CHECK(cfree_obj_open(&ctx, &input, &f) == CFREE_OK && f, + CHECK(cfree_obj_open(&ctx, CFREE_SLICE_LIT("groupiter"), &input, &f) == CFREE_OK && f, "cfree_obj_open failed"); if (f) { /* Resolve section IDs by name so the test isn't coupled to ordering. */ CfreeObjSection text_pub = CFREE_SECTION_NONE; CfreeObjSection data_pub = CFREE_SECTION_NONE; - CHECK(cfree_obj_section_by_name(f, ".text.comdat_fn", &text_pub) == + CHECK(cfree_obj_section_by_name(f, CFREE_SLICE_LIT(".text.comdat_fn"), &text_pub) == CFREE_OK, "section_by_name .text.comdat_fn"); - CHECK(cfree_obj_section_by_name(f, ".data.comdat_fn", &data_pub) == + CHECK(cfree_obj_section_by_name(f, CFREE_SLICE_LIT(".data.comdat_fn"), &data_pub) == CFREE_OK, "section_by_name .data.comdat_fn"); @@ -178,8 +178,8 @@ int main(void) { CfreeObjGroupInfo gi; while (cfree_obj_groupiter_next(git, &gi) == CFREE_ITER_ITEM) { ++seen; - CHECK(name_eq(gi.name, "comdat_sig"), "public iter: name=%s", - gi.name ? gi.name : "(null)"); + CHECK(name_eq(gi.name, "comdat_sig"), "public iter: name=%.*s", + CFREE_SLICE_ARG(gi.name)); CHECK((gi.flags & CFREE_OBJ_GROUP_COMDAT) != 0, "public iter: missing COMDAT flag (flags=0x%x)", gi.flags); CHECK(gi.nsections == 2, "public iter: nsections=%u, want 2", diff --git a/test/elf/unit/mutate.c b/test/elf/unit/mutate.c @@ -97,13 +97,13 @@ int main(void) { ObjBuilder* ob = obj_new(c); Pool* p = c->global; - Sym text_nm = pool_intern_cstr(p, ".text"); - Sym data_nm = pool_intern_cstr(p, ".data"); - Sym entry_nm = pool_intern_cstr(p, "entry"); - Sym entry_new_nm = pool_intern_cstr(p, "renamed_entry"); - Sym keep_nm = pool_intern_cstr(p, "keep_global"); - Sym foo_nm = pool_intern_cstr(p, "foo_ref"); - Sym spurious_nm = pool_intern_cstr(p, "spurious_extern"); + Sym text_nm = pool_intern_slice(p, SLICE_LIT(".text")); + Sym data_nm = pool_intern_slice(p, SLICE_LIT(".data")); + Sym entry_nm = pool_intern_slice(p, SLICE_LIT("entry")); + Sym entry_new_nm = pool_intern_slice(p, SLICE_LIT("renamed_entry")); + Sym keep_nm = pool_intern_slice(p, SLICE_LIT("keep_global")); + Sym foo_nm = pool_intern_slice(p, SLICE_LIT("foo_ref")); + Sym spurious_nm = pool_intern_slice(p, SLICE_LIT("spurious_extern")); ObjSecId sec_text = obj_section(ob, text_nm, SEC_TEXT, SF_ALLOC | SF_EXEC, 4); @@ -163,37 +163,37 @@ int main(void) { memcpy(roundtrip, out_data, out_len); cfree_writer_close(w); - CfreeBytes input = {.name = "mutate", .data = roundtrip, .len = out_len}; + CfreeSlice input = {.data = roundtrip, .len = out_len}; CfreeObjFile* f = NULL; - CHECK(cfree_obj_open(&ctx, &input, &f) == CFREE_OK && f, "reopen"); + CHECK(cfree_obj_open(&ctx, CFREE_SLICE_LIT("mutate"), &input, &f) == CFREE_OK && f, "reopen"); if (f) { /* .data should be gone. */ CfreeObjSection s_data = CFREE_SECTION_NONE; CfreeStatus st_data = - cfree_obj_section_by_name(f, ".data", &s_data); + cfree_obj_section_by_name(f, CFREE_SLICE_LIT(".data"), &s_data); CHECK(st_data == CFREE_NOT_FOUND, ".data still present after removal"); /* .text should remain. */ CfreeObjSection s_text = CFREE_SECTION_NONE; - CHECK(cfree_obj_section_by_name(f, ".text", &s_text) == CFREE_OK, + CHECK(cfree_obj_section_by_name(f, CFREE_SLICE_LIT(".text"), &s_text) == CFREE_OK, ".text missing after roundtrip"); /* Renamed entry symbol is present; old name is gone. */ CfreeObjSymInfo si; - CHECK(cfree_obj_symbol_by_name(f, "renamed_entry", &si) == CFREE_OK, + CHECK(cfree_obj_symbol_by_name(f, CFREE_SLICE_LIT("renamed_entry"), &si) == CFREE_OK, "renamed_entry not found"); - CHECK(cfree_obj_symbol_by_name(f, "entry", &si) == CFREE_NOT_FOUND, + CHECK(cfree_obj_symbol_by_name(f, CFREE_SLICE_LIT("entry"), &si) == CFREE_NOT_FOUND, "old 'entry' symbol survived rename"); /* keep_global was localized; reads back as SB_LOCAL. */ - CHECK(cfree_obj_symbol_by_name(f, "keep_global", &si) == CFREE_OK, + CHECK(cfree_obj_symbol_by_name(f, CFREE_SLICE_LIT("keep_global"), &si) == CFREE_OK, "keep_global lost"); CHECK(si.bind == CFREE_SB_LOCAL, "keep_global bind=%d, want LOCAL=%d", (int)si.bind, (int)CFREE_SB_LOCAL); /* Spurious extern was pruned by the sweep. */ - CHECK(cfree_obj_symbol_by_name(f, "spurious_extern", &si) == + CHECK(cfree_obj_symbol_by_name(f, CFREE_SLICE_LIT("spurious_extern"), &si) == CFREE_NOT_FOUND, "spurious_extern survived sweep"); @@ -203,7 +203,7 @@ int main(void) { * via obj_reloc_ex at build time, BUT the reloc is then dropped at * sweep. The symbol's `referenced` flag was set at obj_reloc time and * does not get cleared, so foo_ref survives as a plain UNDEF. */ - CHECK(cfree_obj_symbol_by_name(f, "foo_ref", &si) == CFREE_OK, + CHECK(cfree_obj_symbol_by_name(f, CFREE_SLICE_LIT("foo_ref"), &si) == CFREE_OK, "foo_ref UNDEF should survive"); /* No relocs should remain — all were in the removed .data. */ diff --git a/test/elf/unit/smoke.c b/test/elf/unit/smoke.c @@ -80,10 +80,10 @@ static ObjBuilder* build_input(Compiler* c) { ObjBuilder* ob = obj_new(c); Pool* p = c->global; - Sym text = pool_intern_cstr(p, ".text"); - Sym data = pool_intern_cstr(p, ".data"); - Sym main = pool_intern_cstr(p, "main"); - Sym foo = pool_intern_cstr(p, "foo"); + Sym text = pool_intern_slice(p, SLICE_LIT(".text")); + Sym data = pool_intern_slice(p, SLICE_LIT(".data")); + Sym main = pool_intern_slice(p, SLICE_LIT("main")); + Sym foo = pool_intern_slice(p, SLICE_LIT("foo")); ObjSecId sec_text = obj_section(ob, text, SEC_TEXT, SF_ALLOC | SF_EXEC, 4); ObjSecId sec_data = obj_section(ob, data, SEC_DATA, SF_ALLOC | SF_WRITE, 8); @@ -108,11 +108,10 @@ static ObjBuilder* build_input(Compiler* c) { /* Pool strings are NOT NUL-terminated (pool_intern stores raw bytes), so * compare by length + memcmp rather than strcmp. */ static int sym_eq_str(Pool* p, Sym s, const char* want) { - size_t len; - const char* got = pool_str(p, s, &len); + Slice got = pool_slice(p, s); size_t wlen = 0; while (want[wlen]) ++wlen; - return got && len == wlen && memcmp(got, want, len) == 0; + return got.s && got.len == wlen && memcmp(got.s, want, got.len) == 0; } static const Section* find_section_named(const ObjBuilder* ob, Pool* p, @@ -219,10 +218,9 @@ static void verify_shape(const ObjBuilder* ob, Pool* p) { (long long)found->addend); const ObjSym* tsym = obj_symbol_get(ob, found->sym); if (tsym) { - size_t l; - const char* nm = pool_str(p, tsym->name, &l); + Slice nm = pool_slice(p, tsym->name); CHECK(sym_eq_str(p, tsym->name, "foo"), "reloc target name = %.*s", - (int)l, nm ? nm : "(null)"); + (int)nm.len, nm.s ? nm.s : "(null)"); } } } diff --git a/test/elf/unit/x64_disasm_annotations.c b/test/elf/unit/x64_disasm_annotations.c @@ -72,12 +72,12 @@ static CfreeTarget x64_elf_target(void) { static ObjBuilder* build_input(Compiler* c) { ObjBuilder* ob = obj_new(c); Pool* p = c->global; - Sym text = pool_intern_cstr(p, ".text"); - Sym start = pool_intern_cstr(p, "_start"); - Sym load_data = pool_intern_cstr(p, "load_data"); - Sym foo = pool_intern_cstr(p, "foo"); - Sym bar = pool_intern_cstr(p, "bar"); - Sym global_data = pool_intern_cstr(p, "global_data"); + Sym text = pool_intern_slice(p, SLICE_LIT(".text")); + Sym start = pool_intern_slice(p, SLICE_LIT("_start")); + Sym load_data = pool_intern_slice(p, SLICE_LIT("load_data")); + Sym foo = pool_intern_slice(p, SLICE_LIT("foo")); + Sym bar = pool_intern_slice(p, SLICE_LIT("bar")); + Sym global_data = pool_intern_slice(p, SLICE_LIT("global_data")); ObjSecId sec_text = obj_section(ob, text, SEC_TEXT, SF_ALLOC | SF_EXEC, 16); static const uint8_t text_bytes[] = { @@ -105,14 +105,14 @@ static ObjBuilder* build_input(Compiler* c) { return ob; } -static void check_reloc_names(const CfreeBytes* bytes, const CfreeContext* ctx) { +static void check_reloc_names(const CfreeSlice* bytes, const CfreeContext* ctx) { CfreeObjFile* f = NULL; CfreeObjRelocIter* it = NULL; CfreeObjReloc r; int saw_plt32 = 0; int saw_pc32 = 0; - CHECK(cfree_obj_open(ctx, bytes, &f) == CFREE_OK && f, "cfree_obj_open"); + CHECK(cfree_obj_open(ctx, CFREE_SLICE_LIT("x64_disasm_annotations.o"), bytes, &f) == CFREE_OK && f, "cfree_obj_open"); if (!f) return; CHECK(cfree_obj_reliter_new(f, &it) == CFREE_OK && it, "reliter_new"); if (!it) { @@ -121,14 +121,14 @@ static void check_reloc_names(const CfreeBytes* bytes, const CfreeContext* ctx) } while (cfree_obj_reliter_next(it, &r) == CFREE_ITER_ITEM) { if (r.offset == 1 || r.offset == 13) { - CHECK(r.kind_name && strcmp(r.kind_name, "R_X86_64_PLT32") == 0, - "PLT32 kind name at offset %llu is %s", - (unsigned long long)r.offset, r.kind_name ? r.kind_name : "(null)"); + CHECK(cfree_slice_eq_cstr(r.kind_name, "R_X86_64_PLT32"), + "PLT32 kind name at offset %llu is %.*s", + (unsigned long long)r.offset, CFREE_SLICE_ARG(r.kind_name)); saw_plt32++; } if (r.offset == 8) { - CHECK(r.kind_name && strcmp(r.kind_name, "R_X86_64_PC32") == 0, - "PC32 kind name is %s", r.kind_name ? r.kind_name : "(null)"); + CHECK(cfree_slice_eq_cstr(r.kind_name, "R_X86_64_PC32"), + "PC32 kind name is %.*s", CFREE_SLICE_ARG(r.kind_name)); saw_pc32 = 1; } } @@ -138,7 +138,7 @@ static void check_reloc_names(const CfreeBytes* bytes, const CfreeContext* ctx) cfree_obj_free(f); } -static void check_disasm_annotations(const CfreeBytes* bytes, +static void check_disasm_annotations(const CfreeSlice* bytes, const CfreeContext* ctx) { CfreeWriter* w = NULL; const uint8_t* out; @@ -178,7 +178,7 @@ int main(void) { CfreeWriter* w = NULL; const uint8_t* obj_data; size_t obj_len = 0; - CfreeBytes bytes; + CfreeSlice bytes; memset(&ctx, 0, sizeof ctx); ctx.heap = &g_heap; @@ -201,7 +201,6 @@ int main(void) { CHECK(cfree_writer_mem(&g_heap, &w) == CFREE_OK && w, "writer_mem object"); emit_elf(c, ob, w); obj_data = cfree_writer_mem_bytes(w, &obj_len); - bytes.name = "x64_disasm_annotations.o"; bytes.data = obj_data; bytes.len = obj_len; diff --git a/test/libc/cases/11_strings.c b/test/libc/cases/11_strings.c @@ -1,21 +1,23 @@ -/* string.h surface: strlen / strcmp / strchr / strstr / memcpy / memset. */ +/* string.h surface: memcpy / memset / memcmp / memchr. + * + * cfree's freestanding runtime intentionally does not ship the NUL-terminated + * str* family (strlen/strcmp/strchr/strstr/...); the project carries lengths + * explicitly. Only the length-based mem* primitives are provided. */ #include <stdio.h> #include <string.h> int main(void) { const char *s = "hello, world"; - if (strlen(s) != 12) return 1; - if (strcmp(s, "hello, world") != 0) return 2; - if (strcmp(s, "hello") <= 0) return 3; - if (strchr(s, ',') != s + 5) return 4; - if (strstr(s, "world") != s + 7) return 5; + if (memcmp(s, "hello, world", 13) != 0) return 1; /* incl. NUL */ + if (memchr(s, ',', 12) != s + 5) return 2; + if (memchr(s, 'z', 12) != NULL) return 3; char buf[16]; memset(buf, '#', sizeof(buf)); memcpy(buf, "hi", 2); buf[2] = 0; - if (strcmp(buf, "hi") != 0) return 6; + if (memcmp(buf, "hi", 3) != 0) return 4; /* 'h','i','\0' */ printf("strings ok\n"); return 0; diff --git a/test/libc/cases/13_malloc.c b/test/libc/cases/13_malloc.c @@ -9,7 +9,7 @@ int main(void) { if (!buf) return 1; int n = snprintf(buf, 64, "alloc %d bytes", 64); if (n != 14) return 2; - if (strcmp(buf, "alloc 64 bytes") != 0) return 3; + if (memcmp(buf, "alloc 64 bytes", 15) != 0) return 3; /* incl. NUL */ free(buf); printf("malloc ok\n"); return 0; diff --git a/test/link/harness/jit_runner.c b/test/link/harness/jit_runner.c @@ -289,7 +289,7 @@ static void* low_extern_default_value(void) { return &g_extern_default_value; #endif } -static void* extern_resolver(void* user, const char* name) { +static void* extern_resolver(void* user, CfreeSlice name) { (void)user; (void)name; return low_extern_default_value(); @@ -416,7 +416,8 @@ int main(int argc, char** argv) { const char* check_present = NULL; const char* script_path = NULL; - CfreeBytes objs[64]; + CfreeSlice objs[64]; + const char* obj_names[64]; CfreeLinkArchiveInput archives[16]; uint32_t nobj = 0, narc = 0; uint8_t* bufs[80]; @@ -449,16 +450,16 @@ int main(int argc, char** argv) { if (next_archive) { CfreeLinkArchiveInput* a = &archives[narc++]; memset(a, 0, sizeof(*a)); - a->bytes.name = argv[i]; + a->name = cfree_slice_cstr(argv[i]); a->bytes.data = data; a->bytes.len = len; a->whole_archive = (uint8_t)next_whole; next_archive = 0; next_whole = 0; } else { - CfreeBytes* o = &objs[nobj++]; + obj_names[nobj] = argv[i]; + CfreeSlice* o = &objs[nobj++]; memset(o, 0, sizeof(*o)); - o->name = argv[i]; o->data = data; o->len = len; } @@ -493,7 +494,7 @@ int main(int argc, char** argv) { CfreeLinkScript* script = NULL; memset(&opts, 0, sizeof(opts)); opts.output_kind = CFREE_LINK_OUTPUT_JIT; - opts.entry = "test_main"; + opts.entry = CFREE_SLICE_LIT("test_main"); opts.gc_sections = gc_sections; opts.jit_host = &jhost; if (use_resolver) { @@ -509,8 +510,8 @@ int main(int argc, char** argv) { cfree_compiler_free(c); return 2; } - CfreeStatus prc = - cfree_link_script_parse(&ctx, (const char*)sbytes, slen, &script); + CfreeSlice script_text = {.s = (const char*)sbytes, .len = slen}; + CfreeStatus prc = cfree_link_script_parse(&ctx, script_text, &script); free(sbytes); if (prc != CFREE_OK) { fprintf(stderr, "jit-runner: linker script parse failed: %s\n", @@ -524,7 +525,8 @@ int main(int argc, char** argv) { CfreeJit* jit = NULL; CfreeStatus rc = cfree_link_session_new(c, &opts, &link); for (uint32_t i = 0; rc == CFREE_OK && i < nobj; ++i) - rc = cfree_link_session_add_obj_bytes(link, &objs[i]); + rc = cfree_link_session_add_obj_bytes(link, cfree_slice_cstr(obj_names[i]), + &objs[i]); for (uint32_t i = 0; rc == CFREE_OK && i < narc; ++i) rc = cfree_link_session_add_archive_bytes(link, &archives[i]); if (rc == CFREE_OK) rc = cfree_link_session_jit(link, &jit); @@ -540,7 +542,7 @@ int main(int argc, char** argv) { for (int i = 0; i < nbufs; i++) free(bufs[i]); /* Sanity: a never-defined sentinel must not be found (covers case 29). */ - if (cfree_jit_lookup(jit, "__cfree_test_sentinel__")) { + if (cfree_jit_lookup(jit, CFREE_SLICE_LIT("__cfree_test_sentinel__"))) { fprintf(stderr, "jit-runner: sentinel lookup unexpectedly non-NULL\n"); cfree_jit_run_dtors(jit); cfree_jit_free(jit); @@ -550,7 +552,7 @@ int main(int argc, char** argv) { /* --check-absent SYM: verify symbol was removed (e.g. by --gc-sections). */ if (check_absent) { - int absent_ok = cfree_jit_lookup(jit, check_absent) == NULL; + int absent_ok = cfree_jit_lookup(jit, cfree_slice_cstr(check_absent)) == NULL; if (!absent_ok) fprintf(stderr, "jit-runner: symbol '%s' present but expected absent\n", check_absent); @@ -562,7 +564,8 @@ int main(int argc, char** argv) { /* --check-present SYM: verify symbol survives the link / GC. */ if (check_present) { - int present_ok = cfree_jit_lookup(jit, check_present) != NULL; + int present_ok = + cfree_jit_lookup(jit, cfree_slice_cstr(check_present)) != NULL; if (!present_ok) fprintf(stderr, "jit-runner: symbol '%s' missing but expected present\n", check_present); @@ -572,8 +575,8 @@ int main(int argc, char** argv) { return present_ok ? 0 : 1; } - void* wasm_init = cfree_jit_lookup(jit, "__cfree_wasm_init"); - void* entry = cfree_jit_lookup(jit, "test_main"); + void* wasm_init = cfree_jit_lookup(jit, CFREE_SLICE_LIT("__cfree_wasm_init")); + void* entry = cfree_jit_lookup(jit, CFREE_SLICE_LIT("test_main")); int (*fn)(void) = entry; /* TLS local-exec setup. Build the static TLS block and install the @@ -586,10 +589,11 @@ int main(int argc, char** argv) { int restore_fs = 0; #endif { - char* td_start = (char*)cfree_jit_lookup(jit, "__tdata_start"); - char* td_end = (char*)cfree_jit_lookup(jit, "__tdata_end"); - unsigned long bs_n = - (unsigned long)(unsigned long long)cfree_jit_lookup(jit, "__tbss_size"); + char* td_start = + (char*)cfree_jit_lookup(jit, CFREE_SLICE_LIT("__tdata_start")); + char* td_end = (char*)cfree_jit_lookup(jit, CFREE_SLICE_LIT("__tdata_end")); + unsigned long bs_n = (unsigned long)(unsigned long long)cfree_jit_lookup( + jit, CFREE_SLICE_LIT("__tbss_size")); if (td_start && td_end) { unsigned long td_n = (unsigned long)(td_end - td_start); unsigned long i; @@ -662,7 +666,7 @@ int main(int argc, char** argv) { #endif if (result == 0) { - int (*post)(void) = cfree_jit_lookup(jit, "test_post_fini"); + int (*post)(void) = cfree_jit_lookup(jit, CFREE_SLICE_LIT("test_post_fini")); if (post) result = post(); } diff --git a/test/link/harness/link_exe_runner.c b/test/link/harness/link_exe_runner.c @@ -112,9 +112,11 @@ int main(int argc, char** argv) { int next_archive = 0; int next_whole = 0; - CfreeBytes objs[64]; + CfreeSlice objs[64]; + const char* obj_names[64]; CfreeLinkArchiveInput archives[16]; - CfreeBytes dsos[16]; + CfreeSlice dsos[16]; + const char* dso_names[16]; uint32_t nobj = 0, narc = 0, ndso = 0; uint8_t* bufs[96]; int nbufs = 0; @@ -145,25 +147,25 @@ int main(int argc, char** argv) { } bufs[nbufs++] = data; if (next_dso) { - CfreeBytes* d = &dsos[ndso++]; + dso_names[ndso] = argv[i]; + CfreeSlice* d = &dsos[ndso++]; memset(d, 0, sizeof(*d)); - d->name = argv[i]; d->data = data; d->len = len; next_dso = 0; } else if (next_archive) { CfreeLinkArchiveInput* a = &archives[narc++]; memset(a, 0, sizeof(*a)); - a->bytes.name = argv[i]; + a->name = cfree_slice_cstr(argv[i]); a->bytes.data = data; a->bytes.len = len; a->whole_archive = (uint8_t)next_whole; next_archive = 0; next_whole = 0; } else { - CfreeBytes* o = &objs[nobj++]; + obj_names[nobj] = argv[i]; + CfreeSlice* o = &objs[nobj++]; memset(o, 0, sizeof(*o)); - o->name = argv[i]; o->data = data; o->len = len; } @@ -197,7 +199,7 @@ int main(int argc, char** argv) { CfreeLinkScript* script = NULL; memset(&opts, 0, sizeof(opts)); opts.output_kind = CFREE_LINK_OUTPUT_EXE; - opts.entry = entry_name; + opts.entry = cfree_slice_cstr(entry_name); opts.gc_sections = gc_sections; if (script_path) { @@ -208,8 +210,8 @@ int main(int argc, char** argv) { cfree_compiler_free(c); return 2; } - CfreeStatus prc = - cfree_link_script_parse(&ctx, (const char*)sbytes, slen, &script); + CfreeSlice script_text = {.s = (const char*)sbytes, .len = slen}; + CfreeStatus prc = cfree_link_script_parse(&ctx, script_text, &script); free(sbytes); if (prc != CFREE_OK) { fprintf(stderr, "link-exe-runner: linker script parse failed: %s\n", @@ -228,11 +230,13 @@ int main(int argc, char** argv) { CfreeStatus rc = cfree_link_session_new(c, &opts, &link); for (uint32_t i = 0; rc == CFREE_OK && i < nobj; ++i) - rc = cfree_link_session_add_obj_bytes(link, &objs[i]); + rc = cfree_link_session_add_obj_bytes(link, cfree_slice_cstr(obj_names[i]), + &objs[i]); for (uint32_t i = 0; rc == CFREE_OK && i < narc; ++i) rc = cfree_link_session_add_archive_bytes(link, &archives[i]); for (uint32_t i = 0; rc == CFREE_OK && i < ndso; ++i) - rc = cfree_link_session_add_dso_bytes(link, &dsos[i]); + rc = cfree_link_session_add_dso_bytes(link, cfree_slice_cstr(dso_names[i]), + &dsos[i]); if (rc == CFREE_OK) rc = cfree_link_session_emit(link, w); if (rc != CFREE_OK) { diff --git a/test/link/rv64_jit_test.c b/test/link/rv64_jit_test.c @@ -245,7 +245,7 @@ int main(void) { CfreeObjSectionDesc sec_desc; memset(&sec_desc, 0, sizeof(sec_desc)); - sec_desc.name = cfree_sym_intern(c, ".text"); + sec_desc.name = cfree_sym_intern(c, CFREE_SLICE_LIT(".text")); sec_desc.kind = CFREE_SEC_TEXT; sec_desc.flags = CFREE_SF_EXEC | CFREE_SF_ALLOC; sec_desc.align = 4; @@ -263,7 +263,7 @@ int main(void) { CfreeObjSymbolDesc sym_desc; memset(&sym_desc, 0, sizeof(sym_desc)); - sym_desc.name = cfree_sym_intern(c, "rv64_jit_answer"); + sym_desc.name = cfree_sym_intern(c, CFREE_SLICE_LIT("rv64_jit_answer")); sym_desc.bind = CFREE_SB_GLOBAL; sym_desc.kind = CFREE_SK_FUNC; sym_desc.section = text; @@ -290,7 +290,7 @@ int main(void) { CfreeLinkSessionOptions opts; memset(&opts, 0, sizeof(opts)); opts.output_kind = CFREE_LINK_OUTPUT_JIT; - opts.entry = "rv64_jit_answer"; + opts.entry = CFREE_SLICE_LIT("rv64_jit_answer"); opts.jit_host = &jhost; CfreeLinkSession* sess = NULL; @@ -312,7 +312,7 @@ int main(void) { } cfree_link_session_free(sess); - void* fn = cfree_jit_lookup(jit, "rv64_jit_answer"); + void* fn = cfree_jit_lookup(jit, CFREE_SLICE_LIT("rv64_jit_answer")); if (!fn) { fprintf(stderr, "rv64_jit_test: lookup failed\n"); cfree_jit_free(jit); diff --git a/test/opt/opt_test.c b/test/opt/opt_test.c @@ -874,8 +874,9 @@ static void mock_plan_hard_regs(CGTarget* t, RegClass cls, const Reg* regs, static int mock_resolve_reg_name(CGTarget* t, Sym name, Reg* out, RegClass* cls_out) { - size_t len = 0; - const char* s = pool_str(t->c->global, name, &len); + Slice sl = pool_slice(t->c->global, name); + const char* s = sl.s; + size_t len = sl.len; if (!s || len < 2) return 1; if ((s[0] != 'r' && s[0] != 'x' && s[0] != 'v') || s[1] < '0' || s[1] > '9') return 1; @@ -1153,9 +1154,9 @@ static CfreeCgTypeId record_of_i64s(TestCtx* tc, const char* name, u64 count) { CfreeCgTypeId arr = cfree_cg_type_array(tc->c, tc->i64, count); CfreeCgField field; memset(&field, 0, sizeof field); - field.name = cfree_sym_intern(tc->c, "a"); + field.name = cfree_sym_intern(tc->c, CFREE_SLICE_LIT("a")); field.type = arr; - return cfree_cg_type_record(tc->c, cfree_sym_intern(tc->c, name), &field, 1); + return cfree_cg_type_record(tc->c, cfree_sym_intern(tc->c, cfree_slice_cstr(name)), &field, 1); } static CfreeCgTypeId make_func_type(TestCtx* tc, CfreeCgTypeId ret, @@ -4853,7 +4854,7 @@ static void opt_inline_asm_constraints_and_clobbers(void) { aux->ins[0].type = tc.i32; aux->out_ops[0] = op_reg_(out, tc.i32); aux->in_ops[0] = op_reg_(fixed, tc.i32); - aux->clobbers[0] = pool_intern_cstr(tc.c->global, "x20"); + aux->clobbers[0] = pool_intern_slice(tc.c->global, SLICE_LIT("x20")); in->extra.aux = aux; in->ndefs = 1; in->defs = arena_array(f->arena, Val, 1); diff --git a/test/parse/harness/parse_runner.c b/test/parse/harness/parse_runner.c @@ -342,7 +342,7 @@ static int add_runtime_archive(CfreeLinkArchiveInput* rt_archive, path = "build/rt/x86_64-linux/libcfree_rt.a"; if (read_file(path, &data, &len) != 0) return 0; memset(rt_archive, 0, sizeof *rt_archive); - rt_archive->bytes.name = path; + rt_archive->name = cfree_slice_cstr(path); rt_archive->bytes.data = data; rt_archive->bytes.len = len; *rt_data_out = data; @@ -351,7 +351,8 @@ static int add_runtime_archive(CfreeLinkArchiveInput* rt_archive, static CfreeStatus compile_c_obj(CfreeCompiler* c, const CfreeCCompileOptions* opts, - const CfreeBytes* in, CfreeObjBuilder** out) { + CfreeSlice name, const CfreeSlice* in, + CfreeObjBuilder** out) { CfreeCompileSessionOptions sopts; CfreeCompileSession* session = NULL; CfreeSourceInput sin; @@ -362,6 +363,7 @@ static CfreeStatus compile_c_obj(CfreeCompiler* c, sopts.compile.diagnostics = opts->diagnostics; sopts.compile.language_options = opts; memset(&sin, 0, sizeof(sin)); + sin.name = name; sin.bytes = *in; sin.lang = CFREE_LANG_C; st = cfree_compile_session_new(c, &sopts, &session); @@ -372,9 +374,10 @@ static CfreeStatus compile_c_obj(CfreeCompiler* c, static CfreeStatus compile_c_emit(CfreeCompiler* c, const CfreeCCompileOptions* opts, - const CfreeBytes* in, CfreeWriter* w) { + CfreeSlice name, const CfreeSlice* in, + CfreeWriter* w) { CfreeObjBuilder* ob = NULL; - CfreeStatus st = compile_c_obj(c, opts, in, &ob); + CfreeStatus st = compile_c_obj(c, opts, name, in, &ob); if (st == CFREE_OK && !opts->code.emit_c_source) st = cfree_obj_builder_emit(ob, w); cfree_obj_builder_free(ob); @@ -390,7 +393,7 @@ static int mode_emit_impl(const char* src_path, const char* out_path, CfreeTarget tgt; CfreeContext ctx; CfreeCompiler* c = NULL; - CfreeBytes in; + CfreeSlice in; CfreeCCompileOptions opts; CfreeWriter* w = NULL; int rc = 0; @@ -409,7 +412,6 @@ static int mode_emit_impl(const char* src_path, const char* out_path, return 2; } memset(&in, 0, sizeof in); - in.name = src_path; in.data = src; in.len = src_len; @@ -424,7 +426,7 @@ static int mode_emit_impl(const char* src_path, const char* out_path, opts.code.emit_c_source = true; opts.code.c_source_writer = w; } - if (compile_c_emit(c, &opts, &in, w) != CFREE_OK) { + if (compile_c_emit(c, &opts, cfree_slice_cstr(src_path), &in, w) != CFREE_OK) { cfree_writer_close(w); cfree_compiler_free(c); free(src); @@ -470,7 +472,7 @@ static int mode_jit(const char* src_path) { CfreeTarget tgt; CfreeContext ctx; CfreeCompiler* c = NULL; - CfreeBytes in; + CfreeSlice in; CfreeCCompileOptions opts; CfreeObjBuilder* ob = NULL; CfreeLinkArchiveInput rt_archive; @@ -493,14 +495,14 @@ static int mode_jit(const char* src_path) { return 2; } memset(&in, 0, sizeof in); - in.name = src_path; in.data = src; in.len = src_len; memset(&opts, 0, sizeof opts); opts.code.opt_level = opt_level_from_env(); add_test_system_includes(&opts); - if (compile_c_obj(c, &opts, &in, &ob) != CFREE_OK || !ob) { + if (compile_c_obj(c, &opts, cfree_slice_cstr(src_path), &in, &ob) != CFREE_OK || + !ob) { cfree_compiler_free(c); free(src); return 1; @@ -508,7 +510,7 @@ static int mode_jit(const char* src_path) { memset(&lopts, 0, sizeof lopts); lopts.output_kind = CFREE_LINK_OUTPUT_JIT; - lopts.entry = "test_main"; + lopts.entry = CFREE_SLICE_LIT("test_main"); memset(&jhost, 0, sizeof jhost); jhost.execmem = &g_execmem; @@ -531,14 +533,14 @@ static int mode_jit(const char* src_path) { } cfree_link_session_free(link); - fn = (int (*)(void))cfree_jit_lookup(jit, "test_main"); + fn = (int (*)(void))cfree_jit_lookup(jit, CFREE_SLICE_LIT("test_main")); #if defined(__aarch64__) || defined(__arm64__) { - char* td_start = (char*)cfree_jit_lookup(jit, "__tdata_start"); - char* td_end = (char*)cfree_jit_lookup(jit, "__tdata_end"); + char* td_start = (char*)cfree_jit_lookup(jit, CFREE_SLICE_LIT("__tdata_start")); + char* td_end = (char*)cfree_jit_lookup(jit, CFREE_SLICE_LIT("__tdata_end")); unsigned long bs_n = - (unsigned long)(unsigned long long)cfree_jit_lookup(jit, "__tbss_size"); + (unsigned long)(unsigned long long)cfree_jit_lookup(jit, CFREE_SLICE_LIT("__tbss_size")); if (td_start && td_end) { unsigned long td_n = (unsigned long)(td_end - td_start); unsigned long i; diff --git a/test/wasm/harness/wasm_tool.c b/test/wasm/harness/wasm_tool.c @@ -120,9 +120,8 @@ int main(int argc, char** argv) { free(src); return 2; } - CfreeBytes in; + CfreeSlice in; memset(&in, 0, sizeof in); - in.name = argv[2]; in.data = src; in.len = src_len; int rc = cfree_wasm_wat_to_wasm(c, &in, w);