Files
scc/libs/target/sccf2target/src/sccf2pe.c
zzy 8b817da3b6 feat(ast): 将AST上下文重构为模块并添加字符串池支持
- 将scc_ast_ctx重命名为scc_ast_module以更好地反映其功能
- 添加scc_strpool_t用于统一管理AST节点名称字符串的生命周期
- 实现scc_ast_module_intern函数用于字符串驻留
- 更新所有相关的初始化、销毁和访问函数命名
- 修改内存分配宏以使用新的模块结构

refactor(parser): 更新解析器以使用AST模块和字符串池

- 将解析器中的ast_ctx字段替换为ast_module
- 在创建AST节点时使用新的ast_module参数
- 使用scc_ast_module_intern函数处理标识符和字符串字面量
- 确保所有字符串都被正确驻留到模块的字符串池中

refactor(sema): 更新语义分析器使用AST模块

- 将sema_ctx中的ast_ctx字段替换为ast_module
- 更新语义分析器初始化函数参数

refactor(ast2ir): 更新AST到IR转换器使用AST模块

- 将ast_ctx字段替换为ast_module
- 更新上下文初始化函数参数和实现

fix(cfg): 修复CFG模块中的符号查找错误

- 修正scc_cfg_module_unsafe_get_symbol函数中的边界检查条件

perf(ir): 完善各IR层模块的内存清理机制

- 为HIR模块添加函数和基本块元数据的释放逻辑
- 为MIR和LIR模块完善完整的资源清理和内存释放
- 确保所有分配的元数据结构都能被正确释放

chore(deps): 添加scc_utils依赖到AST库

- 在libs/ast/cbuild.toml中添加对scc_utils的依赖
2026-05-31 19:56:19 +08:00

271 lines
9.5 KiB
C

#include <scc_pe_idata.h>
#include <sccf2pe.h>
#include <sccf_utils.h>
#include <x86/scc_x86_patch.h>
typedef struct {
scc_hashtable_t str2libsym;
scc_pe_idata_lib_vec_t idata_libs;
scc_strpool_t pool; /* owns all interned symbol names and library names */
const char *find_path;
} pe_idata_lib_ctx_t;
static void load_from_def(pe_idata_lib_ctx_t *ctx, const char *file_path,
const char *dll_name) {
/*
LIBRARY <path name>
EXPORTS
name @number
...
*/
scc_str_t fpath = scc_str_from_cstr(file_path);
scc_str_append_ch(&fpath, '/');
scc_str_append_cstr(&fpath, dll_name, scc_strlen(dll_name));
scc_str_append_cstr(&fpath, ".def", 4);
const char *fname = scc_str_as_cstr(&fpath);
scc_file_t fp = scc_fopen(fname, SCC_FILE_READ);
if (fp == nullptr) {
scc_str_drop(&fpath);
return;
}
LOG_TRACE("load_from_def file read sucessful: %s", fname);
usize fsize = scc_fsize(fp);
if (fsize == 0) {
scc_fclose(fp);
scc_str_drop(&fpath);
return;
}
char *buffer = scc_malloc(fsize);
Assert(buffer != nullptr);
usize read_size = scc_fread(fp, buffer, fsize);
Assert(read_size == fsize);
scc_fclose(fp);
usize line = 0;
buffer[fsize - 1] = '\0';
const char *dll_pooled = scc_strpool_intern(&ctx->pool, dll_name);
for (usize i = 0; i < fsize; i += 1) {
if (buffer[i] == '\n') {
line += 1;
}
if (line < 2) {
continue;
}
if (buffer[i] == ' ') {
continue;
}
for (usize j = i; j < fsize; j += 1) {
if (buffer[j] == ' ') {
buffer[j] = '\0';
break;
}
}
const char *sym_pooled = scc_strpool_intern(&ctx->pool, buffer + i);
scc_hashtable_set(&ctx->str2libsym, sym_pooled, (void *)dll_pooled);
}
scc_free(buffer);
scc_str_drop(&fpath);
}
static void pe_idata_lib_init(pe_idata_lib_ctx_t *ctx, const char *find_path) {
// Got .dll.def
scc_hashtable_cstr_init(&ctx->str2libsym);
scc_strpool_init(&ctx->pool);
scc_vec_init(ctx->idata_libs);
ctx->find_path = find_path;
load_from_def(ctx, ctx->find_path, "msvcrt.dll");
}
static cbool pe_idata_get(pe_idata_lib_ctx_t *ctx, const char *name) {
const char *lib_name = scc_hashtable_get(&ctx->str2libsym, name);
if (lib_name == nullptr) {
return false;
}
scc_pe_idata_lib_t *lib = nullptr;
scc_vec_foreach(ctx->idata_libs, i) {
scc_pe_idata_lib_t *idata_lib = &scc_vec_at(ctx->idata_libs, i);
if (scc_strcmp(lib_name, idata_lib->name) == 0) {
lib = idata_lib;
break;
}
}
if (lib == nullptr) {
scc_pe_idata_lib_t new_lib;
new_lib.name = lib_name;
scc_vec_init(new_lib.symbol_names);
scc_vec_push(ctx->idata_libs, new_lib);
lib = &scc_vec_at(ctx->idata_libs, scc_vec_size(ctx->idata_libs) - 1);
}
scc_vec_push(lib->symbol_names, name);
return true;
}
void sccf2pe(scc_pe_builder_t *builder, const sccf_t *sccf) {
scc_pe_builder_init(builder, true, 4096, 512);
sccf_strtab_t strtab;
scc_vec_init(strtab);
sccf_reloc_vec_t relocs;
scc_vec_init(relocs);
sccf_sym_vec_t symtab;
scc_vec_init(symtab);
sccf_sect_data_t *code_data = nullptr;
sccf_sect_data_t *data_data = nullptr;
int num_of_section = 1;
scc_vec_foreach(sccf->sect_headers, i) {
sccf_sect_header_t *sect_header = &scc_vec_at(sccf->sect_headers, i);
sccf_sect_data_t *sect_data = &scc_vec_at(sccf->sect_datas, i);
if (sect_header->sccf_sect_type == SCCF_SECT_CODE) {
if (scc_vec_size(*sect_data) != 0) {
code_data = sect_data;
num_of_section += 1;
}
} else if (sect_header->sccf_sect_type == SCCF_SECT_DATA) {
if (scc_vec_size(*sect_data) != 0) {
data_data = sect_data;
num_of_section += 1;
}
} else if (sect_header->sccf_sect_type == SCCF_SECT_STRTAB) {
scc_vec_unsafe_from_buffer(
strtab, (char *)scc_vec_unsafe_get_data(*sect_data),
scc_vec_size(*sect_data));
} else if (sect_header->sccf_sect_type == SCCF_SECT_RELOCS) {
scc_vec_unsafe_from_buffer(
relocs, (sccf_reloc_t *)scc_vec_unsafe_get_data(*sect_data),
scc_vec_size(*sect_data));
} else if (sect_header->sccf_sect_type == SCCF_SECT_SYMTAB) {
scc_vec_unsafe_from_buffer(
symtab, (sccf_sym_t *)scc_vec_unsafe_get_data(*sect_data),
scc_vec_size(*sect_data));
}
}
scc_pe_reserve_header(builder, num_of_section);
scc_pe_section_range code_range = {0};
scc_pe_section_range data_range = {0};
scc_pe_section_range idata_range = {0};
if (code_data) {
code_range = scc_pe_reserve_text_section_header(
builder, scc_vec_size(*code_data));
}
if (data_data) {
data_range = scc_pe_reserve_data_section_header(
builder, scc_vec_size(*data_data));
}
pe_idata_lib_ctx_t idata_lib_ctx;
pe_idata_lib_init(&idata_lib_ctx, "./.scc_dll");
scc_vec_foreach(symtab, i) {
sccf_sym_t *sym = &scc_vec_at(symtab, i);
if (sym->sccf_sym_type == SCCF_SYM_TYPE_EXTERN) {
const char *name =
(const char *)&scc_vec_at(strtab, sym->name_offset);
if (pe_idata_get(&idata_lib_ctx, name) == false) {
LOG_ERROR("link error: symbol [%s] not found", name);
}
}
}
scc_pe_idata_builder_t idata_builder;
scc_pe_idata_builder_init(&idata_builder, &idata_lib_ctx.idata_libs);
u32 idata_size = scc_pe_reserve_idata(&idata_builder);
idata_range = scc_pe_reserve_idata_section_header(builder, idata_size);
scc_pe_buffer_t idata_buffer =
scc_pe_construct_idata(&idata_builder, &idata_range);
u32 entry_point_offset = sccf->header.entry_point;
Assert(code_data != nullptr &&
entry_point_offset < scc_vec_size(*code_data));
u64 base_address = 0x140000000;
u32 entry_point = code_range.virual_address + entry_point_offset;
scc_pe_config_t config = (scc_pe_config_t){
.machine = IMAGE_FILE_MACHINE_AMD64,
.time_date_stamp = 0,
.characteristics =
IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_LARGE_ADDRESS_AWARE,
.major_linker_version = 14,
.minor_linker_version = 0,
.address_of_entry_point = entry_point,
.image_base = base_address,
.major_operating_system_version = 6,
.minor_operating_system_version = 0,
.major_image_version = 0,
.minor_image_version = 0,
.major_subsystem_version = 6,
.minor_subsystem_version = 0,
.subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI,
.dll_characteristics = IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA |
IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE |
IMAGE_DLLCHARACTERISTICS_NX_COMPAT,
.size_of_stack_reserve = 0x100000,
.size_of_stack_commit = 0x1000,
.size_of_heap_reserve = 0x100000,
.size_of_heap_commit = 0x1000,
};
scc_mcode_t mcode;
scc_mcode_init(&mcode, SCC_MCODE_ARCH_X86_64);
// FIXME hack
mcode.code = *(scc_mcode_buff_t *)code_data;
scc_vec_foreach(relocs, i) {
sccf_reloc_t *reloc = &scc_vec_at(relocs, i);
if (reloc->reloc_type == SCCF_RELOC_TYPE_EMPTY) {
continue;
}
Assert(reloc->sect_type == SCCF_SECT_CODE);
sccf_sym_t *sym = &scc_vec_at(symtab, reloc->sym_idx);
const char *name = &scc_vec_at(strtab, sym->name_offset);
u32 rva = 0;
if (sym->sccf_sym_type == SCCF_SYM_TYPE_EXTERN) {
rva = scc_pe_idata_get_symbol_rva(&idata_builder, name);
} else if (sym->sccf_sect_type == SCCF_SECT_DATA) {
rva = data_range.virual_address + sym->sccf_sect_offset;
} else if (sym->sccf_sect_type == SCCF_SECT_CODE) {
rva = code_range.virual_address + sym->sccf_sect_offset;
} else {
Panic("unsupported reloc symbol type");
}
Assert(rva != 0);
Assert(code_data != nullptr);
// FIXME patch type
// if (reloc->reloc_type == SCCF_RELOC_TYPE_ABS) {
// TODO();
// }
scc_x86_patch(&mcode, SCC_X86_PATCH_PC32, reloc->offset + reloc->addend,
(i64)rva - (i64)code_range.virual_address);
}
*(scc_mcode_buff_t *)code_data = mcode.code;
scc_pe_write_header(builder, &config);
if (code_data != nullptr) {
scc_pe_write_section(builder, &code_range,
(u8 *)scc_vec_unsafe_get_data(*code_data),
scc_vec_size(*code_data));
}
if (data_data != nullptr) {
scc_pe_write_section(builder, &data_range,
(u8 *)scc_vec_unsafe_get_data(*data_data),
scc_vec_size(*data_data));
}
scc_pe_write_section(builder, &idata_range,
scc_vec_unsafe_get_data(idata_buffer),
scc_vec_size(idata_buffer));
// Cleanup
scc_vec_foreach(idata_lib_ctx.idata_libs, i) {
scc_vec_free(scc_vec_at(idata_lib_ctx.idata_libs, i).symbol_names);
}
scc_vec_free(idata_lib_ctx.idata_libs);
scc_hashtable_drop(&idata_lib_ctx.str2libsym);
scc_strpool_drop(&idata_lib_ctx.pool);
}