kit

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

commit b2c078511489aa871aed0d68e564019ee8c02760
parent d1144788d5d7e4b65ab69dff577f284420eefc8c
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Mon, 25 May 2026 17:12:02 -0700

Add split section codegen flags

Diffstat:
MMakefile | 20++++++++++++++++----
Mdriver/cc.c | 20++++++++++++++++++++
Minclude/cfree/core.h | 4++++
Msrc/cg/data.c | 30++++++++++++++++++++++++------
Msrc/cg/internal.h | 4++++
Msrc/cg/session.c | 16+++++++++++++---
Msrc/cg/symbol.c | 31+++++++++++++++++++++++++++++++
7 files changed, 112 insertions(+), 13 deletions(-)

diff --git a/Makefile b/Makefile @@ -444,8 +444,19 @@ BOOTSTRAP_STAGE1_BIN = $(BOOTSTRAP_STAGE1_DIR)/cfree BOOTSTRAP_STAGE2_BIN = $(BOOTSTRAP_STAGE2_DIR)/cfree BOOTSTRAP_STAGE3_BIN = $(BOOTSTRAP_STAGE3_DIR)/cfree BOOTSTRAP_TOOLS = cc ld ar ranlib as +BOOTSTRAP_HOST_MODE_CFLAGS = +BOOTSTRAP_STAMP = $(BOOTSTRAP_DIR)/.stamp +BOOTSTRAP_RT_LIBS = $(addprefix $(RT_BUILD_DIR)/,$(addsuffix /libcfree_rt.a,$(RT_DEFAULT_VARIANTS))) +BOOTSTRAP_MAKEFILES = Makefile mk/config.mk rt/Makefile -bootstrap: $(BIN) rt +ifeq ($(RELEASE),1) +bootstrap $(BOOTSTRAP_STAMP): HOST_OPTFLAGS = -O1 +bootstrap $(BOOTSTRAP_STAMP): BOOTSTRAP_HOST_MODE_CFLAGS = $(HOST_MODE_CFLAGS) +endif + +bootstrap: $(BOOTSTRAP_STAMP) + +$(BOOTSTRAP_STAMP): $(BIN) $(BOOTSTRAP_RT_LIBS) $(BOOTSTRAP_MAKEFILES) rm -rf $(BOOTSTRAP_DIR) @mkdir -p $(BOOTSTRAP_STAGE1_DIR) cp $(BIN) $(BOOTSTRAP_STAGE1_BIN) @@ -454,7 +465,7 @@ bootstrap: $(BIN) rt BUILD_DIR='$(abspath $(BOOTSTRAP_STAGE2_DIR))' \ RELEASE='$(RELEASE)' \ HOST_OPTFLAGS='$(HOST_OPTFLAGS)' \ - HOST_MODE_CFLAGS= \ + HOST_MODE_CFLAGS='$(BOOTSTRAP_HOST_MODE_CFLAGS)' \ HOST_MODE_LDFLAGS= \ CC='$(abspath $(BOOTSTRAP_STAGE1_DIR))/cc' \ AR='$(abspath $(BOOTSTRAP_STAGE1_DIR))/ar' \ @@ -464,15 +475,16 @@ bootstrap: $(BIN) rt BUILD_DIR='$(abspath $(BOOTSTRAP_STAGE3_DIR))' \ RELEASE='$(RELEASE)' \ HOST_OPTFLAGS='$(HOST_OPTFLAGS)' \ - HOST_MODE_CFLAGS= \ + HOST_MODE_CFLAGS='$(BOOTSTRAP_HOST_MODE_CFLAGS)' \ HOST_MODE_LDFLAGS= \ CC='$(abspath $(BOOTSTRAP_STAGE2_DIR))/cc' \ AR='$(abspath $(BOOTSTRAP_STAGE2_DIR))/ar' \ LD='$(abspath $(BOOTSTRAP_STAGE2_DIR))/ld' cmp $(BOOTSTRAP_STAGE2_BIN) $(BOOTSTRAP_STAGE3_BIN) shasum -a 256 $(BOOTSTRAP_STAGE2_BIN) $(BOOTSTRAP_STAGE3_BIN) + @touch $@ -bootstrap-test-toy: bootstrap +bootstrap-test-toy: $(BOOTSTRAP_STAMP) @CFREE='$(abspath $(BOOTSTRAP_STAGE3_BIN))' test/toy/run.sh bench-opt: bin diff --git a/driver/cc.c b/driver/cc.c @@ -119,6 +119,8 @@ typedef struct CcOptions { int emit_asm_source; /* -S */ int opt_level; /* -O0/-O1/-O2 */ int debug_info; /* -g */ + int function_sections; /* -ffunction-sections */ + int data_sections; /* -fdata-sections */ int warnings_are_errors; /* -Werror */ uint32_t max_errors; /* -fmax-errors=N */ CfreeTarget target; /* -target / host */ @@ -1172,6 +1174,22 @@ static int cc_parse(int argc, char** argv, CcOptions* o) { o->freestanding = 0; continue; } + if (driver_streq(a, "-ffunction-sections")) { + o->function_sections = 1; + continue; + } + if (driver_streq(a, "-fno-function-sections")) { + o->function_sections = 0; + continue; + } + if (driver_streq(a, "-fdata-sections")) { + o->data_sections = 1; + continue; + } + if (driver_streq(a, "-fno-data-sections")) { + o->data_sections = 0; + continue; + } if (driver_streq(a, "-nostdinc")) { o->nostdinc = 1; continue; @@ -2113,6 +2131,8 @@ static void cc_fill_c_opts(const CcOptions* o, const CfreePreprocessOptions* pp, copts->code.default_visibility = o->default_visibility; copts->code.emit_c_source = o->emit_c_source ? true : false; copts->code.emit_asm_source = o->emit_asm_source ? true : false; + copts->code.function_sections = o->function_sections ? true : false; + copts->code.data_sections = o->data_sections ? true : false; copts->code.epoch = o->epoch; copts->code.path_map = o->npath_map ? o->path_map : NULL; copts->code.npath_map = o->npath_map; diff --git a/include/cfree/core.h b/include/cfree/core.h @@ -216,6 +216,10 @@ typedef struct CfreeCodeOptions { * machine-code path runs, and the assembled bytes are disassembled into * GAS-syntax text after compilation. Implies compile_only / no link. */ bool emit_asm_source; + /* Place each defined function/object with a linker-visible symbol in a + * per-symbol section when no explicit frontend section was requested. */ + bool function_sections; + bool data_sections; uint64_t epoch; /* reproducible timestamp seed; 0 means no timestamp */ const CfreePathPrefixMap* path_map; uint32_t npath_map; diff --git a/src/cg/data.c b/src/cg/data.c @@ -66,6 +66,7 @@ void cfree_cg_data_begin(CfreeCg* g, CfreeCgSym cg_sym, SecKind sec_kind; u16 sec_flags; Sym sec_name_sym; + Slice split_base; ObjSecId sec; CfreeCgDecl decl_attrs; if (!g) return; @@ -114,17 +115,26 @@ void cfree_cg_data_begin(CfreeCg* g, CfreeCgSym cg_sym, if (!attrs.section && decl_attrs.as.object.section) { attrs.section = decl_attrs.as.object.section; } + split_base = SLICE_NULL; if ((decl_attrs.as.object.flags & CFREE_CG_OBJ_TLS) && (attrs.flags & CFREE_CG_DATADEF_ZERO_FILL)) { sec_kind = SEC_BSS; sec_flags = SF_ALLOC | SF_WRITE | SF_TLS; - sec_name_sym = attrs.section ? (Sym)attrs.section : obj_secname_tbss(c); + if (attrs.section) { + sec_name_sym = (Sym)attrs.section; + } else { + sec_name_sym = obj_secname_tbss(c); + split_base = pool_slice(c->global, sec_name_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_slice(c->global, SLICE_LIT(".bss")); + if (attrs.section) { + sec_name_sym = (Sym)attrs.section; + } else { + split_base = SLICE_LIT(".bss"); + sec_name_sym = pool_intern_slice(c->global, split_base); + } } else if (attrs.section) { sec_name_sym = (Sym)attrs.section; if (attrs.flags & CFREE_CG_DATADEF_READONLY) { @@ -138,15 +148,23 @@ 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_slice(c->global, SLICE_LIT(".rodata")); + split_base = SLICE_LIT(".rodata"); + sec_name_sym = pool_intern_slice(c->global, split_base); } else if (decl_attrs.as.object.flags & CFREE_CG_OBJ_TLS) { sec_kind = SEC_DATA; sec_flags = SF_ALLOC | SF_WRITE | SF_TLS; sec_name_sym = obj_secname_tdata(c); + split_base = pool_slice(c->global, sec_name_sym); } else { sec_kind = SEC_DATA; sec_flags = SF_ALLOC | SF_WRITE; - sec_name_sym = pool_intern_slice(c->global, SLICE_LIT(".data")); + split_base = SLICE_LIT(".data"); + sec_name_sym = pool_intern_slice(c->global, split_base); + } + if (!attrs.section && g->data_sections && split_base.len) { + Sym split_name = + api_cg_symbol_section_name(g, split_base, decl_attrs.linkage_name); + if (split_name) sec_name_sym = split_name; } if (attrs.flags & CFREE_CG_DATADEF_RETAIN) sec_flags |= SF_RETAIN; if (attrs.flags & CFREE_CG_DATADEF_MERGE) sec_flags |= SF_MERGE; diff --git a/src/cg/internal.h b/src/cg/internal.h @@ -158,6 +158,9 @@ struct CfreeCg { u32 rodata_counter; int opt_level; u8 check_only; + u8 function_sections; + u8 data_sections; + u8 section_pad[1]; ObjSecId data_sec; ObjSymId data_sym; @@ -366,6 +369,7 @@ void cfree_cg_func_end(CfreeCg* g); SymBind api_map_bind(CfreeSymBind b); SymVis api_map_vis(CfreeCgVisibility v); SymKind api_decl_sym_kind(CfreeCgDecl decl); +Sym api_cg_symbol_section_name(CfreeCg* g, Slice base, CfreeSym linkage_name); void api_remember_sym(CfreeCg* g, ObjSymId sym, CfreeCgTypeId ty, CfreeCgDecl decl); CfreeCgTypeId api_sym_type(CfreeCg* g, CfreeCgSym sym); diff --git a/src/cg/session.c b/src/cg/session.c @@ -61,6 +61,8 @@ static void cg_free_obj_state(CfreeCg* g) { g->nscopes = 0; g->scope_generation = 0; g->rodata_counter = 0; + g->function_sections = 0; + g->data_sections = 0; g->data_sec = OBJ_SEC_NONE; g->data_sym = OBJ_SYM_NONE; g->data_base = 0; @@ -125,6 +127,8 @@ CfreeStatus cfree_cg_begin_obj(CfreeCg* g, CfreeObjBuilder* out, g->debug = target->debug; g->opt_level = opt_level; g->check_only = (opts && opts->check_only) ? 1u : 0u; + g->function_sections = (opts && opts->function_sections) ? 1u : 0u; + g->data_sections = (opts && opts->data_sections) ? 1u : 0u; return CFREE_OK; } @@ -250,6 +254,7 @@ void cfree_cg_func_begin_attrs(CfreeCg* g, CfreeCgSym cg_sym, CfreeCgTypeId fty; const ABIFuncInfo* abi; CfreeCgDecl attrs; + Sym sec_name; if (!g) return; c = g->c; ob = g->obj; @@ -260,9 +265,14 @@ 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_slice(c->global, SLICE_LIT(".text")), - SEC_TEXT, - SF_EXEC | SF_ALLOC, 4); + sec_name = begin_attrs.section ? (Sym)begin_attrs.section + : (Sym)attrs.as.func.section; + if (!sec_name && g->function_sections) { + sec_name = + api_cg_symbol_section_name(g, SLICE_LIT(".text"), attrs.linkage_name); + } + if (!sec_name) sec_name = pool_intern_slice(c->global, SLICE_LIT(".text")); + text_sec = obj_section(ob, sec_name, SEC_TEXT, SF_EXEC | SF_ALLOC, 4); if (sym != OBJ_SYM_NONE) { obj_symbol_define(ob, sym, text_sec, 0, 0); diff --git a/src/cg/symbol.c b/src/cg/symbol.c @@ -33,6 +33,37 @@ SymKind api_decl_sym_kind(CfreeCgDecl decl) { return SK_OBJ; } +Sym api_cg_symbol_section_name(CfreeCg* g, Slice base, CfreeSym linkage_name) { + Compiler* c; + Heap* h; + Slice name; + size_t len; + char* buf; + Sym out; + if (!g || !base.len || !linkage_name) return 0; + c = g->c; + name = pool_slice(c->global, (Sym)linkage_name); + if (!name.len) return 0; + if (base.len > SIZE_MAX - 2u || name.len > SIZE_MAX - base.len - 2u) { + compiler_panic(c, api_no_loc(), "CfreeCg: section name too long"); + return 0; + } + len = base.len + 1u + name.len; + h = c->ctx->heap; + buf = (char*)h->alloc(h, len + 1u, 1); + if (!buf) { + compiler_panic(c, api_no_loc(), "CfreeCg: oom building section name"); + return 0; + } + memcpy(buf, base.s, base.len); + buf[base.len] = '.'; + memcpy(buf + base.len + 1u, name.s, name.len); + buf[len] = '\0'; + out = pool_intern_slice(c->global, (Slice){.s = buf, .len = len}); + h->free(h, buf, len + 1u); + return out; +} + void api_remember_sym(CfreeCg* g, ObjSymId sym, CfreeCgTypeId ty, CfreeCgDecl decl) { Heap* h;