kit

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

commit 1b5a72b7bfb642b0a17e7e5cb8236930bd3a6fab
parent ca3d78eacf3e52586542094ebca90c079b9d9edd
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Tue, 19 May 2026 16:12:13 -0700

Reorganize public API bridge files

Diffstat:
Dsrc/api/ar.c | 435-------------------------------------------------------------------------------
Asrc/api/arch.c | 36++++++++++++++++++++++++++++++++++++
Dsrc/api/arch_regs.c | 36------------------------------------
Asrc/api/archive.c | 435+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/api/compile.c | 408+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/api/core.c | 193+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/api/dep.c | 59-----------------------------------------------------------
Msrc/api/frontend.c | 43-------------------------------------------
Dsrc/api/lifecycle.c | 158-------------------------------------------------------------------------------
Asrc/api/link.c | 168+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/api/objbuilder.c | 214-------------------------------------------------------------------------------
Asrc/api/object_builder.c | 214+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Rsrc/api/detect.c -> src/api/object_detect.c | 0
Asrc/api/object_file.c | 375+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/api/objfile.c | 376-------------------------------------------------------------------------------
Dsrc/api/pipeline.c | 351-------------------------------------------------------------------------------
Asrc/api/source.c | 64++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/api/support_arena.c | 45+++++++++++++++++++++++++++++++++++++++++++++
Dsrc/api/writer_mem.c | 110-------------------------------------------------------------------------------
Dsrc/link/link_api.c | 168-------------------------------------------------------------------------------
20 files changed, 1938 insertions(+), 1950 deletions(-)

diff --git a/src/api/ar.c b/src/api/ar.c @@ -1,435 +0,0 @@ -/* POSIX ar archive reader/writer. */ - -#include <cfree/archive.h> -#include <cfree/object.h> - -#include "core/bytes.h" -#include "core/core.h" -#include "core/heap.h" - -/* ============================================================ - * Write helpers - * ============================================================ */ - -static CfreeStatus wh_bytes(Writer* w, const void* p, size_t n) { - return cfree_writer_write(w, p, n); -} -static CfreeStatus wh_char(Writer* w, char c) { - return cfree_writer_write(w, &c, 1); -} -static CfreeStatus wh_nl(Writer* w) { return wh_char(w, '\n'); } - -static void wh_ar_num(char* dst, int width, u64 v) { - char tmp[20]; - int len = 0, i; - if (v == 0) { - tmp[len++] = '0'; - } else { - u64 t = v; - while (t) { - tmp[len++] = '0' + (int)(t % 10); - t /= 10; - } - } - for (i = 0; i < len / 2; ++i) { - char x = tmp[i]; - tmp[i] = tmp[len - 1 - i]; - tmp[len - 1 - i] = x; - } - for (i = 0; i < len && i < width; ++i) dst[i] = tmp[i]; - for (; i < width; ++i) dst[i] = ' '; -} - -static CfreeStatus wh_be32(Writer* w, u32 v) { - u8 b[4]; - wr_u32_be(b, 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; - } - for (p = name; *p; ++p) ++namelen; - *name_out = name; - *len_out = namelen; -} - -static int ar_name_needs_longtable(const char* name, size_t len) { - size_t i; - if (len > 15) return 1; - for (i = 0; i < len; ++i) - if (name[i] == '/') return 1; - 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], - uint64_t epoch, uint64_t size) { - size_t j; - for (j = 0; j < 16; ++j) hdr[j] = name_field[j]; - for (j = 16; j < 28; ++j) hdr[j] = ' '; - if (epoch) - wh_ar_num(hdr + 16, 12, epoch); - else - hdr[16] = '0'; - for (j = 28; j < 34; ++j) hdr[j] = ' '; - hdr[28] = '0'; - for (j = 34; j < 40; ++j) hdr[j] = ' '; - hdr[34] = '0'; - for (j = 40; j < 48; ++j) hdr[j] = ' '; - hdr[40] = '6'; - hdr[41] = '4'; - hdr[42] = '4'; - wh_ar_num(hdr + 48, 10, size); - hdr[58] = '`'; - hdr[59] = '\n'; -} - -CfreeStatus cfree_ar_write(CfreeWriter* out, const CfreeBytes* members, - uint32_t nmembers, const CfreeArWriteOptions* opts) { - static const char magic[] = "!<arch>\n"; - static const CfreeArWriteOptions default_opts = {0, 0, 0, NULL}; - uint32_t i; - uint64_t epoch; - int long_names; - int symbol_index; - const CfreeArMemberSymbols* msyms; - uint64_t longtab_size = 0; - uint32_t nsyms = 0; - uint64_t names_size = 0; - uint64_t index_payload = 0; - uint64_t index_total = 0; - uint64_t longtab_total = 0; - char pad = '\n'; - - if (!out) return CFREE_INVALID; - if (!members && nmembers) return CFREE_INVALID; - - if (!opts) opts = &default_opts; - epoch = opts->epoch; - long_names = opts->long_names; - symbol_index = opts->symbol_index; - msyms = opts->member_symbols; - - 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; - } - } - } else { - for (i = 0; i < nmembers; ++i) { - if (!members[i].name) return CFREE_INVALID; - } - } - - if (symbol_index) { - if (msyms) { - for (i = 0; i < nmembers; ++i) { - 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; - nsyms += 1; - names_size += (uint64_t)ar_strlen(nm) + 1; - } - } - } - index_payload = (uint64_t)4 + (uint64_t)4 * (uint64_t)nsyms + names_size; - index_total = 60 + index_payload + (index_payload & 1); - } - if (longtab_size) { - longtab_total = 60 + longtab_size + (longtab_size & 1); - } - - wh_bytes(out, magic, 8); - - if (symbol_index) { - char hdr[60]; - char name_field[16]; - size_t j; - uint64_t cur_offset; - - for (j = 0; j < 16; ++j) name_field[j] = ' '; - name_field[0] = '/'; - ar_fill_header(hdr, name_field, epoch, index_payload); - wh_bytes(out, hdr, 60); - - wh_be32(out, nsyms); - - cur_offset = (uint64_t)8 + index_total + longtab_total; - if (msyms) { - for (i = 0; i < nmembers; ++i) { - u32 k; - for (k = 0; k < msyms[i].count; ++k) { - wh_be32(out, (u32)cur_offset); - } - cur_offset += ar_member_padded_size(members[i].len); - } - } - - if (msyms) { - 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); - } - } - } - - if (index_payload & 1) wh_bytes(out, &pad, 1); - } - - if (longtab_size) { - char hdr[60]; - char name_field[16]; - size_t j; - for (j = 0; j < 16; ++j) name_field[j] = ' '; - name_field[0] = '/'; - name_field[1] = '/'; - 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); - wh_bytes(out, "/\n", 2); - } - } - if (longtab_size & 1) wh_bytes(out, &pad, 1); - } - - { - uint64_t longtab_off = 0; - for (i = 0; i < nmembers; ++i) { - const CfreeBytes* m = &members[i]; - const char* name; - size_t namelen; - 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)) { - name_field[0] = '/'; - wh_ar_num(name_field + 1, 15, longtab_off); - longtab_off += (uint64_t)namelen + 2; - } else { - size_t emit = namelen > 15 ? 15 : namelen; - for (j = 0; j < emit; ++j) name_field[j] = name[j]; - name_field[emit] = '/'; - } - - ar_fill_header(hdr, name_field, epoch, (uint64_t)m->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); - } - } - - return cfree_writer_status(out); -} - -/* ============================================================ - * Read (iterator) and list - * ============================================================ */ - -#define AR_NAMEBUF 256 - -struct CfreeArIter { - const CfreeContext* ctx; - const u8* p; - const u8* end; - const u8* longnames; - size_t longnames_len; - char namebuf[AR_NAMEBUF]; -}; - -static size_t ar_resolve_longname(CfreeArIter* it, uint64_t off) { - size_t i; - if (!it->longnames) return 0; - if (off >= it->longnames_len) return 0; - for (i = 0; i + 1 < sizeof(it->namebuf); ++i) { - size_t k = (size_t)off + i; - char ch; - if (k >= it->longnames_len) break; - ch = (char)it->longnames[k]; - if (ch == '/' || ch == '\n') break; - it->namebuf[i] = ch; - } - it->namebuf[i] = '\0'; - return i; -} - -CfreeStatus cfree_ar_iter_new(const CfreeContext* ctx, const CfreeBytes* archive, - CfreeArIter** out) { - Heap* h; - CfreeArIter* it; - if (!out) return CFREE_INVALID; - if (!ctx || !ctx->heap || !archive) return CFREE_INVALID; - if (!archive->data && archive->len) return CFREE_INVALID; - if (cfree_detect_fmt(archive->data, archive->len) != CFREE_BIN_AR) - return CFREE_MALFORMED; - h = ctx->heap; - it = (CfreeArIter*)h->alloc(h, sizeof(*it), _Alignof(CfreeArIter)); - if (!it) return CFREE_NOMEM; - it->ctx = ctx; - it->p = archive->data + 8; - it->end = archive->data + archive->len; - it->longnames = NULL; - it->longnames_len = 0; - it->namebuf[0] = '\0'; - *out = it; - return CFREE_OK; -} - -CfreeIterResult cfree_ar_iter_next(CfreeArIter* it, CfreeArMember* out) { - if (!it || !out) return CFREE_ITER_ERROR; - for (;;) { - uint64_t size; - size_t avail; - int j; - int namelen; - char name_field[16]; - - if (it->p + 60 > it->end) return CFREE_ITER_END; - - for (j = 0; j < 16; ++j) name_field[j] = (char)it->p[j]; - - size = 0; - for (j = 48; j < 58; ++j) { - char ch = (char)it->p[j]; - if (ch < '0' || ch > '9') break; - size = size * 10 + (uint64_t)(unsigned char)(ch - '0'); - } - - it->p += 60; - avail = (size_t)(it->end - it->p); - if ((uint64_t)avail < size) return CFREE_ITER_END; - - if (name_field[0] == '/' && name_field[1] == '/') { - it->longnames = it->p; - it->longnames_len = (size_t)size; - goto advance; - } - if (name_field[0] == '/' && name_field[1] == ' ') { - goto advance; - } - - if (name_field[0] == '/' && name_field[1] >= '0' && name_field[1] <= '9') { - uint64_t off = 0; - for (j = 1; j < 16; ++j) { - char ch = name_field[j]; - if (ch < '0' || ch > '9') break; - off = off * 10 + (uint64_t)(unsigned char)(ch - '0'); - } - namelen = (int)ar_resolve_longname(it, off); - } else if (name_field[0] == '#' && name_field[1] == '1' && - name_field[2] == '/') { - uint64_t nlen = 0; - size_t k; - for (j = 3; j < 16; ++j) { - char ch = name_field[j]; - if (ch < '0' || ch > '9') break; - nlen = nlen * 10 + (uint64_t)(unsigned char)(ch - '0'); - } - if (nlen > size || nlen + 1 > sizeof(it->namebuf)) - return CFREE_ITER_ERROR; - namelen = 0; - for (k = 0; k < (size_t)nlen; ++k) { - char ch = (char)it->p[k]; - if (ch == '\0') break; - it->namebuf[namelen++] = ch; - } - it->namebuf[namelen] = '\0'; - it->p += (size_t)nlen; - size -= nlen; - } else { - namelen = 0; - for (j = 0; j < 16; ++j) { - char ch = name_field[j]; - if (ch == '/' || ch == ' ' || ch == '\0') break; - it->namebuf[namelen++] = ch; - } - it->namebuf[namelen] = '\0'; - } - - out->name = it->namebuf; - out->data = it->p; - out->size = (size_t)size; - - it->p += (size_t)size; - if ((size & 1) && it->p < it->end) it->p++; - - if (it->namebuf[0] == '_' && it->namebuf[1] == '_' && - it->namebuf[2] == '.') { - continue; - } - if (namelen > 0) return CFREE_ITER_ITEM; - continue; - - advance: - it->p += (size_t)size; - if ((size & 1) && it->p < it->end) it->p++; - } -} - -void cfree_ar_iter_free(CfreeArIter* it) { - Heap* h; - if (!it) return; - h = it->ctx->heap; - h->free(h, it, sizeof(*it)); -} - -CfreeStatus cfree_ar_list(const CfreeBytes* 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; - if (cfree_detect_fmt(archive->data, archive->len) != CFREE_BIN_AR) - return CFREE_MALFORMED; - local.ctx = NULL; - local.p = archive->data + 8; - local.end = archive->data + archive->len; - local.longnames = NULL; - local.longnames_len = 0; - local.namebuf[0] = '\0'; - - 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_nl(out); - } - - return cfree_writer_status(out); -} diff --git a/src/api/arch.c b/src/api/arch.c @@ -0,0 +1,36 @@ +/* Public arch register name API. */ + +#include "arch/arch.h" + +#include <cfree/arch.h> +#include <stddef.h> + +const char* 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); +} + +CfreeStatus cfree_arch_register_index(CfreeArchKind arch, const char* name, + uint32_t* idx_out) { + const ArchImpl* impl; + if (!name || !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; +} + +uint32_t cfree_arch_register_count(CfreeArchKind arch) { + const ArchImpl* impl = arch_lookup(arch); + if (!impl || !impl->register_count) return 0; + return impl->register_count(); +} + +CfreeStatus cfree_arch_register_at(CfreeArchKind arch, uint32_t idx, + CfreeArchReg* out) { + const ArchImpl* impl; + if (!out) return CFREE_INVALID; + impl = arch_lookup(arch); + if (!impl || !impl->register_at) return CFREE_UNSUPPORTED; + return impl->register_at(idx, out) == 0 ? CFREE_OK : CFREE_NOT_FOUND; +} diff --git a/src/api/arch_regs.c b/src/api/arch_regs.c @@ -1,36 +0,0 @@ -/* Public arch register name API. */ - -#include <cfree/arch.h> -#include <stddef.h> - -#include "arch/arch.h" - -const char* 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); -} - -CfreeStatus cfree_arch_register_index(CfreeArchKind arch, const char* name, - uint32_t* idx_out) { - const ArchImpl* impl; - if (!name || !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; -} - -uint32_t cfree_arch_register_count(CfreeArchKind arch) { - const ArchImpl* impl = arch_lookup(arch); - if (!impl || !impl->register_count) return 0; - return impl->register_count(); -} - -CfreeStatus cfree_arch_register_at(CfreeArchKind arch, uint32_t idx, - CfreeArchReg* out) { - const ArchImpl* impl; - if (!out) return CFREE_INVALID; - impl = arch_lookup(arch); - if (!impl || !impl->register_at) return CFREE_UNSUPPORTED; - return impl->register_at(idx, out) == 0 ? CFREE_OK : CFREE_NOT_FOUND; -} diff --git a/src/api/archive.c b/src/api/archive.c @@ -0,0 +1,435 @@ +/* POSIX ar archive reader/writer. */ + +#include <cfree/archive.h> +#include <cfree/object.h> + +#include "core/bytes.h" +#include "core/core.h" +#include "core/heap.h" + +/* ============================================================ + * Write helpers + * ============================================================ */ + +static CfreeStatus wh_bytes(Writer* w, const void* p, size_t n) { + return cfree_writer_write(w, p, n); +} +static CfreeStatus wh_char(Writer* w, char c) { + return cfree_writer_write(w, &c, 1); +} +static CfreeStatus wh_nl(Writer* w) { return wh_char(w, '\n'); } + +static void wh_ar_num(char* dst, int width, u64 v) { + char tmp[20]; + int len = 0, i; + if (v == 0) { + tmp[len++] = '0'; + } else { + u64 t = v; + while (t) { + tmp[len++] = '0' + (int)(t % 10); + t /= 10; + } + } + for (i = 0; i < len / 2; ++i) { + char x = tmp[i]; + tmp[i] = tmp[len - 1 - i]; + tmp[len - 1 - i] = x; + } + for (i = 0; i < len && i < width; ++i) dst[i] = tmp[i]; + for (; i < width; ++i) dst[i] = ' '; +} + +static CfreeStatus wh_be32(Writer* w, u32 v) { + u8 b[4]; + wr_u32_be(b, 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; + } + for (p = name; *p; ++p) ++namelen; + *name_out = name; + *len_out = namelen; +} + +static int ar_name_needs_longtable(const char* name, size_t len) { + size_t i; + if (len > 15) return 1; + for (i = 0; i < len; ++i) + if (name[i] == '/') return 1; + 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], + uint64_t epoch, uint64_t size) { + size_t j; + for (j = 0; j < 16; ++j) hdr[j] = name_field[j]; + for (j = 16; j < 28; ++j) hdr[j] = ' '; + if (epoch) + wh_ar_num(hdr + 16, 12, epoch); + else + hdr[16] = '0'; + for (j = 28; j < 34; ++j) hdr[j] = ' '; + hdr[28] = '0'; + for (j = 34; j < 40; ++j) hdr[j] = ' '; + hdr[34] = '0'; + for (j = 40; j < 48; ++j) hdr[j] = ' '; + hdr[40] = '6'; + hdr[41] = '4'; + hdr[42] = '4'; + wh_ar_num(hdr + 48, 10, size); + hdr[58] = '`'; + hdr[59] = '\n'; +} + +CfreeStatus cfree_ar_write(CfreeWriter* out, const CfreeBytes* members, + uint32_t nmembers, const CfreeArWriteOptions* opts) { + static const char magic[] = "!<arch>\n"; + static const CfreeArWriteOptions default_opts = {0, 0, 0, NULL}; + uint32_t i; + uint64_t epoch; + int long_names; + int symbol_index; + const CfreeArMemberSymbols* msyms; + uint64_t longtab_size = 0; + uint32_t nsyms = 0; + uint64_t names_size = 0; + uint64_t index_payload = 0; + uint64_t index_total = 0; + uint64_t longtab_total = 0; + char pad = '\n'; + + if (!out) return CFREE_INVALID; + if (!members && nmembers) return CFREE_INVALID; + + if (!opts) opts = &default_opts; + epoch = opts->epoch; + long_names = opts->long_names; + symbol_index = opts->symbol_index; + msyms = opts->member_symbols; + + 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; + } + } + } else { + for (i = 0; i < nmembers; ++i) { + if (!members[i].name) return CFREE_INVALID; + } + } + + if (symbol_index) { + if (msyms) { + for (i = 0; i < nmembers; ++i) { + 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; + nsyms += 1; + names_size += (uint64_t)ar_strlen(nm) + 1; + } + } + } + index_payload = (uint64_t)4 + (uint64_t)4 * (uint64_t)nsyms + names_size; + index_total = 60 + index_payload + (index_payload & 1); + } + if (longtab_size) { + longtab_total = 60 + longtab_size + (longtab_size & 1); + } + + wh_bytes(out, magic, 8); + + if (symbol_index) { + char hdr[60]; + char name_field[16]; + size_t j; + uint64_t cur_offset; + + for (j = 0; j < 16; ++j) name_field[j] = ' '; + name_field[0] = '/'; + ar_fill_header(hdr, name_field, epoch, index_payload); + wh_bytes(out, hdr, 60); + + wh_be32(out, nsyms); + + cur_offset = (uint64_t)8 + index_total + longtab_total; + if (msyms) { + for (i = 0; i < nmembers; ++i) { + u32 k; + for (k = 0; k < msyms[i].count; ++k) { + wh_be32(out, (u32)cur_offset); + } + cur_offset += ar_member_padded_size(members[i].len); + } + } + + if (msyms) { + 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); + } + } + } + + if (index_payload & 1) wh_bytes(out, &pad, 1); + } + + if (longtab_size) { + char hdr[60]; + char name_field[16]; + size_t j; + for (j = 0; j < 16; ++j) name_field[j] = ' '; + name_field[0] = '/'; + name_field[1] = '/'; + 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); + wh_bytes(out, "/\n", 2); + } + } + if (longtab_size & 1) wh_bytes(out, &pad, 1); + } + + { + uint64_t longtab_off = 0; + for (i = 0; i < nmembers; ++i) { + const CfreeBytes* m = &members[i]; + const char* name; + size_t namelen; + 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)) { + name_field[0] = '/'; + wh_ar_num(name_field + 1, 15, longtab_off); + longtab_off += (uint64_t)namelen + 2; + } else { + size_t emit = namelen > 15 ? 15 : namelen; + for (j = 0; j < emit; ++j) name_field[j] = name[j]; + name_field[emit] = '/'; + } + + ar_fill_header(hdr, name_field, epoch, (uint64_t)m->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); + } + } + + return cfree_writer_status(out); +} + +/* ============================================================ + * Read (iterator) and list + * ============================================================ */ + +#define AR_NAMEBUF 256 + +struct CfreeArIter { + const CfreeContext* ctx; + const u8* p; + const u8* end; + const u8* longnames; + size_t longnames_len; + char namebuf[AR_NAMEBUF]; +}; + +static size_t ar_resolve_longname(CfreeArIter* it, uint64_t off) { + size_t i; + if (!it->longnames) return 0; + if (off >= it->longnames_len) return 0; + for (i = 0; i + 1 < sizeof(it->namebuf); ++i) { + size_t k = (size_t)off + i; + char ch; + if (k >= it->longnames_len) break; + ch = (char)it->longnames[k]; + if (ch == '/' || ch == '\n') break; + it->namebuf[i] = ch; + } + it->namebuf[i] = '\0'; + return i; +} + +CfreeStatus cfree_ar_iter_new(const CfreeContext* ctx, + const CfreeBytes* archive, CfreeArIter** out) { + Heap* h; + CfreeArIter* it; + if (!out) return CFREE_INVALID; + if (!ctx || !ctx->heap || !archive) return CFREE_INVALID; + if (!archive->data && archive->len) return CFREE_INVALID; + if (cfree_detect_fmt(archive->data, archive->len) != CFREE_BIN_AR) + return CFREE_MALFORMED; + h = ctx->heap; + it = (CfreeArIter*)h->alloc(h, sizeof(*it), _Alignof(CfreeArIter)); + if (!it) return CFREE_NOMEM; + it->ctx = ctx; + it->p = archive->data + 8; + it->end = archive->data + archive->len; + it->longnames = NULL; + it->longnames_len = 0; + it->namebuf[0] = '\0'; + *out = it; + return CFREE_OK; +} + +CfreeIterResult cfree_ar_iter_next(CfreeArIter* it, CfreeArMember* out) { + if (!it || !out) return CFREE_ITER_ERROR; + for (;;) { + uint64_t size; + size_t avail; + int j; + int namelen; + char name_field[16]; + + if (it->p + 60 > it->end) return CFREE_ITER_END; + + for (j = 0; j < 16; ++j) name_field[j] = (char)it->p[j]; + + size = 0; + for (j = 48; j < 58; ++j) { + char ch = (char)it->p[j]; + if (ch < '0' || ch > '9') break; + size = size * 10 + (uint64_t)(unsigned char)(ch - '0'); + } + + it->p += 60; + avail = (size_t)(it->end - it->p); + if ((uint64_t)avail < size) return CFREE_ITER_END; + + if (name_field[0] == '/' && name_field[1] == '/') { + it->longnames = it->p; + it->longnames_len = (size_t)size; + goto advance; + } + if (name_field[0] == '/' && name_field[1] == ' ') { + goto advance; + } + + if (name_field[0] == '/' && name_field[1] >= '0' && name_field[1] <= '9') { + uint64_t off = 0; + for (j = 1; j < 16; ++j) { + char ch = name_field[j]; + if (ch < '0' || ch > '9') break; + off = off * 10 + (uint64_t)(unsigned char)(ch - '0'); + } + namelen = (int)ar_resolve_longname(it, off); + } else if (name_field[0] == '#' && name_field[1] == '1' && + name_field[2] == '/') { + uint64_t nlen = 0; + size_t k; + for (j = 3; j < 16; ++j) { + char ch = name_field[j]; + if (ch < '0' || ch > '9') break; + nlen = nlen * 10 + (uint64_t)(unsigned char)(ch - '0'); + } + if (nlen > size || nlen + 1 > sizeof(it->namebuf)) + return CFREE_ITER_ERROR; + namelen = 0; + for (k = 0; k < (size_t)nlen; ++k) { + char ch = (char)it->p[k]; + if (ch == '\0') break; + it->namebuf[namelen++] = ch; + } + it->namebuf[namelen] = '\0'; + it->p += (size_t)nlen; + size -= nlen; + } else { + namelen = 0; + for (j = 0; j < 16; ++j) { + char ch = name_field[j]; + if (ch == '/' || ch == ' ' || ch == '\0') break; + it->namebuf[namelen++] = ch; + } + it->namebuf[namelen] = '\0'; + } + + out->name = it->namebuf; + out->data = it->p; + out->size = (size_t)size; + + it->p += (size_t)size; + if ((size & 1) && it->p < it->end) it->p++; + + if (it->namebuf[0] == '_' && it->namebuf[1] == '_' && + it->namebuf[2] == '.') { + continue; + } + if (namelen > 0) return CFREE_ITER_ITEM; + continue; + + advance: + it->p += (size_t)size; + if ((size & 1) && it->p < it->end) it->p++; + } +} + +void cfree_ar_iter_free(CfreeArIter* it) { + Heap* h; + if (!it) return; + h = it->ctx->heap; + h->free(h, it, sizeof(*it)); +} + +CfreeStatus cfree_ar_list(const CfreeBytes* 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; + if (cfree_detect_fmt(archive->data, archive->len) != CFREE_BIN_AR) + return CFREE_MALFORMED; + local.ctx = NULL; + local.p = archive->data + 8; + local.end = archive->data + archive->len; + local.longnames = NULL; + local.longnames_len = 0; + local.namebuf[0] = '\0'; + + 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_nl(out); + } + + return cfree_writer_status(out); +} diff --git a/src/api/compile.c b/src/api/compile.c @@ -0,0 +1,408 @@ +/* libcfree's top-level compile entry points. Status-returning shapes + * that drive the C, asm, and registered-frontend paths. */ + +#include <cfree/compile.h> +#include <cfree/core.h> + +#include "arch/arch.h" +#include "asm/asm.h" +#include "core/arena.h" +#include "core/core.h" +#include "core/heap.h" +#include "core/metrics.h" +#include "core/pool.h" +#include "obj/obj.h" + +static SrcLoc no_loc(void) { + SrcLoc loc; + loc.file_id = 0; + loc.line = 0; + loc.col = 0; + return loc; +} + +static _Noreturn void panic_bad_options(Compiler* c, const char* msg) { + compiler_panic(c, no_loc(), "bad cfree options: %s", msg); +} + +CfreeLanguage cfree_language_for_path(const char* path) { + size_t i, len; + if (!path) return CFREE_LANG_C; + for (len = 0; path[len]; ++len) { + } + i = len; + while (i > 0) { + --i; + if (path[i] == '/') return CFREE_LANG_C; + if (path[i] == '.') { + const char* ext = path + i + 1; + if (ext[0] == 's' && ext[1] == '\0') return CFREE_LANG_ASM; + if (ext[0] == 't' && ext[1] == 'o' && ext[2] == 'y' && ext[3] == '\0') + return CFREE_LANG_TOY; + if (ext[0] == 'w' && ext[1] == 'a' && ext[2] == 't' && ext[3] == '\0') + return CFREE_LANG_WASM; + if (ext[0] == 'w' && ext[1] == 'a' && ext[2] == 's' && ext[3] == 'm' && + ext[4] == '\0') + return CFREE_LANG_WASM; + return CFREE_LANG_C; + } + } + return CFREE_LANG_C; +} + +CfreeStatus cfree_register_frontend(CfreeCompiler* c, CfreeLanguage lang, + CfreeCompileFn fn) { + if (!c) return CFREE_INVALID; + if ((unsigned)lang >= CFREE_LANG_COUNT) return CFREE_INVALID; + c->frontends[lang] = fn; + return CFREE_OK; +} + +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) { + panic_bad_options(c, "input data is NULL but len > 0"); + } +} + +static void emit_object_bytes(Compiler* c, ObjBuilder* ob, Writer* w) { + switch (c->target.obj) { + case CFREE_OBJ_ELF: + emit_elf(c, ob, w); + break; + case CFREE_OBJ_COFF: + emit_coff(c, ob, w); + break; + case CFREE_OBJ_MACHO: + emit_macho(c, ob, w); + break; + case CFREE_OBJ_WASM: + emit_wasm(c, ob, w); + break; + } +} + +/* Run the source-input-shaped path. */ +static void compile_source_into(Compiler* c, + const CfreeFrontendCompileOptions* opts, + const CfreeSourceInput* input, ObjBuilder* ob) { + CfreeCompileFn frontend = NULL; + AsmLexer* lex; + MCEmitter* mc; + + if ((unsigned)input->lang < CFREE_LANG_COUNT) { + frontend = c->frontends[input->lang]; + } + if (frontend) { + CfreeStatus st; + metrics_scope_begin(c, "compile.frontend"); + st = frontend(c, 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); + } + metrics_scope_begin(c, "compile.obj_finalize"); + obj_finalize(ob); + metrics_scope_end(c, "compile.obj_finalize"); + metrics_count(c, "compile.obj_sections", obj_section_count(ob)); + metrics_count(c, "compile.obj_relocs", obj_reloc_total(ob)); + return; + } + + if (input->lang == CFREE_LANG_ASM) { + 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); + metrics_scope_end(c, "compile.asm.lex_open"); + metrics_scope_begin(c, "compile.asm.mc_new"); + mc = mc_new(c, ob); + metrics_scope_end(c, "compile.asm.mc_new"); + metrics_scope_begin(c, "compile.asm.parse"); + asm_parse(c, lex, mc); + metrics_scope_end(c, "compile.asm.parse"); + metrics_scope_begin(c, "compile.obj_finalize"); + obj_finalize(ob); + metrics_scope_end(c, "compile.obj_finalize"); + metrics_count(c, "compile.obj_sections", obj_section_count(ob)); + metrics_count(c, "compile.obj_relocs", obj_reloc_total(ob)); + metrics_scope_begin(c, "compile.asm.mc_free"); + mc_free(mc); + metrics_scope_end(c, "compile.asm.mc_free"); + return; + } + + compiler_panic(c, no_loc(), "no frontend registered for language: %u", + (u32)input->lang); +} + +/* ============================================================ + * C + * ============================================================ */ + +static CfreeStatus compile_c_into(Compiler* c, const CfreeCCompileOptions* opts, + const CfreeBytes* input, ObjBuilder* ob) { + CfreeFrontendCompileOptions fe; + CfreeSourceInput si; + CfreeCompileFn frontend; + + frontend = c->frontends[CFREE_LANG_C]; + if (!frontend) { + compiler_panic(c, no_loc(), "no C frontend registered"); + } + + fe.code = opts->code; + fe.diagnostics = opts->diagnostics; + fe.language_options = opts; + si.bytes = *input; + si.lang = CFREE_LANG_C; + + metrics_scope_begin(c, "compile.frontend"); + CfreeStatus st = frontend(c, &fe, &si, ob); + metrics_scope_end(c, "compile.frontend"); + if (st != CFREE_OK) { + compiler_panic(c, no_loc(), "C frontend failed for input: %s", input->name); + } + metrics_scope_begin(c, "compile.obj_finalize"); + obj_finalize(ob); + metrics_scope_end(c, "compile.obj_finalize"); + return CFREE_OK; +} + +CfreeStatus cfree_compile_c_obj(CfreeCompiler* c, + const CfreeCCompileOptions* opts, + const CfreeBytes* input, + CfreeObjBuilder** out) { + PanicSave saved; + ObjBuilder* ob; + + if (!out) return CFREE_INVALID; + *out = NULL; + if (!c || !opts || !input) return CFREE_INVALID; + compiler_panic_save(c, &saved); + if (setjmp(c->panic)) { + compiler_run_cleanups(c); + compiler_panic_restore(c, &saved); + return CFREE_ERR; + } + validate_bytes(c, input); + ob = obj_new(c); + metrics_scope_begin(c, "compile.tu"); + metrics_count(c, "compile.input_bytes", (u64)input->len); + compile_c_into(c, opts, input, ob); + metrics_scope_end(c, "compile.tu"); + *out = ob; + compiler_panic_restore(c, &saved); + return CFREE_OK; +} + +CfreeStatus cfree_compile_c_obj_emit(CfreeCompiler* c, + const CfreeCCompileOptions* opts, + const CfreeBytes* input, + CfreeWriter* out) { + PanicSave saved; + ObjBuilder* ob; + + if (!c || !opts || !input || !out) return CFREE_INVALID; + compiler_panic_save(c, &saved); + if (setjmp(c->panic)) { + compiler_run_cleanups(c); + compiler_panic_restore(c, &saved); + return CFREE_ERR; + } + validate_bytes(c, input); + ob = obj_new(c); + metrics_scope_begin(c, "compile.tu"); + metrics_count(c, "compile.input_bytes", (u64)input->len); + compile_c_into(c, opts, input, ob); + emit_object_bytes(c, ob, out); + metrics_scope_end(c, "compile.tu"); + obj_free(ob); + compiler_panic_restore(c, &saved); + return CFREE_OK; +} + +/* ============================================================ + * Asm + * ============================================================ */ + +static void compile_asm_into(Compiler* c, const CfreeAsmCompileOptions* opts, + const CfreeBytes* input, ObjBuilder* ob) { + AsmLexer* lex; + MCEmitter* mc; + (void)opts; + metrics_scope_begin(c, "compile.asm.lex_open"); + lex = asm_lex_open_mem(c, input->name, (const char*)input->data, input->len); + metrics_scope_end(c, "compile.asm.lex_open"); + metrics_scope_begin(c, "compile.asm.mc_new"); + mc = mc_new(c, ob); + metrics_scope_end(c, "compile.asm.mc_new"); + metrics_scope_begin(c, "compile.asm.parse"); + asm_parse(c, lex, mc); + metrics_scope_end(c, "compile.asm.parse"); + metrics_scope_begin(c, "compile.obj_finalize"); + obj_finalize(ob); + metrics_scope_end(c, "compile.obj_finalize"); + metrics_scope_begin(c, "compile.asm.mc_free"); + mc_free(mc); + metrics_scope_end(c, "compile.asm.mc_free"); +} + +CfreeStatus cfree_compile_asm_obj(CfreeCompiler* c, + const CfreeAsmCompileOptions* opts, + const CfreeBytes* input, + CfreeObjBuilder** out) { + PanicSave saved; + ObjBuilder* ob; + + if (!out) return CFREE_INVALID; + *out = NULL; + if (!c || !opts || !input) return CFREE_INVALID; + compiler_panic_save(c, &saved); + if (setjmp(c->panic)) { + compiler_run_cleanups(c); + compiler_panic_restore(c, &saved); + return CFREE_ERR; + } + validate_bytes(c, input); + ob = obj_new(c); + metrics_scope_begin(c, "compile.tu"); + metrics_count(c, "compile.input_bytes", (u64)input->len); + compile_asm_into(c, opts, input, ob); + metrics_scope_end(c, "compile.tu"); + *out = ob; + compiler_panic_restore(c, &saved); + return CFREE_OK; +} + +CfreeStatus cfree_compile_asm_obj_emit(CfreeCompiler* c, + const CfreeAsmCompileOptions* opts, + const CfreeBytes* input, + CfreeWriter* out) { + PanicSave saved; + ObjBuilder* ob; + if (!c || !opts || !input || !out) return CFREE_INVALID; + compiler_panic_save(c, &saved); + if (setjmp(c->panic)) { + compiler_run_cleanups(c); + compiler_panic_restore(c, &saved); + return CFREE_ERR; + } + validate_bytes(c, input); + ob = obj_new(c); + metrics_scope_begin(c, "compile.tu"); + metrics_count(c, "compile.input_bytes", (u64)input->len); + compile_asm_into(c, opts, input, ob); + emit_object_bytes(c, ob, out); + metrics_scope_end(c, "compile.tu"); + obj_free(ob); + compiler_panic_restore(c, &saved); + return CFREE_OK; +} + +/* ============================================================ + * Source (registered frontend) + * ============================================================ */ + +CfreeStatus cfree_compile_source_obj(CfreeCompiler* c, + const CfreeFrontendCompileOptions* opts, + const CfreeSourceInput* input, + CfreeObjBuilder** out) { + PanicSave saved; + ObjBuilder* ob; + + if (!out) return CFREE_INVALID; + *out = NULL; + if (!c || !opts || !input) return CFREE_INVALID; + compiler_panic_save(c, &saved); + if (setjmp(c->panic)) { + compiler_run_cleanups(c); + compiler_panic_restore(c, &saved); + return CFREE_ERR; + } + validate_bytes(c, &input->bytes); + ob = obj_new(c); + metrics_scope_begin(c, "compile.tu"); + metrics_count(c, "compile.input_bytes", (u64)input->bytes.len); + compile_source_into(c, opts, input, ob); + metrics_scope_end(c, "compile.tu"); + *out = ob; + compiler_panic_restore(c, &saved); + return CFREE_OK; +} + +CfreeStatus cfree_compile_source_obj_emit( + CfreeCompiler* c, const CfreeFrontendCompileOptions* opts, + const CfreeSourceInput* input, CfreeWriter* out) { + PanicSave saved; + ObjBuilder* ob; + if (!c || !opts || !input || !out) return CFREE_INVALID; + compiler_panic_save(c, &saved); + if (setjmp(c->panic)) { + compiler_run_cleanups(c); + compiler_panic_restore(c, &saved); + return CFREE_ERR; + } + validate_bytes(c, &input->bytes); + ob = obj_new(c); + metrics_scope_begin(c, "compile.tu"); + metrics_count(c, "compile.input_bytes", (u64)input->bytes.len); + compile_source_into(c, opts, input, ob); + emit_object_bytes(c, ob, out); + metrics_scope_end(c, "compile.tu"); + obj_free(ob); + compiler_panic_restore(c, &saved); + return CFREE_OK; +} + +struct CfreeDepIter { + Compiler* c; + SourceDepIter* inner; +}; + +CfreeStatus cfree_dep_iter_new(CfreeCompiler* c, CfreeDepIter** out) { + Heap* h; + CfreeDepIter* it; + if (!out) return CFREE_INVALID; + if (!c || !c->sources) return CFREE_INVALID; + h = c->ctx->heap; + it = (CfreeDepIter*)h->alloc(h, sizeof(*it), _Alignof(CfreeDepIter)); + if (!it) return CFREE_NOMEM; + it->c = c; + it->inner = source_depiter_new(c->sources); + if (!it->inner) { + h->free(h, it, sizeof(*it)); + return CFREE_NOMEM; + } + *out = it; + return CFREE_OK; +} + +CfreeIterResult cfree_dep_iter_next(CfreeDepIter* it, CfreeDepEdge* out) { + const SourceInclude* edge; + const SourceFile* includer; + const SourceFile* included; + if (!it || !out) return CFREE_ITER_ERROR; + edge = source_depiter_next(it->inner); + if (!edge) return CFREE_ITER_END; + 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; + out->included_name = + included ? pool_str(it->c->global, included->name, NULL) : 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); + out->pad[0] = 0; + out->pad[1] = 0; + return CFREE_ITER_ITEM; +} + +void cfree_dep_iter_free(CfreeDepIter* it) { + Heap* h; + if (!it) return; + h = it->c->ctx->heap; + if (it->inner) source_depiter_free(it->inner); + h->free(h, it, sizeof(*it)); +} diff --git a/src/api/core.c b/src/api/core.c @@ -0,0 +1,193 @@ +/* Public core API bridge. */ + +#include "core/core.h" + +#include <cfree/core.h> +#include <string.h> + +#include "core/heap.h" +#include "core/pool.h" + +CfreeStatus cfree_compiler_new(CfreeTarget target, const CfreeContext* ctx, + CfreeCompiler** out) { + Heap* h; + Compiler* c; + + if (!out) return CFREE_INVALID; + if (!ctx || !ctx->heap) return CFREE_INVALID; + h = ctx->heap; + c = h->alloc(h, sizeof(*c), _Alignof(Compiler)); + if (!c) return CFREE_NOMEM; + compiler_init(c, target, ctx); + *out = c; + return CFREE_OK; +} + +void cfree_compiler_free(CfreeCompiler* c) { + Heap* h; + if (!c) return; + h = c->ctx->heap; + compiler_fini(c); + h->free(h, c, sizeof(*c)); +} + +CfreeTarget cfree_compiler_target(CfreeCompiler* c) { + CfreeTarget t; + memset(&t, 0, sizeof t); + if (!c) return t; + return c->target; +} + +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) { + const SourceFile* f; + if (!c) return NULL; + f = source_file(c->sources, file_id); + if (!f) return NULL; + return pool_str(c->global, f->name, NULL); +} + +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_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); +} + +CfreeSym cfree_cg_c_linkage_name(CfreeCompiler* c, CfreeSym source_name) { + const char* name; + size_t len; + char* buf; + CfreeSym out; + Heap* h; + + if (!c || !source_name) return 0; + name = pool_str(c->global, (Sym)source_name, &len); + if (!name) return 0; + if (c->target.obj != CFREE_OBJ_MACHO) return source_name; + + h = c->ctx->heap; + buf = (char*)h->alloc(h, len + 2u, 1); + if (!buf) return 0; + buf[0] = '_'; + if (len) memcpy(buf + 1, name, len); + buf[len + 1u] = '\0'; + out = pool_intern(c->global, buf, (u32)(len + 1u)); + h->free(h, buf, len + 2u); + return out; +} + +typedef struct MemWriter { + CfreeWriter base; + Heap* heap; + u8* data; + size_t cap; + size_t len; + size_t pos; + CfreeStatus status; +} MemWriter; + +static CfreeStatus mw_grow(MemWriter* mw, size_t needed) { + size_t new_cap; + u8* p; + + if (needed <= mw->cap) return CFREE_OK; + new_cap = mw->cap ? mw->cap : 64; + while (new_cap < needed) { + size_t doubled = new_cap * 2; + if (doubled <= new_cap) { + mw->status = CFREE_NOMEM; + return CFREE_NOMEM; + } + new_cap = doubled; + } + + p = (u8*)mw->heap->realloc(mw->heap, mw->data, mw->cap, new_cap, 1); + if (!p) { + mw->status = CFREE_NOMEM; + return CFREE_NOMEM; + } + if (new_cap > mw->cap) memset(p + mw->cap, 0, new_cap - mw->cap); + mw->data = p; + mw->cap = new_cap; + return CFREE_OK; +} + +static CfreeStatus mw_write(CfreeWriter* w, const void* data, size_t n) { + MemWriter* mw = (MemWriter*)w; + size_t end; + CfreeStatus st; + + if (mw->status != CFREE_OK) return mw->status; + if (n == 0) return CFREE_OK; + end = mw->pos + n; + if (end < mw->pos) { + mw->status = CFREE_NOMEM; + return CFREE_NOMEM; + } + st = mw_grow(mw, end); + if (st != CFREE_OK) return st; + memcpy(mw->data + mw->pos, data, n); + mw->pos = end; + if (mw->pos > mw->len) mw->len = mw->pos; + return CFREE_OK; +} + +static CfreeStatus mw_seek(CfreeWriter* w, uint64_t off) { + MemWriter* mw = (MemWriter*)w; + if (mw->status != CFREE_OK) return mw->status; + mw->pos = (size_t)off; + return CFREE_OK; +} + +static uint64_t mw_tell(CfreeWriter* w) { return ((MemWriter*)w)->pos; } + +static CfreeStatus mw_status(CfreeWriter* w) { return ((MemWriter*)w)->status; } + +static void mw_close(CfreeWriter* w) { + MemWriter* mw = (MemWriter*)w; + Heap* h = mw->heap; + if (mw->data) h->free(h, mw->data, mw->cap); + h->free(h, mw, sizeof(*mw)); +} + +CfreeStatus cfree_writer_mem(CfreeHeap* heap, CfreeWriter** out) { + MemWriter* mw; + if (!out) return CFREE_INVALID; + if (!heap) return CFREE_INVALID; + mw = (MemWriter*)heap->alloc(heap, sizeof(*mw), _Alignof(MemWriter)); + if (!mw) return CFREE_NOMEM; + mw->base.write = mw_write; + mw->base.seek = mw_seek; + mw->base.tell = mw_tell; + mw->base.status = mw_status; + mw->base.close = mw_close; + mw->heap = heap; + mw->data = NULL; + mw->cap = 0; + mw->len = 0; + mw->pos = 0; + mw->status = CFREE_OK; + *out = &mw->base; + return CFREE_OK; +} + +const uint8_t* cfree_writer_mem_bytes(CfreeWriter* w, size_t* len_out) { + MemWriter* mw = (MemWriter*)w; + if (len_out) *len_out = mw ? mw->len : 0; + return mw ? mw->data : NULL; +} diff --git a/src/api/dep.c b/src/api/dep.c @@ -1,59 +0,0 @@ -/* Header-dependency iteration. */ - -#include <cfree/compile.h> - -#include "core/core.h" -#include "core/heap.h" -#include "core/pool.h" - -struct CfreeDepIter { - Compiler* c; - SourceDepIter* inner; -}; - -CfreeStatus cfree_dep_iter_new(CfreeCompiler* c, CfreeDepIter** out) { - Heap* h; - CfreeDepIter* it; - if (!out) return CFREE_INVALID; - if (!c || !c->sources) return CFREE_INVALID; - h = c->ctx->heap; - it = (CfreeDepIter*)h->alloc(h, sizeof(*it), _Alignof(CfreeDepIter)); - if (!it) return CFREE_NOMEM; - it->c = c; - it->inner = source_depiter_new(c->sources); - if (!it->inner) { - h->free(h, it, sizeof(*it)); - return CFREE_NOMEM; - } - *out = it; - return CFREE_OK; -} - -CfreeIterResult cfree_dep_iter_next(CfreeDepIter* it, CfreeDepEdge* out) { - const SourceInclude* edge; - const SourceFile* includer; - const SourceFile* included; - if (!it || !out) return CFREE_ITER_ERROR; - edge = source_depiter_next(it->inner); - if (!edge) return CFREE_ITER_END; - 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; - out->included_name = - included ? pool_str(it->c->global, included->name, NULL) : 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); - out->pad[0] = 0; - out->pad[1] = 0; - return CFREE_ITER_ITEM; -} - -void cfree_dep_iter_free(CfreeDepIter* it) { - Heap* h; - if (!it) return; - h = it->c->ctx->heap; - if (it->inner) source_depiter_free(it->inner); - h->free(h, it, sizeof(*it)); -} diff --git a/src/api/frontend.c b/src/api/frontend.c @@ -1,52 +1,9 @@ #include <cfree/frontend.h> -#include <cfree/support/arena.h> #include <setjmp.h> #include <stdarg.h> -#include <string.h> -#include "core/arena.h" #include "core/core.h" #include "core/metrics.h" -#include "core/pool.h" - -struct CfreeArena { - Arena inner; -}; - -CfreeStatus cfree_arena_new(CfreeHeap* h, size_t block_size, CfreeArena** out) { - CfreeArena* a; - if (!out) return CFREE_INVALID; - if (!h) return CFREE_INVALID; - a = (CfreeArena*)h->alloc(h, sizeof(*a), _Alignof(CfreeArena)); - if (!a) return CFREE_NOMEM; - arena_init(&a->inner, (Heap*)h, block_size); - *out = a; - return CFREE_OK; -} - -void cfree_arena_free(CfreeArena* a) { - CfreeHeap* h; - if (!a) return; - h = a->inner.heap; - arena_fini(&a->inner); - h->free(h, a, sizeof(*a)); -} - -void cfree_arena_reset(CfreeArena* a) { - if (a) arena_reset(&a->inner); -} - -void* cfree_arena_alloc(CfreeArena* a, size_t size, size_t align) { - return a ? arena_alloc(&a->inner, size, align) : NULL; -} - -void* cfree_arena_zalloc(CfreeArena* a, size_t size, size_t align) { - return a ? arena_zalloc(&a->inner, size, align) : NULL; -} - -char* cfree_arena_strdup(CfreeArena* a, const char* s, size_t len) { - return a ? arena_strdup(&a->inner, s, len) : NULL; -} CfreeStatus cfree_frontend_run(CfreeCompiler* c, CfreeFrontendRunFn fn, void* user) { diff --git a/src/api/lifecycle.c b/src/api/lifecycle.c @@ -1,158 +0,0 @@ -/* CfreeCompiler lifecycle. */ - -#include <cfree/core.h> -#include <cfree/source.h> -#include <string.h> - -#include "core/core.h" -#include "core/heap.h" -#include "core/pool.h" - -CfreeStatus cfree_compiler_new(CfreeTarget target, const CfreeContext* ctx, - CfreeCompiler** out) { - Heap* h; - Compiler* c; - - if (!out) return CFREE_INVALID; - if (!ctx || !ctx->heap) return CFREE_INVALID; - h = ctx->heap; - c = h->alloc(h, sizeof(*c), _Alignof(Compiler)); - if (!c) return CFREE_NOMEM; - compiler_init(c, target, ctx); - *out = c; - return CFREE_OK; -} - -void cfree_compiler_free(CfreeCompiler* c) { - Heap* h; - if (!c) return; - h = c->ctx->heap; - compiler_fini(c); - h->free(h, c, sizeof(*c)); -} - -CfreeTarget cfree_compiler_target(CfreeCompiler* c) { - CfreeTarget t; - memset(&t, 0, sizeof t); - if (!c) return t; - return c->target; -} - -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) { - const SourceFile* f; - if (!c) return NULL; - f = source_file(c->sources, file_id); - if (!f) return NULL; - return pool_str(c->global, f->name, NULL); -} - -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_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); -} - -CfreeSym cfree_cg_c_linkage_name(CfreeCompiler* c, CfreeSym source_name) { - const char* name; - size_t len; - char* buf; - CfreeSym out; - Heap* h; - - if (!c || !source_name) return 0; - name = pool_str(c->global, (Sym)source_name, &len); - if (!name) return 0; - if (c->target.obj != CFREE_OBJ_MACHO) return source_name; - - h = c->ctx->heap; - buf = (char*)h->alloc(h, len + 2u, 1); - if (!buf) return 0; - buf[0] = '_'; - if (len) memcpy(buf + 1, name, len); - buf[len + 1u] = '\0'; - out = pool_intern(c->global, buf, (u32)(len + 1u)); - h->free(h, buf, len + 2u); - return out; -} - -CfreeStatus cfree_register_frontend(CfreeCompiler* c, CfreeLanguage lang, - CfreeCompileFn fn) { - if (!c) return CFREE_INVALID; - if ((unsigned)lang >= CFREE_LANG_COUNT) return CFREE_INVALID; - c->frontends[lang] = fn; - return CFREE_OK; -} - -/* Source registry public wrappers. */ - -CfreeStatus cfree_source_add_file(CfreeCompiler* c, const char* path, - int system_header, uint32_t* file_id_out) { - uint32_t tmp; - CfreeStatus st; - if (!c || !file_id_out) return CFREE_INVALID; - st = source_add_file(c->sources, path, system_header, &tmp); - if (st != CFREE_OK) return st; - *file_id_out = tmp; - return CFREE_OK; -} - -CfreeStatus cfree_source_add_memory(CfreeCompiler* c, const char* name, - uint32_t* file_id_out) { - uint32_t tmp; - CfreeStatus st; - if (!c || !file_id_out) return CFREE_INVALID; - st = source_add_memory(c->sources, name, &tmp); - if (st != CFREE_OK) return st; - *file_id_out = tmp; - return CFREE_OK; -} - -CfreeStatus cfree_source_add_builtin(CfreeCompiler* c, const char* name, - uint32_t* file_id_out) { - uint32_t tmp; - CfreeStatus st; - if (!c || !file_id_out) return CFREE_INVALID; - st = source_add_builtin(c->sources, name, &tmp); - if (st != CFREE_OK) return st; - *file_id_out = tmp; - return CFREE_OK; -} - -CfreeStatus cfree_source_add_include(CfreeCompiler* c, uint32_t includer_file_id, - uint32_t included_file_id, - CfreeSrcLoc loc, int system) { - if (!c) return CFREE_INVALID; - return source_add_include(c->sources, includer_file_id, included_file_id, - loc, system); -} - -CfreeStatus cfree_source_file(CfreeCompiler* c, uint32_t file_id, - CfreeSourceFile* out) { - const SourceFile* f; - if (!c || !out) return CFREE_INVALID; - f = source_file(c->sources, file_id); - if (!f) return CFREE_NOT_FOUND; - memset(out, 0, sizeof *out); - out->id = f->id; - out->name = f->name; - out->path = f->path; - out->kind = f->kind; - out->system_header = f->system_header; - return CFREE_OK; -} diff --git a/src/api/link.c b/src/api/link.c @@ -0,0 +1,168 @@ +/* Public link API entries. + * + * Thin orchestrators over the Linker primitives in link.c / link_resolve.c / + * link_layout.c / link_jit.c. Each entry: + * - allocates a Linker against the caller's Compiler, + * - feeds in the CfreeLinkInputs, + * - configures lane-specific flags (pie, shared, jit), + * - calls link_resolve, + * - dispatches to the emit (writer) or JIT-map (cfree_jit_from_image) tail. + * + * The driver's job ends at populating CfreeLinkInputs; everything below this + * line is libcfree-internal. */ + +#include "link/link.h" + +#include <cfree/core.h> +#include <cfree/jit.h> +#include <cfree/link.h> +#include <setjmp.h> + +#include "core/core.h" +#include "link/link_internal.h" + +CfreeJit* cfree_jit_from_image(LinkImage*); + +static void load_inputs(Linker* l, const CfreeLinkInputs* in) { + uint32_t i; + for (i = 0; i < in->nobjs; ++i) { + if (in->objs[i]) link_add_obj(l, in->objs[i]); + } + for (i = 0; i < in->nobj_bytes; ++i) { + const CfreeBytes* b = &in->obj_bytes[i]; + link_add_obj_bytes(l, b->name, b->data, b->len); + } + for (i = 0; i < in->narchives; ++i) { + const CfreeLinkArchiveInput* a = &in->archives[i]; + link_add_archive_bytes(l, a->bytes.name, a->bytes.data, a->bytes.len, + a->whole_archive, a->link_mode, a->group_id); + } + for (i = 0; i < in->ndso_bytes; ++i) { + const CfreeBytes* b = &in->dso_bytes[i]; + link_add_dso_bytes(l, b->name, b->data, b->len); + } + if (in->linker_script) link_set_script(l, in->linker_script); + if (in->entry) link_set_entry(l, in->entry); + /* build_id_* fields are accepted but not yet plumbed through the + * Linker — the elf emit currently derives the build-id from the + * image bytes unconditionally. Left as a TODO when the linker + * grows a configurable build-id mode. */ + (void)in->build_id_mode; + (void)in->build_id_bytes; + (void)in->build_id_len; +} + +CfreeStatus cfree_link_exe(CfreeCompiler* c, const CfreeExeLinkOptions* opts, + CfreeWriter* out) { + PanicSave saved; + Linker* l; + LinkImage* img; + if (!c || !opts || !out) return CFREE_INVALID; + compiler_panic_save(c, &saved); + if (setjmp(c->panic)) { + compiler_run_cleanups(c); + compiler_panic_restore(c, &saved); + return CFREE_ERR; + } + l = link_new(c); + if (!l) { + compiler_panic_restore(c, &saved); + return CFREE_NOMEM; + } + load_inputs(l, &opts->inputs); + link_set_emit_static_exe(l, 1); + link_set_gc_sections(l, opts->gc_sections); + link_set_pie(l, opts->pie); + link_set_interp_path(l, opts->interp_path); + img = link_resolve(l); + link_emit_image_writer(img, out); + link_image_free(img); + link_free(l); + compiler_panic_restore(c, &saved); + return CFREE_OK; +} + +CfreeStatus cfree_link_shared(CfreeCompiler* c, + const CfreeSharedLinkOptions* opts, + CfreeWriter* out) { + PanicSave saved; + Linker* l; + LinkImage* img; + if (!c || !opts || !out) return CFREE_INVALID; + compiler_panic_save(c, &saved); + if (setjmp(c->panic)) { + compiler_run_cleanups(c); + compiler_panic_restore(c, &saved); + return CFREE_ERR; + } + l = link_new(c); + if (!l) { + compiler_panic_restore(c, &saved); + return CFREE_NOMEM; + } + load_inputs(l, &opts->inputs); + link_set_gc_sections(l, opts->gc_sections); + /* Shared output is intrinsically PIC and uses the dynamic emit path. */ + link_set_pie(l, 1); + /* soname / rpaths / runpaths / exports / allow_undefined: forwarded + * fields not yet wired into the Linker. Recorded here so the surface + * matches the public API; the linker emits a static shared-friendly + * image regardless for the time being. */ + (void)opts->soname; + (void)opts->rpaths; + (void)opts->nrpaths; + (void)opts->runpaths; + (void)opts->nrunpaths; + (void)opts->exports; + (void)opts->nexports; + (void)opts->allow_undefined; + img = link_resolve(l); + link_emit_image_writer(img, out); + link_image_free(img); + link_free(l); + compiler_panic_restore(c, &saved); + return CFREE_OK; +} + +CfreeStatus cfree_link_jit(CfreeCompiler* c, const CfreeJitLinkOptions* opts, + const CfreeJitHost* host, CfreeJit** out_jit) { + PanicSave saved; + Linker* l; + LinkImage* img; + CfreeJit* jit; + if (!out_jit) return CFREE_INVALID; + *out_jit = NULL; + if (!c || !opts || !host) return CFREE_INVALID; + compiler_panic_save(c, &saved); + if (setjmp(c->panic)) { + compiler_run_cleanups(c); + compiler_panic_restore(c, &saved); + return CFREE_ERR; + } + l = link_new(c); + if (!l) { + compiler_panic_restore(c, &saved); + return CFREE_NOMEM; + } + link_set_jit_host(l, host); + link_set_jit_mode(l, 1); + link_set_gc_sections(l, opts->gc_sections); + if (opts->extern_resolver) { + link_set_extern_resolver(l, opts->extern_resolver, + opts->extern_resolver_user); + } + load_inputs(l, &opts->inputs); + img = link_resolve(l); + /* cfree_jit_from_image undefers the Linker / image and binds the JIT + * to them — do not link_free(l) on success. */ + jit = cfree_jit_from_image(img); + if (!jit) { + link_image_free(img); + link_free(l); + compiler_panic_restore(c, &saved); + return CFREE_ERR; + } + *out_jit = jit; + compiler_panic_restore(c, &saved); + return CFREE_OK; +} diff --git a/src/api/objbuilder.c b/src/api/objbuilder.c @@ -1,214 +0,0 @@ -/* Public CfreeObjBuilder API: thin adapter over the internal obj_* surface. */ - -#include <cfree/object.h> -#include <string.h> - -#include "core/core.h" -#include "obj/obj.h" - -static ObjSecId pub_to_intern_sec(CfreeObjSection s) { - if (s == CFREE_SECTION_NONE) return OBJ_SEC_NONE; - return (ObjSecId)(s + 1); -} - -static CfreeObjSection intern_to_pub_sec(ObjSecId id) { - if (id == OBJ_SEC_NONE) return CFREE_SECTION_NONE; - return (CfreeObjSection)(id - 1); -} - -static ObjSymId pub_to_intern_sym(CfreeObjSymbol s) { - if (s == CFREE_OBJ_SYMBOL_NONE) return OBJ_SYM_NONE; - return (ObjSymId)s; -} - -static CfreeObjSymbol intern_to_pub_sym(ObjSymId id) { - if (id == OBJ_SYM_NONE) return CFREE_OBJ_SYMBOL_NONE; - return (CfreeObjSymbol)id; -} - -static ObjGroupId pub_to_intern_group(CfreeObjGroup g) { - if (g == CFREE_OBJ_GROUP_NONE) return OBJ_GROUP_NONE; - return (ObjGroupId)g; -} - -static CfreeObjGroup intern_to_pub_group(ObjGroupId id) { - if (id == OBJ_GROUP_NONE) return CFREE_OBJ_GROUP_NONE; - return (CfreeObjGroup)id; -} - -CfreeStatus cfree_obj_builder_new(CfreeCompiler* c, CfreeObjBuilder** out) { - ObjBuilder* ob; - if (!out) return CFREE_INVALID; - if (!c) return CFREE_INVALID; - ob = obj_new(c); - if (!ob) return CFREE_NOMEM; - *out = ob; - return CFREE_OK; -} - -void cfree_obj_builder_free(CfreeObjBuilder* b) { - if (b) obj_free(b); -} - -CfreeStatus cfree_obj_builder_section(CfreeObjBuilder* b, - const CfreeObjSectionDesc* desc, - CfreeObjSection* out) { - ObjSecId id; - if (!b || !desc || !out) return CFREE_INVALID; - id = obj_section(b, (Sym)desc->name, (SecKind)desc->kind, - (u16)desc->flags, desc->align ? desc->align : 1u); - if (id == OBJ_SEC_NONE) return CFREE_ERR; - if (desc->entsize) { - /* Carry entsize through obj_section_ex if needed; obj_section path - * uses default 0. Use obj_section_ex when caller specifies entsize. */ - const Section* sec = obj_section_get(b, id); - (void)sec; - /* Re-create via the _ex path to set entsize. */ - /* obj_section dedupes by name+kind+flags+align; calling _ex with the - * same fields plus the entsize updates that section. */ - id = obj_section_ex(b, (Sym)desc->name, (SecKind)desc->kind, - SSEM_PROGBITS, (u16)desc->flags, - desc->align ? desc->align : 1u, desc->entsize, 0, 0); - } - *out = intern_to_pub_sec(id); - return CFREE_OK; -} - -CfreeStatus cfree_obj_builder_section_group(CfreeObjBuilder* b, - CfreeObjSection sec, - CfreeObjGroup grp) { - if (!b) return CFREE_INVALID; - obj_section_set_group(b, pub_to_intern_sec(sec), pub_to_intern_group(grp)); - return CFREE_OK; -} - -CfreeStatus cfree_obj_builder_pos(CfreeObjBuilder* b, CfreeObjSection sec, - uint64_t* out) { - if (!b || !out) return CFREE_INVALID; - *out = obj_pos(b, pub_to_intern_sec(sec)); - return CFREE_OK; -} - -CfreeStatus cfree_obj_builder_align(CfreeObjBuilder* b, CfreeObjSection sec, - uint32_t align, uint64_t* new_pos_out) { - u32 pos; - if (!b) return CFREE_INVALID; - pos = obj_align_to(b, pub_to_intern_sec(sec), align ? align : 1u); - if (new_pos_out) *new_pos_out = pos; - return CFREE_OK; -} - -CfreeStatus cfree_obj_builder_write(CfreeObjBuilder* b, CfreeObjSection sec, - const void* data, size_t n) { - if (!b) return CFREE_INVALID; - obj_write(b, pub_to_intern_sec(sec), data, n); - return CFREE_OK; -} - -CfreeStatus cfree_obj_builder_reserve(CfreeObjBuilder* b, CfreeObjSection sec, - size_t n, void** out) { - u8* p; - if (!b || !out) return CFREE_INVALID; - p = obj_reserve(b, pub_to_intern_sec(sec), n); - if (!p) return CFREE_NOMEM; - *out = p; - return CFREE_OK; -} - -CfreeStatus cfree_obj_builder_reserve_bss(CfreeObjBuilder* b, - CfreeObjSection sec, uint64_t size, - uint32_t align) { - if (!b) return CFREE_INVALID; - obj_reserve_bss(b, pub_to_intern_sec(sec), (u32)size, align ? align : 1u); - return CFREE_OK; -} - -CfreeStatus cfree_obj_builder_patch(CfreeObjBuilder* b, CfreeObjSection sec, - uint64_t offset, const void* data, - size_t n) { - if (!b) return CFREE_INVALID; - obj_patch(b, pub_to_intern_sec(sec), (u32)offset, data, n); - return CFREE_OK; -} - -CfreeStatus cfree_obj_builder_symbol(CfreeObjBuilder* b, - const CfreeObjSymbolDesc* desc, - CfreeObjSymbol* out) { - ObjSymId id; - if (!b || !desc || !out) return CFREE_INVALID; - id = obj_symbol(b, (Sym)desc->name, (SymBind)desc->bind, (SymKind)desc->kind, - pub_to_intern_sec(desc->section), desc->value, desc->size); - if (id == OBJ_SYM_NONE) return CFREE_ERR; - *out = intern_to_pub_sym(id); - return CFREE_OK; -} - -CfreeStatus cfree_obj_builder_symbol_define(CfreeObjBuilder* b, - CfreeObjSymbol sym, - CfreeObjSection section, - uint64_t value, uint64_t size) { - if (!b) return CFREE_INVALID; - obj_symbol_define(b, pub_to_intern_sym(sym), pub_to_intern_sec(section), - value, size); - return CFREE_OK; -} - -CfreeStatus cfree_obj_builder_reloc(CfreeObjBuilder* b, - const CfreeObjRelocDesc* desc) { - if (!b || !desc) return CFREE_INVALID; - /* Public CfreeRelocKind.code is the raw internal RelocKind value - * (single shared numeric space). */ - obj_reloc(b, pub_to_intern_sec(desc->section), (u32)desc->offset, - (RelocKind)desc->kind.code, pub_to_intern_sym(desc->symbol), - desc->addend); - return CFREE_OK; -} - -CfreeStatus cfree_obj_builder_group(CfreeObjBuilder* b, CfreeSym name, - CfreeObjSymbol signature, uint32_t flags, - CfreeObjGroup* out) { - ObjGroupId id; - if (!b || !out) return CFREE_INVALID; - id = obj_group(b, (Sym)name, pub_to_intern_sym(signature), flags); - if (id == OBJ_GROUP_NONE) return CFREE_ERR; - *out = intern_to_pub_group(id); - return CFREE_OK; -} - -CfreeStatus cfree_obj_builder_group_add_section(CfreeObjBuilder* b, - CfreeObjGroup grp, - CfreeObjSection sec) { - if (!b) return CFREE_INVALID; - obj_group_add_section(b, pub_to_intern_group(grp), pub_to_intern_sec(sec)); - return CFREE_OK; -} - -CfreeStatus cfree_obj_builder_finalize(CfreeObjBuilder* b) { - if (!b) return CFREE_INVALID; - obj_finalize(b); - return CFREE_OK; -} - -CfreeStatus cfree_obj_builder_emit(CfreeObjBuilder* b, CfreeWriter* w) { - Compiler* c; - if (!b || !w) return CFREE_INVALID; - c = obj_compiler(b); - if (!c) return CFREE_INVALID; - switch (c->target.obj) { - case CFREE_OBJ_ELF: - emit_elf(c, b, w); - break; - case CFREE_OBJ_COFF: - emit_coff(c, b, w); - break; - case CFREE_OBJ_MACHO: - emit_macho(c, b, w); - break; - case CFREE_OBJ_WASM: - emit_wasm(c, b, w); - break; - default: - return CFREE_UNSUPPORTED; - } - return cfree_writer_status(w); -} diff --git a/src/api/object_builder.c b/src/api/object_builder.c @@ -0,0 +1,214 @@ +/* Public CfreeObjBuilder API: thin adapter over the internal obj_* surface. */ + +#include <cfree/object.h> +#include <string.h> + +#include "core/core.h" +#include "obj/obj.h" + +static ObjSecId pub_to_intern_sec(CfreeObjSection s) { + if (s == CFREE_SECTION_NONE) return OBJ_SEC_NONE; + return (ObjSecId)(s + 1); +} + +static CfreeObjSection intern_to_pub_sec(ObjSecId id) { + if (id == OBJ_SEC_NONE) return CFREE_SECTION_NONE; + return (CfreeObjSection)(id - 1); +} + +static ObjSymId pub_to_intern_sym(CfreeObjSymbol s) { + if (s == CFREE_OBJ_SYMBOL_NONE) return OBJ_SYM_NONE; + return (ObjSymId)s; +} + +static CfreeObjSymbol intern_to_pub_sym(ObjSymId id) { + if (id == OBJ_SYM_NONE) return CFREE_OBJ_SYMBOL_NONE; + return (CfreeObjSymbol)id; +} + +static ObjGroupId pub_to_intern_group(CfreeObjGroup g) { + if (g == CFREE_OBJ_GROUP_NONE) return OBJ_GROUP_NONE; + return (ObjGroupId)g; +} + +static CfreeObjGroup intern_to_pub_group(ObjGroupId id) { + if (id == OBJ_GROUP_NONE) return CFREE_OBJ_GROUP_NONE; + return (CfreeObjGroup)id; +} + +CfreeStatus cfree_obj_builder_new(CfreeCompiler* c, CfreeObjBuilder** out) { + ObjBuilder* ob; + if (!out) return CFREE_INVALID; + if (!c) return CFREE_INVALID; + ob = obj_new(c); + if (!ob) return CFREE_NOMEM; + *out = ob; + return CFREE_OK; +} + +void cfree_obj_builder_free(CfreeObjBuilder* b) { + if (b) obj_free(b); +} + +CfreeStatus cfree_obj_builder_section(CfreeObjBuilder* b, + const CfreeObjSectionDesc* desc, + CfreeObjSection* out) { + ObjSecId id; + if (!b || !desc || !out) return CFREE_INVALID; + id = obj_section(b, (Sym)desc->name, (SecKind)desc->kind, (u16)desc->flags, + desc->align ? desc->align : 1u); + if (id == OBJ_SEC_NONE) return CFREE_ERR; + if (desc->entsize) { + /* Carry entsize through obj_section_ex if needed; obj_section path + * uses default 0. Use obj_section_ex when caller specifies entsize. */ + const Section* sec = obj_section_get(b, id); + (void)sec; + /* Re-create via the _ex path to set entsize. */ + /* obj_section dedupes by name+kind+flags+align; calling _ex with the + * same fields plus the entsize updates that section. */ + id = obj_section_ex(b, (Sym)desc->name, (SecKind)desc->kind, SSEM_PROGBITS, + (u16)desc->flags, desc->align ? desc->align : 1u, + desc->entsize, 0, 0); + } + *out = intern_to_pub_sec(id); + return CFREE_OK; +} + +CfreeStatus cfree_obj_builder_section_group(CfreeObjBuilder* b, + CfreeObjSection sec, + CfreeObjGroup grp) { + if (!b) return CFREE_INVALID; + obj_section_set_group(b, pub_to_intern_sec(sec), pub_to_intern_group(grp)); + return CFREE_OK; +} + +CfreeStatus cfree_obj_builder_pos(CfreeObjBuilder* b, CfreeObjSection sec, + uint64_t* out) { + if (!b || !out) return CFREE_INVALID; + *out = obj_pos(b, pub_to_intern_sec(sec)); + return CFREE_OK; +} + +CfreeStatus cfree_obj_builder_align(CfreeObjBuilder* b, CfreeObjSection sec, + uint32_t align, uint64_t* new_pos_out) { + u32 pos; + if (!b) return CFREE_INVALID; + pos = obj_align_to(b, pub_to_intern_sec(sec), align ? align : 1u); + if (new_pos_out) *new_pos_out = pos; + return CFREE_OK; +} + +CfreeStatus cfree_obj_builder_write(CfreeObjBuilder* b, CfreeObjSection sec, + const void* data, size_t n) { + if (!b) return CFREE_INVALID; + obj_write(b, pub_to_intern_sec(sec), data, n); + return CFREE_OK; +} + +CfreeStatus cfree_obj_builder_reserve(CfreeObjBuilder* b, CfreeObjSection sec, + size_t n, void** out) { + u8* p; + if (!b || !out) return CFREE_INVALID; + p = obj_reserve(b, pub_to_intern_sec(sec), n); + if (!p) return CFREE_NOMEM; + *out = p; + return CFREE_OK; +} + +CfreeStatus cfree_obj_builder_reserve_bss(CfreeObjBuilder* b, + CfreeObjSection sec, uint64_t size, + uint32_t align) { + if (!b) return CFREE_INVALID; + obj_reserve_bss(b, pub_to_intern_sec(sec), (u32)size, align ? align : 1u); + return CFREE_OK; +} + +CfreeStatus cfree_obj_builder_patch(CfreeObjBuilder* b, CfreeObjSection sec, + uint64_t offset, const void* data, + size_t n) { + if (!b) return CFREE_INVALID; + obj_patch(b, pub_to_intern_sec(sec), (u32)offset, data, n); + return CFREE_OK; +} + +CfreeStatus cfree_obj_builder_symbol(CfreeObjBuilder* b, + const CfreeObjSymbolDesc* desc, + CfreeObjSymbol* out) { + ObjSymId id; + if (!b || !desc || !out) return CFREE_INVALID; + id = obj_symbol(b, (Sym)desc->name, (SymBind)desc->bind, (SymKind)desc->kind, + pub_to_intern_sec(desc->section), desc->value, desc->size); + if (id == OBJ_SYM_NONE) return CFREE_ERR; + *out = intern_to_pub_sym(id); + return CFREE_OK; +} + +CfreeStatus cfree_obj_builder_symbol_define(CfreeObjBuilder* b, + CfreeObjSymbol sym, + CfreeObjSection section, + uint64_t value, uint64_t size) { + if (!b) return CFREE_INVALID; + obj_symbol_define(b, pub_to_intern_sym(sym), pub_to_intern_sec(section), + value, size); + return CFREE_OK; +} + +CfreeStatus cfree_obj_builder_reloc(CfreeObjBuilder* b, + const CfreeObjRelocDesc* desc) { + if (!b || !desc) return CFREE_INVALID; + /* Public CfreeRelocKind.code is the raw internal RelocKind value + * (single shared numeric space). */ + obj_reloc(b, pub_to_intern_sec(desc->section), (u32)desc->offset, + (RelocKind)desc->kind.code, pub_to_intern_sym(desc->symbol), + desc->addend); + return CFREE_OK; +} + +CfreeStatus cfree_obj_builder_group(CfreeObjBuilder* b, CfreeSym name, + CfreeObjSymbol signature, uint32_t flags, + CfreeObjGroup* out) { + ObjGroupId id; + if (!b || !out) return CFREE_INVALID; + id = obj_group(b, (Sym)name, pub_to_intern_sym(signature), flags); + if (id == OBJ_GROUP_NONE) return CFREE_ERR; + *out = intern_to_pub_group(id); + return CFREE_OK; +} + +CfreeStatus cfree_obj_builder_group_add_section(CfreeObjBuilder* b, + CfreeObjGroup grp, + CfreeObjSection sec) { + if (!b) return CFREE_INVALID; + obj_group_add_section(b, pub_to_intern_group(grp), pub_to_intern_sec(sec)); + return CFREE_OK; +} + +CfreeStatus cfree_obj_builder_finalize(CfreeObjBuilder* b) { + if (!b) return CFREE_INVALID; + obj_finalize(b); + return CFREE_OK; +} + +CfreeStatus cfree_obj_builder_emit(CfreeObjBuilder* b, CfreeWriter* w) { + Compiler* c; + if (!b || !w) return CFREE_INVALID; + c = obj_compiler(b); + if (!c) return CFREE_INVALID; + switch (c->target.obj) { + case CFREE_OBJ_ELF: + emit_elf(c, b, w); + break; + case CFREE_OBJ_COFF: + emit_coff(c, b, w); + break; + case CFREE_OBJ_MACHO: + emit_macho(c, b, w); + break; + case CFREE_OBJ_WASM: + emit_wasm(c, b, w); + break; + default: + return CFREE_UNSUPPORTED; + } + return cfree_writer_status(w); +} diff --git a/src/api/detect.c b/src/api/object_detect.c diff --git a/src/api/object_file.c b/src/api/object_file.c @@ -0,0 +1,375 @@ +/* Public CfreeObjFile reader. Wraps the internal read_/obj_ surface + * and exposes format-neutral object inspection. */ + +#include <cfree/object.h> +#include <setjmp.h> +#include <string.h> + +#include "core/buf.h" +#include "core/core.h" +#include "core/heap.h" +#include "core/pool.h" +#include "obj/obj.h" + +struct CfreeObjFile { + Compiler compiler; + const CfreeContext* ctx; + ObjBuilder* ob; + ObjFmt fmt; + CfreeTarget target; + const u8** sec_data_cache; + u32* sec_data_size; + u32 sec_data_n; +}; + +static ObjBuilder* obj_read_bytes(Compiler* c, const char* name, const u8* data, + size_t len, ObjFmt fmt) { + switch (fmt) { + case CFREE_OBJ_ELF: + return read_elf(c, name, data, len); + case CFREE_OBJ_COFF: + return read_coff(c, name, data, len); + case CFREE_OBJ_MACHO: + return read_macho(c, name, data, len); + case CFREE_OBJ_WASM: + return read_wasm(c, name, data, len); + } + return NULL; +} + +CfreeStatus cfree_obj_open(const CfreeContext* ctx, const CfreeBytes* input, + CfreeObjFile** out) { + Heap* h; + CfreeObjFile* f; + CfreeTarget target; + CfreeStatus st; + + if (!out) return CFREE_INVALID; + *out = NULL; + if (!ctx || !ctx->heap || !input) return CFREE_INVALID; + if (!input->data && input->len > 0) return CFREE_INVALID; + + st = cfree_detect_target(input->data, input->len, &target); + if (st != CFREE_OK) return st; + + h = ctx->heap; + f = (CfreeObjFile*)h->alloc(h, sizeof(*f), _Alignof(CfreeObjFile)); + if (!f) return CFREE_NOMEM; + memset(f, 0, sizeof(*f)); + f->ctx = ctx; + f->fmt = target.obj; + f->target = target; + + compiler_init(&f->compiler, target, ctx); + if (setjmp(f->compiler.panic)) { + compiler_run_cleanups(&f->compiler); + compiler_fini(&f->compiler); + h->free(h, f, sizeof(*f)); + return CFREE_MALFORMED; + } + f->ob = obj_read_bytes(&f->compiler, input->name, input->data, input->len, + target.obj); + if (!f->ob) { + compiler_fini(&f->compiler); + h->free(h, f, sizeof(*f)); + return CFREE_MALFORMED; + } + *out = f; + return CFREE_OK; +} + +void cfree_obj_free(CfreeObjFile* f) { + Heap* h; + if (!f) return; + h = f->ctx->heap; + if (f->sec_data_cache) { + u32 i; + for (i = 0; i < f->sec_data_n; ++i) { + if (f->sec_data_cache[i]) { + h->free(h, (void*)f->sec_data_cache[i], f->sec_data_size[i]); + } + } + h->free(h, f->sec_data_cache, sizeof(*f->sec_data_cache) * f->sec_data_n); + h->free(h, f->sec_data_size, sizeof(*f->sec_data_size) * f->sec_data_n); + } + if (f->ob) obj_free(f->ob); + compiler_fini(&f->compiler); + h->free(h, f, sizeof(*f)); +} + +CfreeObjFmt cfree_obj_fmt(const CfreeObjFile* f) { return f->fmt; } + +CfreeTarget cfree_obj_target(const CfreeObjFile* f) { return f->target; } + +uint32_t cfree_obj_nsections(const CfreeObjFile* f) { + return obj_section_count(f->ob); +} + +CfreeStatus cfree_obj_section(const CfreeObjFile* f, CfreeObjSection idx, + CfreeObjSecInfo* out) { + const Section* sec; + if (!f || !out) return CFREE_INVALID; + 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->kind = (CfreeSecKind)sec->kind; + out->flags = (uint32_t)sec->flags; + out->size = sec->bss_size ? sec->bss_size : sec->bytes.total; + out->align = sec->align > 1u ? sec->align : 1u; + out->entsize = sec->entsize; + return CFREE_OK; +} + +CfreeStatus cfree_obj_section_data(const CfreeObjFile* cf, CfreeObjSection idx, + const uint8_t** data_out, size_t* len_out) { + CfreeObjFile* f = (CfreeObjFile*)cf; + const Section* sec; + Heap* h; + u32 n; + u8* buf; + + if (!f || !data_out || !len_out) return CFREE_INVALID; + *data_out = NULL; + *len_out = 0; + + n = obj_section_count(f->ob); + if (idx >= n) return CFREE_NOT_FOUND; + + sec = obj_section_get(f->ob, (ObjSecId)(idx + 1)); + if (!sec) return CFREE_NOT_FOUND; + if (sec->bss_size || sec->bytes.total == 0) return CFREE_OK; + + h = f->ctx->heap; + + if (!f->sec_data_cache) { + f->sec_data_cache = (const u8**)h->alloc(h, sizeof(*f->sec_data_cache) * n, + _Alignof(const u8*)); + if (!f->sec_data_cache) return CFREE_NOMEM; + f->sec_data_size = + (u32*)h->alloc(h, sizeof(*f->sec_data_size) * n, _Alignof(u32)); + if (!f->sec_data_size) { + h->free(h, f->sec_data_cache, sizeof(*f->sec_data_cache) * n); + f->sec_data_cache = NULL; + return CFREE_NOMEM; + } + { + u32 i; + for (i = 0; i < n; ++i) { + f->sec_data_cache[i] = NULL; + f->sec_data_size[i] = 0; + } + } + f->sec_data_n = n; + } + + if (f->sec_data_cache[idx]) { + *data_out = f->sec_data_cache[idx]; + *len_out = f->sec_data_size[idx]; + return CFREE_OK; + } + + buf = (u8*)h->alloc(h, sec->bytes.total, 1); + if (!buf) return CFREE_NOMEM; + buf_flatten(&sec->bytes, buf); + f->sec_data_cache[idx] = buf; + f->sec_data_size[idx] = sec->bytes.total; + *data_out = buf; + *len_out = sec->bytes.total; + return CFREE_OK; +} + +CfreeStatus cfree_obj_section_by_name(const CfreeObjFile* f, const char* name, + CfreeObjSection* out) { + u32 n, i; + if (!f || !name || !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) { + *out = i; + return CFREE_OK; + } + } + return CFREE_NOT_FOUND; +} + +static void fill_syminfo(const CfreeObjFile* f, const ObjSym* sym, + CfreeObjSymInfo* out) { + out->name = sym->name ? pool_str(f->compiler.global, sym->name, NULL) : ""; + out->bind = (CfreeSymBind)sym->bind; + out->kind = (CfreeSymKind)sym->kind; + out->section = sym->section_id != OBJ_SEC_NONE + ? (CfreeObjSection)(sym->section_id - 1) + : CFREE_SECTION_NONE; + out->value = sym->value; + out->size = sym->size; +} + +CfreeStatus cfree_obj_symbol_by_name(const CfreeObjFile* f, const char* name, + CfreeObjSymInfo* out) { + ObjSymIter* it; + ObjSymEntry e; + if (!f || !name || !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) { + fill_syminfo(f, e.sym, out); + obj_symiter_free(it); + return CFREE_OK; + } + } + obj_symiter_free(it); + return CFREE_NOT_FOUND; +} + +struct CfreeObjSymIter { + CfreeObjFile* file; + ObjSymIter* inner; +}; + +CfreeStatus cfree_obj_symiter_new(CfreeObjFile* f, CfreeObjSymIter** out) { + Heap* h; + CfreeObjSymIter* it; + if (!f || !out) return CFREE_INVALID; + h = f->ctx->heap; + it = (CfreeObjSymIter*)h->alloc(h, sizeof(*it), _Alignof(CfreeObjSymIter)); + if (!it) return CFREE_NOMEM; + it->file = f; + it->inner = obj_symiter_new(f->ob); + if (!it->inner) { + h->free(h, it, sizeof(*it)); + return CFREE_NOMEM; + } + *out = it; + return CFREE_OK; +} + +CfreeIterResult cfree_obj_symiter_next(CfreeObjSymIter* it, + CfreeObjSymInfo* out) { + ObjSymEntry entry; + if (!it || !out) return CFREE_ITER_ERROR; + if (!obj_symiter_next(it->inner, &entry)) return CFREE_ITER_END; + fill_syminfo(it->file, entry.sym, out); + return CFREE_ITER_ITEM; +} + +void cfree_obj_symiter_free(CfreeObjSymIter* it) { + Heap* h; + if (!it) return; + obj_symiter_free(it->inner); + h = it->file->ctx->heap; + h->free(h, it, sizeof(*it)); +} + +struct CfreeObjRelocIter { + CfreeObjFile* file; + u32 idx; + u32 total; +}; + +CfreeStatus cfree_obj_reliter_new(CfreeObjFile* f, CfreeObjRelocIter** out) { + Heap* h; + CfreeObjRelocIter* it; + if (!f || !out) return CFREE_INVALID; + h = f->ctx->heap; + it = + (CfreeObjRelocIter*)h->alloc(h, sizeof(*it), _Alignof(CfreeObjRelocIter)); + if (!it) return CFREE_NOMEM; + it->file = f; + it->idx = 0; + it->total = obj_reloc_total(f->ob); + *out = it; + return CFREE_OK; +} + +CfreeIterResult cfree_obj_reliter_next(CfreeObjRelocIter* it, + CfreeObjReloc* out) { + const Reloc* r; + const ObjSym* sym; + if (!it || !out) return CFREE_ITER_ERROR; + if (it->idx >= it->total) return CFREE_ITER_END; + + r = obj_reloc_at(it->file->ob, it->idx++); + out->section = + r->section_id ? (CfreeObjSection)(r->section_id - 1) : CFREE_SECTION_NONE; + out->offset = r->offset; + out->addend = r->addend; + out->kind.arch = it->file->target.arch; + out->kind.obj_fmt = it->file->fmt; + out->kind.code = (uint32_t)r->kind; + out->kind_name = NULL; + + if (r->sym == OBJ_SYM_NONE) { + out->sym = CFREE_OBJ_SYMBOL_NONE; + out->sym_name = ""; + } 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) + : ""; + } + return CFREE_ITER_ITEM; +} + +void cfree_obj_reliter_free(CfreeObjRelocIter* it) { + Heap* h; + if (!it) return; + h = it->file->ctx->heap; + h->free(h, it, sizeof(*it)); +} + +/* Accessor for disasm/jit to access the underlying ObjBuilder when both + * are inside libcfree. Not part of the public API. */ +ObjBuilder* cfree_objfile_builder(const CfreeObjFile* f) { + return f ? f->ob : NULL; +} + +/* Allocate an empty CfreeObjFile wrapping a private Compiler and a fresh + * ObjBuilder. Used by the JIT debug-view builder (src/link/link_jit.c) + * to assemble a synthetic object file from merged input debug sections. + * The handle is freed via cfree_objfile_internal_free below — the public + * cfree_obj_free path is keyed off obj_read_bytes, so the view path uses + * its own teardown that does not depend on the cached section data + * tables. */ +CfreeObjFile* cfree_objfile_internal_new(const CfreeContext* ctx, + CfreeTarget target, CfreeObjFmt fmt) { + Heap* h; + CfreeObjFile* f; + if (!ctx || !ctx->heap) return NULL; + h = ctx->heap; + f = (CfreeObjFile*)h->alloc(h, sizeof(*f), _Alignof(CfreeObjFile)); + if (!f) return NULL; + memset(f, 0, sizeof(*f)); + f->ctx = ctx; + f->fmt = fmt; + f->target = target; + compiler_init(&f->compiler, target, ctx); + if (setjmp(f->compiler.panic)) { + compiler_run_cleanups(&f->compiler); + compiler_fini(&f->compiler); + h->free(h, f, sizeof(*f)); + return NULL; + } + f->ob = obj_new(&f->compiler); + if (!f->ob) { + compiler_fini(&f->compiler); + h->free(h, f, sizeof(*f)); + return NULL; + } + return f; +} + +void cfree_objfile_internal_free(CfreeObjFile* f) { + /* Same teardown contract as cfree_obj_free: caller may have cached + * section data, so we route through the same path. */ + cfree_obj_free(f); +} diff --git a/src/api/objfile.c b/src/api/objfile.c @@ -1,376 +0,0 @@ -/* Public CfreeObjFile reader. Wraps the internal read_/obj_ surface - * and exposes format-neutral object inspection. */ - -#include <cfree/object.h> -#include <setjmp.h> -#include <string.h> - -#include "core/buf.h" -#include "core/core.h" -#include "core/heap.h" -#include "core/pool.h" -#include "obj/obj.h" - -struct CfreeObjFile { - Compiler compiler; - const CfreeContext* ctx; - ObjBuilder* ob; - ObjFmt fmt; - CfreeTarget target; - const u8** sec_data_cache; - u32* sec_data_size; - u32 sec_data_n; -}; - -static ObjBuilder* obj_read_bytes(Compiler* c, const char* name, const u8* data, - size_t len, ObjFmt fmt) { - switch (fmt) { - case CFREE_OBJ_ELF: - return read_elf(c, name, data, len); - case CFREE_OBJ_COFF: - return read_coff(c, name, data, len); - case CFREE_OBJ_MACHO: - return read_macho(c, name, data, len); - case CFREE_OBJ_WASM: - return read_wasm(c, name, data, len); - } - return NULL; -} - -CfreeStatus cfree_obj_open(const CfreeContext* ctx, const CfreeBytes* input, - CfreeObjFile** out) { - Heap* h; - CfreeObjFile* f; - CfreeTarget target; - CfreeStatus st; - - if (!out) return CFREE_INVALID; - *out = NULL; - if (!ctx || !ctx->heap || !input) return CFREE_INVALID; - if (!input->data && input->len > 0) return CFREE_INVALID; - - st = cfree_detect_target(input->data, input->len, &target); - if (st != CFREE_OK) return st; - - h = ctx->heap; - f = (CfreeObjFile*)h->alloc(h, sizeof(*f), _Alignof(CfreeObjFile)); - if (!f) return CFREE_NOMEM; - memset(f, 0, sizeof(*f)); - f->ctx = ctx; - f->fmt = target.obj; - f->target = target; - - compiler_init(&f->compiler, target, ctx); - if (setjmp(f->compiler.panic)) { - compiler_run_cleanups(&f->compiler); - compiler_fini(&f->compiler); - h->free(h, f, sizeof(*f)); - return CFREE_MALFORMED; - } - f->ob = obj_read_bytes(&f->compiler, input->name, input->data, input->len, - target.obj); - if (!f->ob) { - compiler_fini(&f->compiler); - h->free(h, f, sizeof(*f)); - return CFREE_MALFORMED; - } - *out = f; - return CFREE_OK; -} - -void cfree_obj_free(CfreeObjFile* f) { - Heap* h; - if (!f) return; - h = f->ctx->heap; - if (f->sec_data_cache) { - u32 i; - for (i = 0; i < f->sec_data_n; ++i) { - if (f->sec_data_cache[i]) { - h->free(h, (void*)f->sec_data_cache[i], f->sec_data_size[i]); - } - } - h->free(h, f->sec_data_cache, sizeof(*f->sec_data_cache) * f->sec_data_n); - h->free(h, f->sec_data_size, sizeof(*f->sec_data_size) * f->sec_data_n); - } - if (f->ob) obj_free(f->ob); - compiler_fini(&f->compiler); - h->free(h, f, sizeof(*f)); -} - -CfreeObjFmt cfree_obj_fmt(const CfreeObjFile* f) { return f->fmt; } - -CfreeTarget cfree_obj_target(const CfreeObjFile* f) { return f->target; } - -uint32_t cfree_obj_nsections(const CfreeObjFile* f) { - return obj_section_count(f->ob); -} - -CfreeStatus cfree_obj_section(const CfreeObjFile* f, CfreeObjSection idx, - CfreeObjSecInfo* out) { - const Section* sec; - if (!f || !out) return CFREE_INVALID; - 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->kind = (CfreeSecKind)sec->kind; - out->flags = (uint32_t)sec->flags; - out->size = sec->bss_size ? sec->bss_size : sec->bytes.total; - out->align = sec->align > 1u ? sec->align : 1u; - out->entsize = sec->entsize; - return CFREE_OK; -} - -CfreeStatus cfree_obj_section_data(const CfreeObjFile* cf, CfreeObjSection idx, - const uint8_t** data_out, - size_t* len_out) { - CfreeObjFile* f = (CfreeObjFile*)cf; - const Section* sec; - Heap* h; - u32 n; - u8* buf; - - if (!f || !data_out || !len_out) return CFREE_INVALID; - *data_out = NULL; - *len_out = 0; - - n = obj_section_count(f->ob); - if (idx >= n) return CFREE_NOT_FOUND; - - sec = obj_section_get(f->ob, (ObjSecId)(idx + 1)); - if (!sec) return CFREE_NOT_FOUND; - if (sec->bss_size || sec->bytes.total == 0) return CFREE_OK; - - h = f->ctx->heap; - - if (!f->sec_data_cache) { - f->sec_data_cache = (const u8**)h->alloc( - h, sizeof(*f->sec_data_cache) * n, _Alignof(const u8*)); - if (!f->sec_data_cache) return CFREE_NOMEM; - f->sec_data_size = - (u32*)h->alloc(h, sizeof(*f->sec_data_size) * n, _Alignof(u32)); - if (!f->sec_data_size) { - h->free(h, f->sec_data_cache, sizeof(*f->sec_data_cache) * n); - f->sec_data_cache = NULL; - return CFREE_NOMEM; - } - { - u32 i; - for (i = 0; i < n; ++i) { - f->sec_data_cache[i] = NULL; - f->sec_data_size[i] = 0; - } - } - f->sec_data_n = n; - } - - if (f->sec_data_cache[idx]) { - *data_out = f->sec_data_cache[idx]; - *len_out = f->sec_data_size[idx]; - return CFREE_OK; - } - - buf = (u8*)h->alloc(h, sec->bytes.total, 1); - if (!buf) return CFREE_NOMEM; - buf_flatten(&sec->bytes, buf); - f->sec_data_cache[idx] = buf; - f->sec_data_size[idx] = sec->bytes.total; - *data_out = buf; - *len_out = sec->bytes.total; - return CFREE_OK; -} - -CfreeStatus cfree_obj_section_by_name(const CfreeObjFile* f, const char* name, - CfreeObjSection* out) { - u32 n, i; - if (!f || !name || !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) { - *out = i; - return CFREE_OK; - } - } - return CFREE_NOT_FOUND; -} - -static void fill_syminfo(const CfreeObjFile* f, const ObjSym* sym, - CfreeObjSymInfo* out) { - out->name = sym->name ? pool_str(f->compiler.global, sym->name, NULL) : ""; - out->bind = (CfreeSymBind)sym->bind; - out->kind = (CfreeSymKind)sym->kind; - out->section = sym->section_id != OBJ_SEC_NONE - ? (CfreeObjSection)(sym->section_id - 1) - : CFREE_SECTION_NONE; - out->value = sym->value; - out->size = sym->size; -} - -CfreeStatus cfree_obj_symbol_by_name(const CfreeObjFile* f, const char* name, - CfreeObjSymInfo* out) { - ObjSymIter* it; - ObjSymEntry e; - if (!f || !name || !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) { - fill_syminfo(f, e.sym, out); - obj_symiter_free(it); - return CFREE_OK; - } - } - obj_symiter_free(it); - return CFREE_NOT_FOUND; -} - -struct CfreeObjSymIter { - CfreeObjFile* file; - ObjSymIter* inner; -}; - -CfreeStatus cfree_obj_symiter_new(CfreeObjFile* f, CfreeObjSymIter** out) { - Heap* h; - CfreeObjSymIter* it; - if (!f || !out) return CFREE_INVALID; - h = f->ctx->heap; - it = (CfreeObjSymIter*)h->alloc(h, sizeof(*it), _Alignof(CfreeObjSymIter)); - if (!it) return CFREE_NOMEM; - it->file = f; - it->inner = obj_symiter_new(f->ob); - if (!it->inner) { - h->free(h, it, sizeof(*it)); - return CFREE_NOMEM; - } - *out = it; - return CFREE_OK; -} - -CfreeIterResult cfree_obj_symiter_next(CfreeObjSymIter* it, - CfreeObjSymInfo* out) { - ObjSymEntry entry; - if (!it || !out) return CFREE_ITER_ERROR; - if (!obj_symiter_next(it->inner, &entry)) return CFREE_ITER_END; - fill_syminfo(it->file, entry.sym, out); - return CFREE_ITER_ITEM; -} - -void cfree_obj_symiter_free(CfreeObjSymIter* it) { - Heap* h; - if (!it) return; - obj_symiter_free(it->inner); - h = it->file->ctx->heap; - h->free(h, it, sizeof(*it)); -} - -struct CfreeObjRelocIter { - CfreeObjFile* file; - u32 idx; - u32 total; -}; - -CfreeStatus cfree_obj_reliter_new(CfreeObjFile* f, CfreeObjRelocIter** out) { - Heap* h; - CfreeObjRelocIter* it; - if (!f || !out) return CFREE_INVALID; - h = f->ctx->heap; - it = (CfreeObjRelocIter*)h->alloc(h, sizeof(*it), - _Alignof(CfreeObjRelocIter)); - if (!it) return CFREE_NOMEM; - it->file = f; - it->idx = 0; - it->total = obj_reloc_total(f->ob); - *out = it; - return CFREE_OK; -} - -CfreeIterResult cfree_obj_reliter_next(CfreeObjRelocIter* it, - CfreeObjReloc* out) { - const Reloc* r; - const ObjSym* sym; - if (!it || !out) return CFREE_ITER_ERROR; - if (it->idx >= it->total) return CFREE_ITER_END; - - r = obj_reloc_at(it->file->ob, it->idx++); - out->section = - r->section_id ? (CfreeObjSection)(r->section_id - 1) : CFREE_SECTION_NONE; - out->offset = r->offset; - out->addend = r->addend; - out->kind.arch = it->file->target.arch; - out->kind.obj_fmt = it->file->fmt; - out->kind.code = (uint32_t)r->kind; - out->kind_name = NULL; - - if (r->sym == OBJ_SYM_NONE) { - out->sym = CFREE_OBJ_SYMBOL_NONE; - out->sym_name = ""; - } 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) - : ""; - } - return CFREE_ITER_ITEM; -} - -void cfree_obj_reliter_free(CfreeObjRelocIter* it) { - Heap* h; - if (!it) return; - h = it->file->ctx->heap; - h->free(h, it, sizeof(*it)); -} - -/* Accessor for disasm/jit to access the underlying ObjBuilder when both - * are inside libcfree. Not part of the public API. */ -ObjBuilder* cfree_objfile_builder(const CfreeObjFile* f) { - return f ? f->ob : NULL; -} - -/* Allocate an empty CfreeObjFile wrapping a private Compiler and a fresh - * ObjBuilder. Used by the JIT debug-view builder (src/link/link_jit.c) - * to assemble a synthetic object file from merged input debug sections. - * The handle is freed via cfree_objfile_internal_free below — the public - * cfree_obj_free path is keyed off obj_read_bytes, so the view path uses - * its own teardown that does not depend on the cached section data - * tables. */ -CfreeObjFile* cfree_objfile_internal_new(const CfreeContext* ctx, - CfreeTarget target, CfreeObjFmt fmt) { - Heap* h; - CfreeObjFile* f; - if (!ctx || !ctx->heap) return NULL; - h = ctx->heap; - f = (CfreeObjFile*)h->alloc(h, sizeof(*f), _Alignof(CfreeObjFile)); - if (!f) return NULL; - memset(f, 0, sizeof(*f)); - f->ctx = ctx; - f->fmt = fmt; - f->target = target; - compiler_init(&f->compiler, target, ctx); - if (setjmp(f->compiler.panic)) { - compiler_run_cleanups(&f->compiler); - compiler_fini(&f->compiler); - h->free(h, f, sizeof(*f)); - return NULL; - } - f->ob = obj_new(&f->compiler); - if (!f->ob) { - compiler_fini(&f->compiler); - h->free(h, f, sizeof(*f)); - return NULL; - } - return f; -} - -void cfree_objfile_internal_free(CfreeObjFile* f) { - /* Same teardown contract as cfree_obj_free: caller may have cached - * section data, so we route through the same path. */ - cfree_obj_free(f); -} diff --git a/src/api/pipeline.c b/src/api/pipeline.c @@ -1,351 +0,0 @@ -/* libcfree's top-level compile entry points. Status-returning shapes - * that drive the C, asm, and registered-frontend paths. */ - -#include <cfree/compile.h> -#include <cfree/core.h> - -#include "arch/arch.h" -#include "asm/asm.h" -#include "core/arena.h" -#include "core/core.h" -#include "core/heap.h" -#include "core/metrics.h" -#include "core/pool.h" -#include "obj/obj.h" - -static SrcLoc no_loc(void) { - SrcLoc loc; - loc.file_id = 0; - loc.line = 0; - loc.col = 0; - return loc; -} - -static _Noreturn void panic_bad_options(Compiler* c, const char* msg) { - compiler_panic(c, no_loc(), "bad cfree options: %s", msg); -} - -CfreeLanguage cfree_language_for_path(const char* path) { - size_t i, len; - if (!path) return CFREE_LANG_C; - for (len = 0; path[len]; ++len) { - } - i = len; - while (i > 0) { - --i; - if (path[i] == '/') return CFREE_LANG_C; - if (path[i] == '.') { - const char* ext = path + i + 1; - if (ext[0] == 's' && ext[1] == '\0') return CFREE_LANG_ASM; - if (ext[0] == 't' && ext[1] == 'o' && ext[2] == 'y' && ext[3] == '\0') - return CFREE_LANG_TOY; - if (ext[0] == 'w' && ext[1] == 'a' && ext[2] == 't' && ext[3] == '\0') - return CFREE_LANG_WASM; - if (ext[0] == 'w' && ext[1] == 'a' && ext[2] == 's' && ext[3] == 'm' && - ext[4] == '\0') - return CFREE_LANG_WASM; - return CFREE_LANG_C; - } - } - return CFREE_LANG_C; -} - -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) { - panic_bad_options(c, "input data is NULL but len > 0"); - } -} - -static void emit_object_bytes(Compiler* c, ObjBuilder* ob, Writer* w) { - switch (c->target.obj) { - case CFREE_OBJ_ELF: - emit_elf(c, ob, w); - break; - case CFREE_OBJ_COFF: - emit_coff(c, ob, w); - break; - case CFREE_OBJ_MACHO: - emit_macho(c, ob, w); - break; - case CFREE_OBJ_WASM: - emit_wasm(c, ob, w); - break; - } -} - -/* Run the source-input-shaped path. */ -static void compile_source_into(Compiler* c, - const CfreeFrontendCompileOptions* opts, - const CfreeSourceInput* input, - ObjBuilder* ob) { - CfreeCompileFn frontend = NULL; - AsmLexer* lex; - MCEmitter* mc; - - if ((unsigned)input->lang < CFREE_LANG_COUNT) { - frontend = c->frontends[input->lang]; - } - if (frontend) { - CfreeStatus st; - metrics_scope_begin(c, "compile.frontend"); - st = frontend(c, 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); - } - metrics_scope_begin(c, "compile.obj_finalize"); - obj_finalize(ob); - metrics_scope_end(c, "compile.obj_finalize"); - metrics_count(c, "compile.obj_sections", obj_section_count(ob)); - metrics_count(c, "compile.obj_relocs", obj_reloc_total(ob)); - return; - } - - if (input->lang == CFREE_LANG_ASM) { - 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); - metrics_scope_end(c, "compile.asm.lex_open"); - metrics_scope_begin(c, "compile.asm.mc_new"); - mc = mc_new(c, ob); - metrics_scope_end(c, "compile.asm.mc_new"); - metrics_scope_begin(c, "compile.asm.parse"); - asm_parse(c, lex, mc); - metrics_scope_end(c, "compile.asm.parse"); - metrics_scope_begin(c, "compile.obj_finalize"); - obj_finalize(ob); - metrics_scope_end(c, "compile.obj_finalize"); - metrics_count(c, "compile.obj_sections", obj_section_count(ob)); - metrics_count(c, "compile.obj_relocs", obj_reloc_total(ob)); - metrics_scope_begin(c, "compile.asm.mc_free"); - mc_free(mc); - metrics_scope_end(c, "compile.asm.mc_free"); - return; - } - - compiler_panic(c, no_loc(), "no frontend registered for language: %u", - (u32)input->lang); -} - -/* ============================================================ - * C - * ============================================================ */ - -static CfreeStatus compile_c_into(Compiler* c, - const CfreeCCompileOptions* opts, - const CfreeBytes* input, ObjBuilder* ob) { - CfreeFrontendCompileOptions fe; - CfreeSourceInput si; - CfreeCompileFn frontend; - - frontend = c->frontends[CFREE_LANG_C]; - if (!frontend) { - compiler_panic(c, no_loc(), "no C frontend registered"); - } - - fe.code = opts->code; - fe.diagnostics = opts->diagnostics; - fe.language_options = opts; - si.bytes = *input; - si.lang = CFREE_LANG_C; - - metrics_scope_begin(c, "compile.frontend"); - CfreeStatus st = frontend(c, &fe, &si, ob); - metrics_scope_end(c, "compile.frontend"); - if (st != CFREE_OK) { - compiler_panic(c, no_loc(), "C frontend failed for input: %s", input->name); - } - metrics_scope_begin(c, "compile.obj_finalize"); - obj_finalize(ob); - metrics_scope_end(c, "compile.obj_finalize"); - return CFREE_OK; -} - -CfreeStatus cfree_compile_c_obj(CfreeCompiler* c, - const CfreeCCompileOptions* opts, - const CfreeBytes* input, - CfreeObjBuilder** out) { - PanicSave saved; - ObjBuilder* ob; - - if (!out) return CFREE_INVALID; - *out = NULL; - if (!c || !opts || !input) return CFREE_INVALID; - compiler_panic_save(c, &saved); - if (setjmp(c->panic)) { - compiler_run_cleanups(c); - compiler_panic_restore(c, &saved); - return CFREE_ERR; - } - validate_bytes(c, input); - ob = obj_new(c); - metrics_scope_begin(c, "compile.tu"); - metrics_count(c, "compile.input_bytes", (u64)input->len); - compile_c_into(c, opts, input, ob); - metrics_scope_end(c, "compile.tu"); - *out = ob; - compiler_panic_restore(c, &saved); - return CFREE_OK; -} - -CfreeStatus cfree_compile_c_obj_emit(CfreeCompiler* c, - const CfreeCCompileOptions* opts, - const CfreeBytes* input, - CfreeWriter* out) { - PanicSave saved; - ObjBuilder* ob; - - if (!c || !opts || !input || !out) return CFREE_INVALID; - compiler_panic_save(c, &saved); - if (setjmp(c->panic)) { - compiler_run_cleanups(c); - compiler_panic_restore(c, &saved); - return CFREE_ERR; - } - validate_bytes(c, input); - ob = obj_new(c); - metrics_scope_begin(c, "compile.tu"); - metrics_count(c, "compile.input_bytes", (u64)input->len); - compile_c_into(c, opts, input, ob); - emit_object_bytes(c, ob, out); - metrics_scope_end(c, "compile.tu"); - obj_free(ob); - compiler_panic_restore(c, &saved); - return CFREE_OK; -} - -/* ============================================================ - * Asm - * ============================================================ */ - -static void compile_asm_into(Compiler* c, const CfreeAsmCompileOptions* opts, - const CfreeBytes* input, ObjBuilder* ob) { - AsmLexer* lex; - MCEmitter* mc; - (void)opts; - metrics_scope_begin(c, "compile.asm.lex_open"); - lex = asm_lex_open_mem(c, input->name, (const char*)input->data, input->len); - metrics_scope_end(c, "compile.asm.lex_open"); - metrics_scope_begin(c, "compile.asm.mc_new"); - mc = mc_new(c, ob); - metrics_scope_end(c, "compile.asm.mc_new"); - metrics_scope_begin(c, "compile.asm.parse"); - asm_parse(c, lex, mc); - metrics_scope_end(c, "compile.asm.parse"); - metrics_scope_begin(c, "compile.obj_finalize"); - obj_finalize(ob); - metrics_scope_end(c, "compile.obj_finalize"); - metrics_scope_begin(c, "compile.asm.mc_free"); - mc_free(mc); - metrics_scope_end(c, "compile.asm.mc_free"); -} - -CfreeStatus cfree_compile_asm_obj(CfreeCompiler* c, - const CfreeAsmCompileOptions* opts, - const CfreeBytes* input, - CfreeObjBuilder** out) { - PanicSave saved; - ObjBuilder* ob; - - if (!out) return CFREE_INVALID; - *out = NULL; - if (!c || !opts || !input) return CFREE_INVALID; - compiler_panic_save(c, &saved); - if (setjmp(c->panic)) { - compiler_run_cleanups(c); - compiler_panic_restore(c, &saved); - return CFREE_ERR; - } - validate_bytes(c, input); - ob = obj_new(c); - metrics_scope_begin(c, "compile.tu"); - metrics_count(c, "compile.input_bytes", (u64)input->len); - compile_asm_into(c, opts, input, ob); - metrics_scope_end(c, "compile.tu"); - *out = ob; - compiler_panic_restore(c, &saved); - return CFREE_OK; -} - -CfreeStatus cfree_compile_asm_obj_emit(CfreeCompiler* c, - const CfreeAsmCompileOptions* opts, - const CfreeBytes* input, - CfreeWriter* out) { - PanicSave saved; - ObjBuilder* ob; - if (!c || !opts || !input || !out) return CFREE_INVALID; - compiler_panic_save(c, &saved); - if (setjmp(c->panic)) { - compiler_run_cleanups(c); - compiler_panic_restore(c, &saved); - return CFREE_ERR; - } - validate_bytes(c, input); - ob = obj_new(c); - metrics_scope_begin(c, "compile.tu"); - metrics_count(c, "compile.input_bytes", (u64)input->len); - compile_asm_into(c, opts, input, ob); - emit_object_bytes(c, ob, out); - metrics_scope_end(c, "compile.tu"); - obj_free(ob); - compiler_panic_restore(c, &saved); - return CFREE_OK; -} - -/* ============================================================ - * Source (registered frontend) - * ============================================================ */ - -CfreeStatus cfree_compile_source_obj(CfreeCompiler* c, - const CfreeFrontendCompileOptions* opts, - const CfreeSourceInput* input, - CfreeObjBuilder** out) { - PanicSave saved; - ObjBuilder* ob; - - if (!out) return CFREE_INVALID; - *out = NULL; - if (!c || !opts || !input) return CFREE_INVALID; - compiler_panic_save(c, &saved); - if (setjmp(c->panic)) { - compiler_run_cleanups(c); - compiler_panic_restore(c, &saved); - return CFREE_ERR; - } - validate_bytes(c, &input->bytes); - ob = obj_new(c); - metrics_scope_begin(c, "compile.tu"); - metrics_count(c, "compile.input_bytes", (u64)input->bytes.len); - compile_source_into(c, opts, input, ob); - metrics_scope_end(c, "compile.tu"); - *out = ob; - compiler_panic_restore(c, &saved); - return CFREE_OK; -} - -CfreeStatus cfree_compile_source_obj_emit(CfreeCompiler* c, - const CfreeFrontendCompileOptions* opts, - const CfreeSourceInput* input, - CfreeWriter* out) { - PanicSave saved; - ObjBuilder* ob; - if (!c || !opts || !input || !out) return CFREE_INVALID; - compiler_panic_save(c, &saved); - if (setjmp(c->panic)) { - compiler_run_cleanups(c); - compiler_panic_restore(c, &saved); - return CFREE_ERR; - } - validate_bytes(c, &input->bytes); - ob = obj_new(c); - metrics_scope_begin(c, "compile.tu"); - metrics_count(c, "compile.input_bytes", (u64)input->bytes.len); - compile_source_into(c, opts, input, ob); - emit_object_bytes(c, ob, out); - metrics_scope_end(c, "compile.tu"); - obj_free(ob); - compiler_panic_restore(c, &saved); - return CFREE_OK; -} diff --git a/src/api/source.c b/src/api/source.c @@ -0,0 +1,64 @@ +/* Public source registry API bridge. */ + +#include <cfree/source.h> +#include <string.h> + +#include "core/core.h" +#include "core/pool.h" + +CfreeStatus cfree_source_add_file(CfreeCompiler* c, const char* path, + int system_header, uint32_t* file_id_out) { + uint32_t tmp; + CfreeStatus st; + if (!c || !file_id_out) return CFREE_INVALID; + st = source_add_file(c->sources, path, system_header, &tmp); + if (st != CFREE_OK) return st; + *file_id_out = tmp; + return CFREE_OK; +} + +CfreeStatus cfree_source_add_memory(CfreeCompiler* c, const char* name, + uint32_t* file_id_out) { + uint32_t tmp; + CfreeStatus st; + if (!c || !file_id_out) return CFREE_INVALID; + st = source_add_memory(c->sources, name, &tmp); + if (st != CFREE_OK) return st; + *file_id_out = tmp; + return CFREE_OK; +} + +CfreeStatus cfree_source_add_builtin(CfreeCompiler* c, const char* name, + uint32_t* file_id_out) { + uint32_t tmp; + CfreeStatus st; + if (!c || !file_id_out) return CFREE_INVALID; + st = source_add_builtin(c->sources, name, &tmp); + if (st != CFREE_OK) return st; + *file_id_out = tmp; + return CFREE_OK; +} + +CfreeStatus cfree_source_add_include(CfreeCompiler* c, + uint32_t includer_file_id, + uint32_t included_file_id, CfreeSrcLoc loc, + int system) { + if (!c) return CFREE_INVALID; + return source_add_include(c->sources, includer_file_id, included_file_id, loc, + system); +} + +CfreeStatus cfree_source_file(CfreeCompiler* c, uint32_t file_id, + CfreeSourceFile* out) { + const SourceFile* f; + if (!c || !out) return CFREE_INVALID; + f = source_file(c->sources, file_id); + if (!f) return CFREE_NOT_FOUND; + memset(out, 0, sizeof *out); + out->id = f->id; + out->name = f->name; + out->path = f->path; + out->kind = f->kind; + out->system_header = f->system_header; + return CFREE_OK; +} diff --git a/src/api/support_arena.c b/src/api/support_arena.c @@ -0,0 +1,45 @@ +/* Public arena support API bridge. */ + +#include <cfree/support/arena.h> + +#include "core/arena.h" +#include "core/core.h" + +struct CfreeArena { + Arena inner; +}; + +CfreeStatus cfree_arena_new(CfreeHeap* h, size_t block_size, CfreeArena** out) { + CfreeArena* a; + if (!out) return CFREE_INVALID; + if (!h) return CFREE_INVALID; + a = (CfreeArena*)h->alloc(h, sizeof(*a), _Alignof(CfreeArena)); + if (!a) return CFREE_NOMEM; + arena_init(&a->inner, (Heap*)h, block_size); + *out = a; + return CFREE_OK; +} + +void cfree_arena_free(CfreeArena* a) { + CfreeHeap* h; + if (!a) return; + h = a->inner.heap; + arena_fini(&a->inner); + h->free(h, a, sizeof(*a)); +} + +void cfree_arena_reset(CfreeArena* a) { + if (a) arena_reset(&a->inner); +} + +void* cfree_arena_alloc(CfreeArena* a, size_t size, size_t align) { + return a ? arena_alloc(&a->inner, size, align) : NULL; +} + +void* cfree_arena_zalloc(CfreeArena* a, size_t size, size_t align) { + return a ? arena_zalloc(&a->inner, size, align) : NULL; +} + +char* cfree_arena_strdup(CfreeArena* a, const char* s, size_t len) { + return a ? arena_strdup(&a->inner, s, len) : NULL; +} diff --git a/src/api/writer_mem.c b/src/api/writer_mem.c @@ -1,110 +0,0 @@ -/* In-memory CfreeWriter. */ - -#include <cfree/core.h> -#include <string.h> - -#include "core/core.h" -#include "core/heap.h" - -typedef struct MemWriter { - CfreeWriter base; - Heap* heap; - u8* data; - size_t cap; - size_t len; - size_t pos; - CfreeStatus status; -} MemWriter; - -static CfreeStatus mw_grow(MemWriter* mw, size_t needed) { - size_t new_cap; - u8* p; - - if (needed <= mw->cap) return CFREE_OK; - new_cap = mw->cap ? mw->cap : 64; - while (new_cap < needed) { - size_t doubled = new_cap * 2; - if (doubled <= new_cap) { - mw->status = CFREE_NOMEM; - return CFREE_NOMEM; - } - new_cap = doubled; - } - - p = (u8*)mw->heap->realloc(mw->heap, mw->data, mw->cap, new_cap, 1); - if (!p) { - mw->status = CFREE_NOMEM; - return CFREE_NOMEM; - } - if (new_cap > mw->cap) memset(p + mw->cap, 0, new_cap - mw->cap); - mw->data = p; - mw->cap = new_cap; - return CFREE_OK; -} - -static CfreeStatus mw_write(CfreeWriter* w, const void* data, size_t n) { - MemWriter* mw = (MemWriter*)w; - size_t end; - CfreeStatus st; - - if (mw->status != CFREE_OK) return mw->status; - if (n == 0) return CFREE_OK; - end = mw->pos + n; - if (end < mw->pos) { - mw->status = CFREE_NOMEM; - return CFREE_NOMEM; - } - st = mw_grow(mw, end); - if (st != CFREE_OK) return st; - memcpy(mw->data + mw->pos, data, n); - mw->pos = end; - if (mw->pos > mw->len) mw->len = mw->pos; - return CFREE_OK; -} - -static CfreeStatus mw_seek(CfreeWriter* w, uint64_t off) { - MemWriter* mw = (MemWriter*)w; - if (mw->status != CFREE_OK) return mw->status; - mw->pos = (size_t)off; - return CFREE_OK; -} - -static uint64_t mw_tell(CfreeWriter* w) { return ((MemWriter*)w)->pos; } - -static CfreeStatus mw_status(CfreeWriter* w) { - return ((MemWriter*)w)->status; -} - -static void mw_close(CfreeWriter* w) { - MemWriter* mw = (MemWriter*)w; - Heap* h = mw->heap; - if (mw->data) h->free(h, mw->data, mw->cap); - h->free(h, mw, sizeof(*mw)); -} - -CfreeStatus cfree_writer_mem(CfreeHeap* heap, CfreeWriter** out) { - MemWriter* mw; - if (!out) return CFREE_INVALID; - if (!heap) return CFREE_INVALID; - mw = (MemWriter*)heap->alloc(heap, sizeof(*mw), _Alignof(MemWriter)); - if (!mw) return CFREE_NOMEM; - mw->base.write = mw_write; - mw->base.seek = mw_seek; - mw->base.tell = mw_tell; - mw->base.status = mw_status; - mw->base.close = mw_close; - mw->heap = heap; - mw->data = NULL; - mw->cap = 0; - mw->len = 0; - mw->pos = 0; - mw->status = CFREE_OK; - *out = &mw->base; - return CFREE_OK; -} - -const uint8_t* cfree_writer_mem_bytes(CfreeWriter* w, size_t* len_out) { - MemWriter* mw = (MemWriter*)w; - if (len_out) *len_out = mw ? mw->len : 0; - return mw ? mw->data : NULL; -} diff --git a/src/link/link_api.c b/src/link/link_api.c @@ -1,168 +0,0 @@ -/* Public link API entries. - * - * Thin orchestrators over the Linker primitives in link.c / link_resolve.c / - * link_layout.c / link_jit.c. Each entry: - * - allocates a Linker against the caller's Compiler, - * - feeds in the CfreeLinkInputs, - * - configures lane-specific flags (pie, shared, jit), - * - calls link_resolve, - * - dispatches to the emit (writer) or JIT-map (cfree_jit_from_image) tail. - * - * The driver's job ends at populating CfreeLinkInputs; everything below this - * line is libcfree-internal. */ - -#include "link/link.h" - -#include <cfree/core.h> -#include <cfree/jit.h> -#include <cfree/link.h> -#include <setjmp.h> - -#include "core/core.h" -#include "link/link_internal.h" - -CfreeJit *cfree_jit_from_image(LinkImage *); - -static void load_inputs(Linker *l, const CfreeLinkInputs *in) { - uint32_t i; - for (i = 0; i < in->nobjs; ++i) { - if (in->objs[i]) link_add_obj(l, in->objs[i]); - } - for (i = 0; i < in->nobj_bytes; ++i) { - const CfreeBytes *b = &in->obj_bytes[i]; - link_add_obj_bytes(l, b->name, b->data, b->len); - } - for (i = 0; i < in->narchives; ++i) { - const CfreeLinkArchiveInput *a = &in->archives[i]; - link_add_archive_bytes(l, a->bytes.name, a->bytes.data, a->bytes.len, - a->whole_archive, a->link_mode, a->group_id); - } - for (i = 0; i < in->ndso_bytes; ++i) { - const CfreeBytes *b = &in->dso_bytes[i]; - link_add_dso_bytes(l, b->name, b->data, b->len); - } - if (in->linker_script) link_set_script(l, in->linker_script); - if (in->entry) link_set_entry(l, in->entry); - /* build_id_* fields are accepted but not yet plumbed through the - * Linker — the elf emit currently derives the build-id from the - * image bytes unconditionally. Left as a TODO when the linker - * grows a configurable build-id mode. */ - (void)in->build_id_mode; - (void)in->build_id_bytes; - (void)in->build_id_len; -} - -CfreeStatus cfree_link_exe(CfreeCompiler *c, const CfreeExeLinkOptions *opts, - CfreeWriter *out) { - PanicSave saved; - Linker *l; - LinkImage *img; - if (!c || !opts || !out) return CFREE_INVALID; - compiler_panic_save(c, &saved); - if (setjmp(c->panic)) { - compiler_run_cleanups(c); - compiler_panic_restore(c, &saved); - return CFREE_ERR; - } - l = link_new(c); - if (!l) { - compiler_panic_restore(c, &saved); - return CFREE_NOMEM; - } - load_inputs(l, &opts->inputs); - link_set_emit_static_exe(l, 1); - link_set_gc_sections(l, opts->gc_sections); - link_set_pie(l, opts->pie); - link_set_interp_path(l, opts->interp_path); - img = link_resolve(l); - link_emit_image_writer(img, out); - link_image_free(img); - link_free(l); - compiler_panic_restore(c, &saved); - return CFREE_OK; -} - -CfreeStatus cfree_link_shared(CfreeCompiler *c, - const CfreeSharedLinkOptions *opts, - CfreeWriter *out) { - PanicSave saved; - Linker *l; - LinkImage *img; - if (!c || !opts || !out) return CFREE_INVALID; - compiler_panic_save(c, &saved); - if (setjmp(c->panic)) { - compiler_run_cleanups(c); - compiler_panic_restore(c, &saved); - return CFREE_ERR; - } - l = link_new(c); - if (!l) { - compiler_panic_restore(c, &saved); - return CFREE_NOMEM; - } - load_inputs(l, &opts->inputs); - link_set_gc_sections(l, opts->gc_sections); - /* Shared output is intrinsically PIC and uses the dynamic emit path. */ - link_set_pie(l, 1); - /* soname / rpaths / runpaths / exports / allow_undefined: forwarded - * fields not yet wired into the Linker. Recorded here so the surface - * matches the public API; the linker emits a static shared-friendly - * image regardless for the time being. */ - (void)opts->soname; - (void)opts->rpaths; - (void)opts->nrpaths; - (void)opts->runpaths; - (void)opts->nrunpaths; - (void)opts->exports; - (void)opts->nexports; - (void)opts->allow_undefined; - img = link_resolve(l); - link_emit_image_writer(img, out); - link_image_free(img); - link_free(l); - compiler_panic_restore(c, &saved); - return CFREE_OK; -} - -CfreeStatus cfree_link_jit(CfreeCompiler *c, const CfreeJitLinkOptions *opts, - const CfreeJitHost *host, CfreeJit **out_jit) { - PanicSave saved; - Linker *l; - LinkImage *img; - CfreeJit *jit; - if (!out_jit) return CFREE_INVALID; - *out_jit = NULL; - if (!c || !opts || !host) return CFREE_INVALID; - compiler_panic_save(c, &saved); - if (setjmp(c->panic)) { - compiler_run_cleanups(c); - compiler_panic_restore(c, &saved); - return CFREE_ERR; - } - l = link_new(c); - if (!l) { - compiler_panic_restore(c, &saved); - return CFREE_NOMEM; - } - link_set_jit_host(l, host); - link_set_jit_mode(l, 1); - link_set_gc_sections(l, opts->gc_sections); - if (opts->extern_resolver) { - link_set_extern_resolver(l, opts->extern_resolver, - opts->extern_resolver_user); - } - load_inputs(l, &opts->inputs); - img = link_resolve(l); - /* cfree_jit_from_image undefers the Linker / image and binds the JIT - * to them — do not link_free(l) on success. */ - jit = cfree_jit_from_image(img); - if (!jit) { - link_image_free(img); - link_free(l); - compiler_panic_restore(c, &saved); - return CFREE_ERR; - } - *out_jit = jit; - compiler_panic_restore(c, &saved); - return CFREE_OK; -}