kit

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

commit 9d57dd046e198673042c8cfca233666f7bfc7480
parent 4e8b7ce43241e6eab39044bd54f6eaaa72b02b8e
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Tue, 19 May 2026 17:36:33 -0700

Emit Mach-O TLV descriptors for TLS data

Diffstat:
Msrc/cg/data.c | 154+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/cg/internal.h | 8++++++++
2 files changed, 162 insertions(+), 0 deletions(-)

diff --git a/src/cg/data.c b/src/cg/data.c @@ -1,4 +1,49 @@ #include "cg/internal.h" +#include "core/vec.h" + +static void api_data_tls_write_zero(CfreeCg* g, uint64_t size); + +static void api_data_tls_ensure_materialized(CfreeCg* g) { + if (!g || !g->data_tls_collect || !g->data_tls_zero_fill) return; + if (g->data_size) api_data_tls_write_zero(g, g->data_size); + g->data_tls_zero_fill = 0; +} + +static void api_data_tls_write(CfreeCg* g, const void* data, size_t len) { + if (!g || !len) return; + api_data_tls_ensure_materialized(g); + buf_write(&g->data_tls_bytes, data, len); + g->data_size += len; +} + +static void api_data_tls_write_zero(CfreeCg* g, uint64_t size) { + u8 pad[64]; + if (!g || !size) return; + memset(pad, 0, sizeof pad); + while (size >= sizeof pad) { + buf_write(&g->data_tls_bytes, pad, sizeof pad); + size -= sizeof pad; + } + if (size) buf_write(&g->data_tls_bytes, pad, (size_t)size); +} + +static void api_data_tls_reloc(CfreeCg* g, CfreeCgSym target, int64_t addend, + RelocKind kind) { + Heap* h; + ObjTlsReloc* r; + if (!g || kind == R_NONE) return; + api_data_tls_ensure_materialized(g); + h = (Heap*)g->c->ctx->heap; + if (VEC_GROW(h, g->data_tls_relocs, g->data_tls_relocs_cap, + g->data_tls_nrelocs + 1u)) { + compiler_panic(g->c, api_no_loc(), "CfreeCg: oom on TLS data relocs"); + } + r = &g->data_tls_relocs[g->data_tls_nrelocs++]; + r->offset = (u32)g->data_size; + r->kind = kind; + r->target = (ObjSymId)target; + r->addend = addend; +} void cfree_cg_data_begin(CfreeCg* g, CfreeCgSym cg_sym, CfreeCgDataDefAttrs attrs) { @@ -21,6 +66,22 @@ void cfree_cg_data_begin(CfreeCg* g, CfreeCgSym cg_sym, decl_attrs = api_sym_attrs(g, cg_sym); align = attrs.align ? attrs.align : (u32)abi_cg_alignof(c->abi, decl_attrs.type); + + if ((decl_attrs.as.object.flags & CFREE_CG_OBJ_TLS) && + obj_format_tls_via_descriptor(c)) { + g->data_sec = OBJ_SEC_NONE; + g->data_sym = sym; + g->data_base = 0; + g->data_size = 0; + g->data_tls_collect = 1; + g->data_tls_zero_fill = + (attrs.flags & CFREE_CG_DATADEF_ZERO_FILL) ? 1u : 0u; + g->data_tls_align = align ? align : 1u; + g->data_tls_nrelocs = 0; + buf_init(&g->data_tls_bytes, (Heap*)c->ctx->heap); + return; + } + if (!attrs.section && decl_attrs.as.object.section) { attrs.section = decl_attrs.as.object.section; } @@ -99,6 +160,20 @@ void cfree_cg_data_common(CfreeCg* g, CfreeCgSym cg_sym, uint64_t size, } void cfree_cg_data_align(CfreeCg* g, uint32_t align) { + if (g && g->data_tls_collect) { + u32 a = align ? align : 1u; + u64 base = (g->data_size + (a - 1u)) & ~(u64)(a - 1u); + u64 pad = base - g->data_size; + if (pad) { + if (g->data_tls_zero_fill) { + g->data_size += pad; + } else { + api_data_tls_write_zero(g, pad); + g->data_size += pad; + } + } + return; + } if (!g || g->data_sec == OBJ_SEC_NONE || !align) return; g->data_size = obj_align_to(g->obj, g->data_sec, align) - g->data_base; } @@ -106,6 +181,24 @@ void cfree_cg_data_align(CfreeCg* g, uint32_t align) { void cfree_cg_data_pad(CfreeCg* g, uint64_t size, uint8_t value) { u8 pad[64]; if (!g || !size) return; + if (g->data_tls_collect) { + if (value == 0 && g->data_tls_zero_fill) { + g->data_size += size; + return; + } + api_data_tls_ensure_materialized(g); + memset(pad, value, sizeof pad); + while (size >= sizeof pad) { + buf_write(&g->data_tls_bytes, pad, sizeof pad); + size -= sizeof pad; + g->data_size += sizeof pad; + } + if (size) { + buf_write(&g->data_tls_bytes, pad, (size_t)size); + g->data_size += size; + } + return; + } memset(pad, value, sizeof(pad)); while (size >= sizeof(pad)) { obj_write(g->obj, g->data_sec, pad, sizeof(pad)); @@ -176,6 +269,10 @@ void cfree_cg_data_float(CfreeCg* g, double value, CfreeCgTypeId type) { void cfree_cg_data_bytes(CfreeCg* g, const uint8_t* data, size_t len) { if (!g || !len) return; + if (g->data_tls_collect) { + api_data_tls_write(g, data, len); + return; + } obj_write(g->obj, g->data_sec, data, len); g->data_size += len; } @@ -183,6 +280,15 @@ void cfree_cg_data_bytes(CfreeCg* g, const uint8_t* data, size_t len) { void cfree_cg_data_zero(CfreeCg* g, uint64_t size) { const Section* sec; if (!g || !size) return; + if (g->data_tls_collect) { + if (g->data_tls_zero_fill) { + g->data_size += size; + } else { + api_data_tls_write_zero(g, size); + g->data_size += size; + } + return; + } sec = obj_section_get(g->obj, g->data_sec); if (sec && (sec->kind == SEC_BSS || sec->sem == SSEM_NOBITS)) { obj_reserve_bss(g->obj, g->data_sec, @@ -212,6 +318,12 @@ void api_cg_data_reloc(CfreeCg* g, CfreeCgSym target, int64_t addend, ob = g->obj; rk = api_data_reloc_kind(pcrel, width); if (rk == R_NONE) return; + if (g->data_tls_collect) { + api_data_tls_reloc(g, target, addend, rk); + memset(pad, 0, sizeof pad); + api_data_tls_write(g, pad, width); + return; + } memset(pad, 0, sizeof pad); obj_write(ob, g->data_sec, pad, width); obj_reloc(ob, g->data_sec, g->data_base + (u32)g->data_size, rk, @@ -235,6 +347,10 @@ void cfree_cg_data_label_addr(CfreeCg* g, CfreeCgLabel target, int64_t addend, u32 shift = g->c->target.big_endian ? (width - 1u - i) * 8u : i * 8u; pad[i] = (u8)(((uint64_t)target + (uint64_t)addend) >> shift); } + if (g->data_tls_collect) { + api_data_tls_write(g, pad, width); + return; + } obj_write(g->obj, g->data_sec, pad, width); g->data_size += width; } @@ -271,6 +387,12 @@ void cfree_cg_data_symdiff(CfreeCg* g, CfreeCgSym lhs, CfreeCgSym rhs, return; } memset(pad, 0, sizeof(pad)); + if (g->data_tls_collect) { + api_data_tls_reloc(g, lhs, addend, add_kind); + api_data_tls_reloc(g, rhs, 0, sub_kind); + api_data_tls_write(g, pad, width); + return; + } obj_write(g->obj, g->data_sec, pad, width); obj_reloc(g->obj, g->data_sec, g->data_base + (u32)g->data_size, add_kind, (ObjSymId)lhs, addend); @@ -280,7 +402,39 @@ void cfree_cg_data_symdiff(CfreeCg* g, CfreeCgSym lhs, CfreeCgSym rhs, } void cfree_cg_data_end(CfreeCg* g) { + Heap* h; + u8* flat; if (!g) return; + if (g->data_tls_collect) { + h = (Heap*)g->c->ctx->heap; + flat = NULL; + if (!g->data_tls_zero_fill && g->data_size) { + flat = (u8*)h->alloc(h, (size_t)g->data_size, 1); + if (!flat) + compiler_panic(g->c, api_no_loc(), "CfreeCg: oom on TLS data bytes"); + buf_flatten(&g->data_tls_bytes, flat); + } + obj_define_tls(g->c, g->obj, g->data_sym, + g->data_tls_zero_fill ? NULL : flat, (u32)g->data_size, + g->data_tls_zero_fill ? 0 : 1, g->data_tls_align, + g->data_tls_relocs, g->data_tls_nrelocs); + if (flat) h->free(h, flat, (size_t)g->data_size); + buf_fini(&g->data_tls_bytes); + if (g->data_tls_relocs) + h->free(h, g->data_tls_relocs, + sizeof(*g->data_tls_relocs) * g->data_tls_relocs_cap); + g->data_tls_relocs = NULL; + g->data_tls_relocs_cap = 0; + g->data_tls_nrelocs = 0; + g->data_tls_collect = 0; + g->data_tls_zero_fill = 0; + g->data_tls_align = 0; + g->data_sec = OBJ_SEC_NONE; + g->data_sym = OBJ_SYM_NONE; + g->data_base = 0; + g->data_size = 0; + return; + } if (g->data_sym != OBJ_SYM_NONE) { obj_symbol_define(g->obj, g->data_sym, g->data_sec, g->data_base, g->data_size); diff --git a/src/cg/internal.h b/src/cg/internal.h @@ -160,6 +160,14 @@ struct CfreeCg { ObjSymId data_sym; u32 data_base; u64 data_size; + u8 data_tls_collect; + u8 data_tls_zero_fill; + u8 data_tls_pad[2]; + u32 data_tls_align; + Buf data_tls_bytes; + ObjTlsReloc* data_tls_relocs; + u32 data_tls_nrelocs; + u32 data_tls_relocs_cap; }; void cg_api_fini(Compiler*);