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:
@@ -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" },
|
||||
]
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
26
libs/sccf/include/sccf_log.h
Normal file
26
libs/sccf/include/sccf_log.h
Normal 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
|
||||
@@ -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
259
libs/sccf/src/sccf_linker.c
Normal 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
2
libs/sccf/src/sccf_log.c
Normal file
@@ -0,0 +1,2 @@
|
||||
#define __SCCF_LOG_IMPL__
|
||||
#include <sccf_log.h>
|
||||
Reference in New Issue
Block a user