refactor(log): 统一日志系统并添加链接器实现

- 为所有模块添加统一的 scc_*_log.h 日志头文件,删除旧的 lexer_log.h/c
- 将运行时日志从 scc_utils 迁移到 scc_core 目录,统一日志管理
- 在解析器表达式/语句/类型解析中添加 LOG_TRACE 调试日志
- 实现 SCCF 链接器 (sccf_linker) 支持多目标文件链接
- 重构 CLI 主程序 (main.c/config.c),新增 cmd_log.h 调试支持
- 优化 x86 指令编码操作数对齐检查
- 修复预处理器的指令处理和宏展开逻辑
This commit is contained in:
zzy
2026-06-05 13:07:41 +08:00
parent 0acea43e4e
commit 88846d7479
70 changed files with 1497 additions and 469 deletions

View File

@@ -5,4 +5,5 @@ version = "0.1.0"
dependencies = [
{ name = "scc_core", path = "../../runtime/scc_core" },
{ name = "scc_utils", path = "../../runtime/scc_utils" },
{ name = "mcode", path = "../mcode" },
]

View File

@@ -13,6 +13,12 @@ typedef struct {
scc_hashtable_t str2offset;
sccf_sym_vec_t symtab;
sccf_reloc_vec_t relocs;
const char *entry_symbol_name;
} sccf_linker_t;
void sccf_linker_init(sccf_linker_t *linker);
void sccf_linker_add_sccf(sccf_linker_t *linker, const sccf_t *sccf);
void sccf_linker_set_entry_symbol_name(sccf_linker_t *linker, const char *name);
const sccf_t *sccf_linker_link(sccf_linker_t *linker);
#endif /* __SCC_FORMAT_LINKER_H__ */

View File

@@ -0,0 +1,26 @@
#ifndef __SCCF_LOG_H__
#define __SCCF_LOG_H__
typedef struct logger logger_t;
extern logger_t __scc_sccf_log;
extern logger_t __scc_sccf_user;
#define SCC_LOG_HANDLER &__scc_sccf_user
#define LOG_DEFAULT_HANDLER &__scc_sccf_log
#include <scc_log.h>
#ifdef __SCCF_LOG_IMPL__
logger_t __scc_sccf_log = {
.name = "sccf",
.level = LOG_LEVEL_ALL,
.handler = log_default_handler,
};
logger_t __scc_sccf_user = {
.name = "sccf",
.level = LOG_LEVEL_ALL,
.user_handler = scc_log_handler,
};
#endif
#endif

View File

@@ -1,4 +1,5 @@
#include <sccf_builder.h>
#include <sccf_log.h>
void sccf_builder_init(sccf_builder_t *builder) {
builder->aligned = 64;

259
libs/sccf/src/sccf_linker.c Normal file
View File

@@ -0,0 +1,259 @@
#include <sccf_linker.h>
#include <scc_mcode.h>
#include <x86/scc_x86_patch.h>
void sccf_linker_init(sccf_linker_t *linker) {
sccf_builder_init(&linker->builder);
scc_vec_init(linker->link_sccfs);
scc_strpool_init(&linker->strpool);
scc_hashtable_cstr_init(&linker->str2offset);
scc_vec_init(linker->symtab);
scc_vec_init(linker->relocs);
linker->entry_symbol_name = "_scc_entry";
}
void sccf_linker_add_sccf(sccf_linker_t *linker, const sccf_t *sccf) {
scc_vec_push(linker->link_sccfs, *sccf);
}
void sccf_linker_set_entry_symbol_name(sccf_linker_t *linker, const char *name) {
linker->entry_symbol_name = name ? name : "_scc_entry";
}
// Per-module extracted data (borrowed references to the original SCCF data)
typedef struct {
usize code_base; // offset of this module's code in merged_code
usize data_base; // offset of this module's data in merged_data
usize code_size;
usize data_size;
u8 *code_data;
u8 *data_data;
char *strtab_data;
usize strtab_size;
sccf_sym_t *sym_data;
usize sym_count;
sccf_reloc_t *reloc_data;
usize reloc_count;
} mod_ctx_t;
// Look up a section in an SCCF module by type, extract info
static void extract_mod_sections(sccf_t *mod, mod_ctx_t *ctx) {
scc_vec_foreach(mod->sect_headers, i) {
sccf_sect_header_t *sh = &scc_vec_at(mod->sect_headers, i);
sccf_sect_data_t *sd = &scc_vec_at(mod->sect_datas, i);
switch (sh->sccf_sect_type) {
case SCCF_SECT_CODE:
ctx->code_data = scc_vec_unsafe_get_data(*sd);
ctx->code_size = scc_vec_size(*sd);
break;
case SCCF_SECT_DATA:
ctx->data_data = scc_vec_unsafe_get_data(*sd);
ctx->data_size = scc_vec_size(*sd);
break;
case SCCF_SECT_STRTAB:
ctx->strtab_data = (char *)scc_vec_unsafe_get_data(*sd);
ctx->strtab_size = scc_vec_size(*sd);
break;
case SCCF_SECT_SYMTAB:
ctx->sym_data = (sccf_sym_t *)scc_vec_unsafe_get_data(*sd);
ctx->sym_count = scc_vec_size(*sd) / sizeof(sccf_sym_t);
break;
case SCCF_SECT_RELOCS:
ctx->reloc_data = (sccf_reloc_t *)scc_vec_unsafe_get_data(*sd);
ctx->reloc_count = scc_vec_size(*sd) / sizeof(sccf_reloc_t);
break;
default:
break;
}
}
}
const sccf_t *sccf_linker_link(sccf_linker_t *linker) {
usize num_modules = scc_vec_size(linker->link_sccfs);
if (num_modules <= 1) {
return sccf_builder_to_sccf(&linker->builder);
}
sccf_builder_t *builder = &linker->builder;
// Concatenated section data
sccf_sect_data_t merged_code, merged_data;
scc_vec_init(merged_code);
scc_vec_init(merged_data);
// Per-module context
SCC_VEC(mod_ctx_t) mods;
scc_vec_init(mods);
// Phase 1: extract data from each module, concatenate code and data sections
scc_vec_foreach(linker->link_sccfs, m) {
sccf_t *mod = &scc_vec_at(linker->link_sccfs, m);
mod_ctx_t ctx = {0};
extract_mod_sections(mod, &ctx);
ctx.code_base = scc_vec_size(merged_code);
for (usize j = 0; j < ctx.code_size; j++) {
scc_vec_push(merged_code, ctx.code_data[j]);
}
ctx.data_base = scc_vec_size(merged_data);
for (usize j = 0; j < ctx.data_size; j++) {
scc_vec_push(merged_data, ctx.data_data[j]);
}
scc_vec_push(mods, ctx);
}
// Phase 2: build unified symbol table.
// For each module, map local symbol index -> global symbol index.
// GLOBAL/EXTERN symbols are deduplicated by name.
// LOCAL symbols get unique entries per module (even if names collide).
typedef SCC_VEC(usize) idx_map_t;
SCC_VEC(idx_map_t) maps;
scc_vec_init(maps);
// First pass: collect all GLOBAL symbol definitions into the unified table
scc_vec_foreach(mods, m) {
mod_ctx_t *ctx = &scc_vec_at(mods, m);
idx_map_t map;
scc_vec_init(map);
// Index 0 = null symbol
scc_vec_push(map, 0);
for (usize j = 1; j < ctx->sym_count; j++) {
sccf_sym_t *sym = &ctx->sym_data[j];
const char *name = &ctx->strtab_data[sym->name_offset];
// Look up in unified table
usize global_idx =
(usize)scc_hashtable_get(&linker->str2offset, name);
if (global_idx == 0) {
// New symbol: add to builder's symtab/strtab
sccf_sym_t adjusted = *sym;
if (adjusted.sccf_sect_type == SCCF_SECT_CODE) {
adjusted.sccf_sect_offset += ctx->code_base;
} else if (adjusted.sccf_sect_type == SCCF_SECT_DATA) {
adjusted.sccf_sect_offset += ctx->data_base;
}
usize name_off = scc_vec_size(builder->strtab);
const char *p = name;
while (*p) {
scc_vec_push(builder->strtab, *p);
p++;
}
scc_vec_push(builder->strtab, '\0');
adjusted.name_offset = name_off;
global_idx = scc_vec_size(builder->symtab);
scc_vec_push(builder->symtab, adjusted);
scc_hashtable_set(&linker->str2offset, name,
(void *)global_idx);
} else {
// Symbol already exists in unified table.
// If the new entry is a definition and existing is UNDEF/EXTERN,
// update the existing entry with the definition.
sccf_sym_t *existing = &scc_vec_at(builder->symtab, global_idx);
bool existing_is_ref =
existing->sccf_sym_type == SCCF_SYM_TYPE_UNDEF ||
existing->sccf_sym_type == SCCF_SYM_TYPE_EXTERN;
bool new_is_def =
sym->sccf_sym_type != SCCF_SYM_TYPE_UNDEF &&
sym->sccf_sym_type != SCCF_SYM_TYPE_EXTERN;
if (new_is_def && existing_is_ref) {
sccf_sym_t adjusted = *sym;
if (adjusted.sccf_sect_type == SCCF_SECT_CODE) {
adjusted.sccf_sect_offset += ctx->code_base;
} else if (adjusted.sccf_sect_type == SCCF_SECT_DATA) {
adjusted.sccf_sect_offset += ctx->data_base;
}
adjusted.name_offset = existing->name_offset;
*existing = adjusted;
}
}
scc_vec_push(map, global_idx);
}
scc_vec_push(maps, map);
}
// Phase 3: process relocations.
// For each module, for each non-empty relocation:
// - Look up the target symbol in the unified table
// - If the symbol is now resolved (was EXTERN/UNDEF, now GLOBAL),
// patch the merged code in-place
// - If still unresolved, keep the relocation for DLL import resolution
// Build mcode wrapper around merged_code for patching.
// adopt_buf transfers ownership, so merged_code is emptied then refilled by
// disown_buf after patching. The cast is safe: both sccf_sect_data_t and
// scc_mcode_buff_t are SCC_VEC(u8) with identical layout.
scc_mcode_t mcode;
scc_mcode_init(&mcode, SCC_MCODE_ARCH_X86_64);
scc_mcode_adopt_buf(&mcode, (scc_mcode_buff_t *)&merged_code);
scc_vec_foreach(mods, m) {
mod_ctx_t *ctx = &scc_vec_at(mods, m);
idx_map_t *map = &scc_vec_at(maps, m);
for (usize j = 0; j < ctx->reloc_count; j++) {
sccf_reloc_t reloc = ctx->reloc_data[j];
if (reloc.reloc_type == SCCF_RELOC_TYPE_EMPTY)
continue;
Assert(reloc.sym_idx < scc_vec_size(*map));
usize global_idx = scc_vec_at(*map, reloc.sym_idx);
Assert(global_idx < scc_vec_size(builder->symtab));
sccf_sym_t *target = &scc_vec_at(builder->symtab, global_idx);
if (target->sccf_sym_type == SCCF_SYM_TYPE_EXTERN ||
target->sccf_sym_type == SCCF_SYM_TYPE_UNDEF) {
// Still unresolved: keep for DLL import resolution
reloc.sym_idx = global_idx;
sccf_builder_add_reloc(builder, reloc);
} else {
// Resolved: patch code in-place
usize patch_site = reloc.offset + reloc.addend + ctx->code_base;
usize target_off = target->sccf_sect_offset;
scc_x86_patch(&mcode, SCC_X86_PATCH_PC32, patch_site,
target_off);
}
}
}
// Return merged data ownership from mcode back to merged_code
scc_mcode_disown_buf(&mcode, (scc_mcode_buff_t *)&merged_code);
scc_mcode_drop(&mcode);
// Phase 4: add merged sections to builder
if (scc_vec_size(merged_code) > 0) {
sccf_builder_add_text_section(builder, &merged_code);
}
if (scc_vec_size(merged_data) > 0) {
sccf_builder_add_data_section(builder, &merged_data);
}
// Set entry point
sccf_builder_set_entry_symbol_name(builder, linker->entry_symbol_name);
// Cleanup per-module data
scc_vec_foreach(maps, i) {
scc_vec_free(scc_vec_at(maps, i));
}
scc_vec_free(maps);
// mod_ctx entries borrow references — no vec data to free for them
scc_vec_free(mods);
scc_vec_free(merged_code);
scc_vec_free(merged_data);
return sccf_builder_to_sccf(builder);
}

2
libs/sccf/src/sccf_log.c Normal file
View File

@@ -0,0 +1,2 @@
#define __SCCF_LOG_IMPL__
#include <sccf_log.h>