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:
@@ -1,5 +1,7 @@
|
||||
#include <sccf_utils.h>
|
||||
#include <sccf_log.h>
|
||||
|
||||
#include <argparse.h>
|
||||
#include <sccf_utils.h>
|
||||
|
||||
void init_platform(void);
|
||||
|
||||
@@ -20,67 +22,96 @@ typedef struct {
|
||||
|
||||
static const char *arch_name(sccf_enum_t arch) {
|
||||
switch (arch) {
|
||||
case SCCF_ARCH_UNKNOWN: return "UNKNOWN";
|
||||
case SCCF_ARCH_RISCV32: return "RISC-V 32";
|
||||
case SCCF_ARCH_RISCV64: return "RISC-V 64";
|
||||
case SCCF_ARCH_X86: return "x86";
|
||||
case SCCF_ARCH_AMD64: return "AMD64";
|
||||
default: return "UNKNOWN";
|
||||
case SCCF_ARCH_UNKNOWN:
|
||||
return "UNKNOWN";
|
||||
case SCCF_ARCH_RISCV32:
|
||||
return "RISC-V 32";
|
||||
case SCCF_ARCH_RISCV64:
|
||||
return "RISC-V 64";
|
||||
case SCCF_ARCH_X86:
|
||||
return "x86";
|
||||
case SCCF_ARCH_AMD64:
|
||||
return "AMD64";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
static const char *type_name(sccf_enum_t type) {
|
||||
switch (type) {
|
||||
case SCCF_TYPE_FLAG_EXECUTABLE: return "executable";
|
||||
case SCCF_TYPE_FLAG_RELOCATABLE: return "relocatable";
|
||||
case SCCF_TYPE_FLAG_EXE_RELOC: return "exe+reloc";
|
||||
default: return "UNKNOWN";
|
||||
case SCCF_TYPE_FLAG_EXECUTABLE:
|
||||
return "executable";
|
||||
case SCCF_TYPE_FLAG_RELOCATABLE:
|
||||
return "relocatable";
|
||||
case SCCF_TYPE_FLAG_EXE_RELOC:
|
||||
return "exe+reloc";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
static const char *sect_type_name(sccf_enum_t t) {
|
||||
switch (t) {
|
||||
case SCCF_SECT_NONE: return "NONE";
|
||||
case SCCF_SECT_CODE: return "CODE";
|
||||
case SCCF_SECT_DATA: return "DATA";
|
||||
case SCCF_SECT_RODATA: return "RODATA";
|
||||
case SCCF_SECT_UNINIT_DATA: return "BSS";
|
||||
case SCCF_SECT_SYMTAB: return "SYMTAB";
|
||||
case SCCF_SECT_STRTAB: return "STRTAB";
|
||||
case SCCF_SECT_RELOCS: return "RELOCS";
|
||||
default: return "UNKNOWN";
|
||||
case SCCF_SECT_NONE:
|
||||
return "NONE";
|
||||
case SCCF_SECT_CODE:
|
||||
return "CODE";
|
||||
case SCCF_SECT_DATA:
|
||||
return "DATA";
|
||||
case SCCF_SECT_RODATA:
|
||||
return "RODATA";
|
||||
case SCCF_SECT_UNINIT_DATA:
|
||||
return "BSS";
|
||||
case SCCF_SECT_SYMTAB:
|
||||
return "SYMTAB";
|
||||
case SCCF_SECT_STRTAB:
|
||||
return "STRTAB";
|
||||
case SCCF_SECT_RELOCS:
|
||||
return "RELOCS";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
static const char *sym_type_name(sccf_enum_t t) {
|
||||
switch (t) {
|
||||
case SCCF_SYM_TYPE_UNDEF: return "UNDEF";
|
||||
case SCCF_SYM_TYPE_FUNC: return "FUNC";
|
||||
case SCCF_SYM_TYPE_DATA: return "DATA";
|
||||
case SCCF_SYM_TYPE_EXTERN: return "EXTERN";
|
||||
default: return "?";
|
||||
case SCCF_SYM_TYPE_UNDEF:
|
||||
return "UNDEF";
|
||||
case SCCF_SYM_TYPE_FUNC:
|
||||
return "FUNC";
|
||||
case SCCF_SYM_TYPE_DATA:
|
||||
return "DATA";
|
||||
case SCCF_SYM_TYPE_EXTERN:
|
||||
return "EXTERN";
|
||||
default:
|
||||
return "?";
|
||||
}
|
||||
}
|
||||
|
||||
static const char *sym_bind_name(sccf_enum_t b) {
|
||||
switch (b) {
|
||||
case SCCF_SYM_BIND_LOCAL: return "LOCAL";
|
||||
case SCCF_SYM_BIND_GLOBAL: return "GLOBAL";
|
||||
case SCCF_SYM_BIND_WEAK: return "WEAK";
|
||||
default: return "?";
|
||||
case SCCF_SYM_BIND_LOCAL:
|
||||
return "LOCAL";
|
||||
case SCCF_SYM_BIND_GLOBAL:
|
||||
return "GLOBAL";
|
||||
case SCCF_SYM_BIND_WEAK:
|
||||
return "WEAK";
|
||||
default:
|
||||
return "?";
|
||||
}
|
||||
}
|
||||
|
||||
static void dump_header(const sccf_header_t *hdr) {
|
||||
scc_printf("header:\n");
|
||||
scc_printf(" magic: %c%c%c%c%c%c%c%c\n",
|
||||
hdr->magic[0], hdr->magic[1], hdr->magic[2], hdr->magic[3],
|
||||
hdr->magic[4], hdr->magic[5], hdr->magic[6], hdr->magic[7]);
|
||||
scc_printf(" magic: %c%c%c%c%c%c%c%c\n", hdr->magic[0], hdr->magic[1],
|
||||
hdr->magic[2], hdr->magic[3], hdr->magic[4], hdr->magic[5],
|
||||
hdr->magic[6], hdr->magic[7]);
|
||||
scc_printf(" type: %u (%s)\n", hdr->type, type_name(hdr->type));
|
||||
scc_printf(" version: %u\n", hdr->version);
|
||||
scc_printf(" arch: %u (%s)\n", hdr->arch, arch_name(hdr->arch));
|
||||
scc_printf(" entry: 0x%llx\n", (unsigned long long)hdr->entry_point);
|
||||
scc_printf(" sect_count: %llu\n", (unsigned long long)hdr->sect_header_num);
|
||||
scc_printf(" sect_count: %llu\n",
|
||||
(unsigned long long)hdr->sect_header_num);
|
||||
}
|
||||
|
||||
static void dump_sections(u8 *base) {
|
||||
@@ -88,14 +119,14 @@ static void dump_sections(u8 *base) {
|
||||
scc_printf("sections:\n");
|
||||
for (usize i = 0; i < (usize)hdr->sect_header_num; i++) {
|
||||
const sccf_sect_header_t *sh = sccf_sect_header(base, i);
|
||||
if (!sh) break;
|
||||
scc_printf(" [%-2llu] %-8s size=%-8llu data_sz=%-8llu align=%-8llu name=%.8s\n",
|
||||
(unsigned long long)i,
|
||||
sect_type_name(sh->sccf_sect_type),
|
||||
(unsigned long long)sh->size,
|
||||
(unsigned long long)sh->data_size,
|
||||
(unsigned long long)sh->addralign,
|
||||
sh->name);
|
||||
if (!sh)
|
||||
break;
|
||||
scc_printf(" [%-2llu] %-8s size=%-8llu data_sz=%-8llu align=%-8llu "
|
||||
"name=%.8s\n",
|
||||
(unsigned long long)i, sect_type_name(sh->sccf_sect_type),
|
||||
(unsigned long long)sh->size,
|
||||
(unsigned long long)sh->data_size,
|
||||
(unsigned long long)sh->addralign, sh->name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,7 +137,7 @@ static void dump_symbols(u8 *base) {
|
||||
return;
|
||||
}
|
||||
usize str_idx = sccf_find_sect_by_type(base, SCCF_SECT_STRTAB);
|
||||
const char *strtab = NULL;
|
||||
const char *strtab = nullptr;
|
||||
if (str_idx < ((const sccf_header_t *)base)->sect_header_num) {
|
||||
strtab = (const char *)sccf_sect_data(base, str_idx);
|
||||
}
|
||||
@@ -119,12 +150,10 @@ static void dump_symbols(u8 *base) {
|
||||
for (usize i = 0; i < count; i++) {
|
||||
const char *name = strtab ? strtab + syms[i].name_offset : "";
|
||||
scc_printf(" [%-2llu] %-8s %-6s %-8s 0x%-6llx %s\n",
|
||||
(unsigned long long)i,
|
||||
sym_type_name(syms[i].sccf_sym_type),
|
||||
sym_bind_name(syms[i].sccf_sym_bind),
|
||||
sect_type_name(syms[i].sccf_sect_type),
|
||||
(unsigned long long)syms[i].sccf_sect_offset,
|
||||
name);
|
||||
(unsigned long long)i, sym_type_name(syms[i].sccf_sym_type),
|
||||
sym_bind_name(syms[i].sccf_sym_bind),
|
||||
sect_type_name(syms[i].sccf_sect_type),
|
||||
(unsigned long long)syms[i].sccf_sect_offset, name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,16 +166,17 @@ static void dump_relocs(u8 *base) {
|
||||
|
||||
const sccf_sect_header_t *sh = sccf_sect_header(base, reloc_idx);
|
||||
usize count = sh->size / sizeof(sccf_reloc_t);
|
||||
const sccf_reloc_t *relocs = (const sccf_reloc_t *)sccf_sect_data(base, reloc_idx);
|
||||
const sccf_reloc_t *relocs =
|
||||
(const sccf_reloc_t *)sccf_sect_data(base, reloc_idx);
|
||||
|
||||
scc_printf("relocations:\n");
|
||||
for (usize i = 0; i < count; i++) {
|
||||
scc_printf(" [%-2llu] type=%-3u sect=%-8s sym=%-2llu offset=0x%-6llx\n",
|
||||
(unsigned long long)i,
|
||||
relocs[i].reloc_type,
|
||||
sect_type_name(relocs[i].sect_type),
|
||||
(unsigned long long)relocs[i].sym_idx,
|
||||
(unsigned long long)relocs[i].offset);
|
||||
scc_printf(
|
||||
" [%-2llu] type=%-3u sect=%-8s sym=%-2llu offset=0x%-6llx\n",
|
||||
(unsigned long long)i, relocs[i].reloc_type,
|
||||
sect_type_name(relocs[i].sect_type),
|
||||
(unsigned long long)relocs[i].sym_idx,
|
||||
(unsigned long long)relocs[i].offset);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,19 +190,23 @@ static void dump_hex(u8 *base, int verbose) {
|
||||
continue;
|
||||
|
||||
u8 *data = sccf_sect_data(base, i);
|
||||
if (!data || sh->size == 0) continue;
|
||||
if (!data || sh->size == 0)
|
||||
continue;
|
||||
|
||||
scc_printf("section [%-2llu] %.8s (%llu bytes):\n",
|
||||
(unsigned long long)i, sh->name, (unsigned long long)sh->size);
|
||||
(unsigned long long)i, sh->name,
|
||||
(unsigned long long)sh->size);
|
||||
usize limit = verbose ? sh->size : (sh->size > 256 ? 256 : sh->size);
|
||||
for (usize j = 0; j < limit; j++) {
|
||||
if (j % 16 == 0) scc_printf(" %08llx: ", (unsigned long long)j);
|
||||
if (j % 16 == 0)
|
||||
scc_printf(" %08llx: ", (unsigned long long)j);
|
||||
scc_printf("%02x ", data[j]);
|
||||
if ((j + 1) % 16 == 0 || j + 1 == limit) scc_printf("\n");
|
||||
if ((j + 1) % 16 == 0 || j + 1 == limit)
|
||||
scc_printf("\n");
|
||||
}
|
||||
if (limit < sh->size)
|
||||
scc_printf(" ... (%llu more bytes)\n",
|
||||
(unsigned long long)(sh->size - limit));
|
||||
(unsigned long long)(sh->size - limit));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -240,7 +274,8 @@ int main(int argc, const char **argv, const char **envp) {
|
||||
config.get_section_idx = -1;
|
||||
|
||||
scc_argparse_t argparse;
|
||||
scc_argparse_init(&argparse, hints[HINT_PROG_NAME], hints[HINT_DESCRIPTION]);
|
||||
scc_argparse_init(&argparse, hints[HINT_PROG_NAME],
|
||||
hints[HINT_DESCRIPTION]);
|
||||
argparse.lang = lang;
|
||||
|
||||
scc_argparse_cmd_t *root = scc_argparse_get_root(&argparse);
|
||||
@@ -286,13 +321,17 @@ int main(int argc, const char **argv, const char **envp) {
|
||||
scc_argparse_cmd_add_opt(root, &opt_verbose);
|
||||
|
||||
scc_argparse_opt_t opt_get_section;
|
||||
scc_argparse_opt_init(&opt_get_section, 0, "get-section", hints[HINT_GET_SECTION]);
|
||||
scc_argparse_spec_setup_string(&opt_get_section.spec, &config.get_section_name);
|
||||
scc_argparse_opt_init(&opt_get_section, 0, "get-section",
|
||||
hints[HINT_GET_SECTION]);
|
||||
scc_argparse_spec_setup_string(&opt_get_section.spec,
|
||||
&config.get_section_name);
|
||||
scc_argparse_cmd_add_opt(root, &opt_get_section);
|
||||
|
||||
scc_argparse_opt_t opt_get_section_idx;
|
||||
scc_argparse_opt_init(&opt_get_section_idx, 0, "get-section-idx", hints[HINT_GET_SECTION_IDX]);
|
||||
scc_argparse_spec_setup_int(&opt_get_section_idx.spec, &config.get_section_idx);
|
||||
scc_argparse_opt_init(&opt_get_section_idx, 0, "get-section-idx",
|
||||
hints[HINT_GET_SECTION_IDX]);
|
||||
scc_argparse_spec_setup_int(&opt_get_section_idx.spec,
|
||||
&config.get_section_idx);
|
||||
scc_argparse_cmd_add_opt(root, &opt_get_section_idx);
|
||||
|
||||
scc_argparse_arg_t arg_file;
|
||||
@@ -310,14 +349,14 @@ int main(int argc, const char **argv, const char **envp) {
|
||||
|
||||
scc_file_t fp = scc_fopen(config.filepath, SCC_FILE_READ);
|
||||
if (!fp) {
|
||||
LOG_ERROR("cannot open %s", config.filepath);
|
||||
SCC_ERROR((scc_pos_t){0}, "cannot open %s", config.filepath);
|
||||
return 1;
|
||||
}
|
||||
|
||||
usize fsize = scc_fsize(fp);
|
||||
if (fsize < sizeof(sccf_header_t)) {
|
||||
LOG_ERROR("file too small: %s (%llu bytes)", config.filepath,
|
||||
(unsigned long long)fsize);
|
||||
SCC_ERROR((scc_pos_t){0}, "file too small: %s (%llu bytes)",
|
||||
config.filepath, (unsigned long long)fsize);
|
||||
scc_fclose(fp);
|
||||
return 1;
|
||||
}
|
||||
@@ -328,7 +367,7 @@ int main(int argc, const char **argv, const char **envp) {
|
||||
usize nread = scc_fread(fp, scc_vec_unsafe_get_data(buf), fsize);
|
||||
scc_fclose(fp);
|
||||
if (nread != fsize) {
|
||||
LOG_ERROR("short read %s", config.filepath);
|
||||
SCC_ERROR((scc_pos_t){0}, "short read %s", config.filepath);
|
||||
scc_vec_free(buf);
|
||||
return 1;
|
||||
}
|
||||
@@ -347,14 +386,15 @@ int main(int argc, const char **argv, const char **envp) {
|
||||
const sccf_header_t *hdr = (const sccf_header_t *)base;
|
||||
for (usize i = 0; i < (usize)hdr->sect_header_num; i++) {
|
||||
const sccf_sect_header_t *sh = sccf_sect_header(base, i);
|
||||
if (sh && scc_memcmp(sh->name,
|
||||
config.get_section_name, 8) == 0) {
|
||||
if (sh &&
|
||||
scc_memcmp(sh->name, config.get_section_name, 8) == 0) {
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (idx == (usize)-1) {
|
||||
LOG_ERROR("section not found: %s", config.get_section_name);
|
||||
SCC_ERROR((scc_pos_t){0}, "section not found: %s",
|
||||
config.get_section_name);
|
||||
scc_vec_free(buf);
|
||||
return 1;
|
||||
}
|
||||
@@ -362,7 +402,8 @@ int main(int argc, const char **argv, const char **envp) {
|
||||
|
||||
const sccf_sect_header_t *sh = sccf_sect_header(base, idx);
|
||||
if (!sh) {
|
||||
LOG_ERROR("invalid section index: %d", config.get_section_idx);
|
||||
SCC_ERROR((scc_pos_t){0}, "invalid section index: %d",
|
||||
config.get_section_idx);
|
||||
scc_vec_free(buf);
|
||||
return 1;
|
||||
}
|
||||
@@ -377,7 +418,8 @@ int main(int argc, const char **argv, const char **envp) {
|
||||
} else if (config.output) {
|
||||
scc_file_t ofp = scc_fopen(config.output, SCC_FILE_WRITE);
|
||||
if (!ofp) {
|
||||
LOG_ERROR("cannot open output: %s", config.output);
|
||||
SCC_ERROR((scc_pos_t){0}, "cannot open output: %s",
|
||||
config.output);
|
||||
scc_vec_free(buf);
|
||||
return 1;
|
||||
}
|
||||
@@ -398,12 +440,17 @@ int main(int argc, const char **argv, const char **envp) {
|
||||
dump_symbols(base);
|
||||
dump_relocs(base);
|
||||
} else {
|
||||
if (config.dump_header) dump_header(&sccf.header);
|
||||
if (config.dump_sections) dump_sections(base);
|
||||
if (config.dump_symbols) dump_symbols(base);
|
||||
if (config.dump_relocs) dump_relocs(base);
|
||||
if (config.dump_header)
|
||||
dump_header(&sccf.header);
|
||||
if (config.dump_sections)
|
||||
dump_sections(base);
|
||||
if (config.dump_symbols)
|
||||
dump_symbols(base);
|
||||
if (config.dump_relocs)
|
||||
dump_relocs(base);
|
||||
}
|
||||
if (config.dump_hex) dump_hex(base, config.verbose);
|
||||
if (config.dump_hex)
|
||||
dump_hex(base, config.verbose);
|
||||
|
||||
scc_vec_free(buf);
|
||||
return 0;
|
||||
|
||||
25
src/cmd_log.h
Normal file
25
src/cmd_log.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#ifndef __SCC_CMD_LOG_H__
|
||||
#define __SCC_CMD_LOG_H__
|
||||
typedef struct logger logger_t;
|
||||
extern logger_t __scc_cmd_log;
|
||||
extern logger_t __scc_cmd_user;
|
||||
|
||||
#define SCC_LOG_HANDLER &__scc_cmd_user
|
||||
#define LOG_DEFAULT_HANDLER &__scc_cmd_log
|
||||
#include <scc_log.h>
|
||||
|
||||
#ifdef __SCC_CMD_LOG_IMPL__
|
||||
logger_t __scc_cmd_log = {
|
||||
.name = "scc",
|
||||
.level = LOG_LEVEL_ALL,
|
||||
.handler = log_default_handler,
|
||||
};
|
||||
|
||||
logger_t __scc_cmd_user = {
|
||||
.name = "scc",
|
||||
.level = LOG_LEVEL_ALL,
|
||||
.user_handler = scc_log_handler,
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
14
src/config.c
14
src/config.c
@@ -9,6 +9,7 @@ void setup_argparse(scc_argparse_t *argparse, scc_config_t *config,
|
||||
SCC_HINT_INPUT_FILE,
|
||||
SCC_HINT_INCLUDE_PATH,
|
||||
SCC_HINT_DEFINED_MACRO,
|
||||
SCC_HINT_LOG_CONFIG,
|
||||
SCC_HINT_TARGET_DESC,
|
||||
SCC_HINT_VERBOSE,
|
||||
|
||||
@@ -35,6 +36,7 @@ void setup_argparse(scc_argparse_t *argparse, scc_config_t *config,
|
||||
[SCC_HINT_INPUT_FILE] = "Input source file",
|
||||
[SCC_HINT_INCLUDE_PATH] = "Add directory to the include search paths",
|
||||
[SCC_HINT_DEFINED_MACRO] = "Define a macro",
|
||||
[SCC_HINT_LOG_CONFIG] = "Set per-module log level (eg. --log pproc=debug)",
|
||||
[SCC_HINT_TARGET_DESC] =
|
||||
"Target description(eg. x86_64-pc-windows-msvc)",
|
||||
[SCC_HINT_VERBOSE] = "Increase verbosity (can be used multiple times)",
|
||||
@@ -62,6 +64,7 @@ void setup_argparse(scc_argparse_t *argparse, scc_config_t *config,
|
||||
[SCC_HINT_INPUT_FILE] = "输入源文件",
|
||||
[SCC_HINT_INCLUDE_PATH] = "添加系统头文件到搜索路径",
|
||||
[SCC_HINT_DEFINED_MACRO] = "定义宏",
|
||||
[SCC_HINT_LOG_CONFIG] = "设置模块日志级别 (eg. --log pproc=debug)",
|
||||
[SCC_HINT_TARGET_DESC] = "目标机器描述(eg. x86_64-pc-windows-msvc)",
|
||||
[SCC_HINT_VERBOSE] = "增加详细输出(可多次使用)",
|
||||
|
||||
@@ -106,10 +109,10 @@ void setup_argparse(scc_argparse_t *argparse, scc_config_t *config,
|
||||
scc_argparse_spec_setup_string(&opt_output.spec, &(config->output_file));
|
||||
scc_argparse_cmd_add_opt(root, &opt_output);
|
||||
|
||||
// input file (必需)
|
||||
// input file(s) (必需, 支持多个)
|
||||
scc_argparse_arg_t arg_input;
|
||||
scc_argparse_arg_init(&arg_input, "input", scc_hints[SCC_HINT_INPUT_FILE]);
|
||||
scc_argparse_spec_setup_string(&arg_input.spec, &(config->input_file));
|
||||
scc_argparse_spec_setup_list(&arg_input.spec, &(config->input_files));
|
||||
scc_argparse_spec_set_required(&arg_input.spec, true);
|
||||
scc_argparse_cmd_add_arg(root, &arg_input);
|
||||
|
||||
@@ -127,6 +130,13 @@ void setup_argparse(scc_argparse_t *argparse, scc_config_t *config,
|
||||
scc_argparse_spec_setup_list(&opt_define.spec, &(config->define_macros));
|
||||
scc_argparse_cmd_add_opt(root, &opt_define);
|
||||
|
||||
// --log (设置模块日志级别)
|
||||
scc_argparse_opt_t opt_log;
|
||||
scc_argparse_opt_init(&opt_log, 0, "log",
|
||||
scc_hints[SCC_HINT_LOG_CONFIG]);
|
||||
scc_argparse_spec_setup_list(&opt_log.spec, &(config->log_configs));
|
||||
scc_argparse_cmd_add_opt(root, &opt_log);
|
||||
|
||||
// --entry-point-symbol (设置入口点符号名称)
|
||||
scc_argparse_opt_t opt_entry_point_symbol;
|
||||
scc_argparse_opt_init(&opt_entry_point_symbol, 0, "entry-point-symbol",
|
||||
|
||||
@@ -23,12 +23,13 @@ typedef enum scc_emit_stage {
|
||||
} scc_emit_stage_t;
|
||||
|
||||
typedef struct {
|
||||
const char *input_file;
|
||||
scc_argparse_list_t input_files;
|
||||
const char *output_file;
|
||||
const char *target_description;
|
||||
int verbose;
|
||||
scc_argparse_list_t include_paths;
|
||||
scc_argparse_list_t define_macros;
|
||||
scc_argparse_list_t log_configs; /* --log module=level */
|
||||
const char *entry_point_symbol;
|
||||
|
||||
scc_emit_stage_t emit_stage;
|
||||
|
||||
558
src/main.c
558
src/main.c
@@ -1,3 +1,6 @@
|
||||
#define __SCC_CMD_LOG_IMPL__
|
||||
#include "cmd_log.h"
|
||||
|
||||
#include <argparse.h>
|
||||
#include <scc_lexer.h>
|
||||
#include <scc_parser.h>
|
||||
@@ -16,6 +19,7 @@
|
||||
#include <scc_ir2mcode.h>
|
||||
#include <scc_ir2sccf.h>
|
||||
#include <sccf2pe.h>
|
||||
#include <sccf_linker.h>
|
||||
|
||||
#define __SCC_TYPE_ABI_WIN_X64_IMPL__
|
||||
#include <scc_type_abi_win_x64.h>
|
||||
@@ -71,6 +75,7 @@ static void print_file(scc_lexer_tok_ring_t *ring, scc_file_t fp) {
|
||||
static void tree_dump_output(const char *str, usize len, void *user) {
|
||||
scc_fprintf(user, "%.*s", (int)len, str);
|
||||
}
|
||||
|
||||
static inline int mir_dump(scc_file_t fp, scc_mir_module_t *mir_module) {
|
||||
scc_tree_dump_t tree_dump;
|
||||
scc_mir_dump_ctx_t mir_dump_ctx;
|
||||
@@ -87,85 +92,35 @@ static inline int mir_dump(scc_file_t fp, scc_mir_module_t *mir_module) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv, const char **envp) {
|
||||
init_platform();
|
||||
|
||||
#ifndef SCC_DEFAULT_ARGPARSE_LANG
|
||||
#define SCC_DEFAULT_ARGPARSE_LANG SCC_ARGPARSE_LANG_ZH
|
||||
#endif
|
||||
|
||||
scc_argparse_lang_t argparse_lang = SCC_DEFAULT_ARGPARSE_LANG;
|
||||
for (const char **env = envp; *env != nullptr; env++) {
|
||||
const char *env_str = *env;
|
||||
if (scc_strcmp(env_str, "LANG=zh_CN.UTF-8") == 0) {
|
||||
argparse_lang = SCC_ARGPARSE_LANG_ZH;
|
||||
}
|
||||
}
|
||||
|
||||
scc_config_t config = {
|
||||
.input_file = nullptr,
|
||||
.verbose = 0,
|
||||
.output_file = nullptr,
|
||||
.entry_point_symbol = nullptr,
|
||||
.emit_stage = SCC_EMIT_STAGE_DEFAULT,
|
||||
.target_description = "x86_64-pc-windows-msvc",
|
||||
};
|
||||
scc_vec_init(config.include_paths);
|
||||
|
||||
scc_argparse_t argparse;
|
||||
setup_argparse(&argparse, &config, argparse_lang);
|
||||
int ret = scc_argparse_parse(&argparse, argc, argv);
|
||||
if (ret != 0) {
|
||||
scc_argparse_drop(&argparse);
|
||||
return 0;
|
||||
}
|
||||
scc_argparse_drop(&argparse);
|
||||
|
||||
scc_file_t fp = nullptr;
|
||||
if (config.output_file) {
|
||||
cbool is_stdout = scc_strcmp(config.output_file, "-") == 0;
|
||||
if (!is_stdout) {
|
||||
fp = scc_fopen(config.output_file, SCC_FILE_WRITE);
|
||||
if (fp == nullptr) {
|
||||
LOG_FATAL("Failed to open file %s", config.output_file);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
fp = scc_stdout;
|
||||
}
|
||||
}
|
||||
|
||||
// Compile a single source file to an SCCF builder.
|
||||
// Returns 0 on success, non-zero on error.
|
||||
// The caller must keep the builder alive until after linking.
|
||||
static int compile_file_to_sccf(const char *input_file, scc_config_t *config,
|
||||
sccf_builder_t *builder) {
|
||||
int error_code = 0;
|
||||
cbool need_end = false;
|
||||
scc_sstream_t sstream;
|
||||
error_code = scc_sstream_init(&sstream, config.input_file, 1024);
|
||||
error_code = scc_sstream_init(&sstream, input_file, 1024);
|
||||
if (error_code) {
|
||||
goto sstream_drop;
|
||||
need_end = true;
|
||||
return error_code;
|
||||
}
|
||||
|
||||
LOG_INFO("=== phase 1/6: lexing '%s' ===", input_file);
|
||||
scc_lexer_t lexer;
|
||||
scc_lexer_init(&lexer, scc_sstream_to_ring(&sstream));
|
||||
if (config.emit_stage == SCC_EMIT_STAGE_LEX) {
|
||||
scc_lexer_tok_ring_t *tok_ring =
|
||||
scc_lexer_to_ring(&lexer, 8, fp == nullptr ? false : true);
|
||||
if (fp == nullptr) {
|
||||
print_ring(tok_ring, config.verbose);
|
||||
} else {
|
||||
print_file(tok_ring, fp);
|
||||
}
|
||||
scc_lexer_drop_ring(tok_ring);
|
||||
need_end = true;
|
||||
goto lexer_drop;
|
||||
if (config->emit_stage == SCC_EMIT_STAGE_LEX) {
|
||||
// Early-lex is handled per-file at call site
|
||||
scc_lexer_drop(&lexer);
|
||||
scc_sstream_drop(&sstream);
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOG_INFO("=== phase 2/6: preprocessing '%s' ===", input_file);
|
||||
scc_pproc_t pproc;
|
||||
scc_pproc_init(&pproc, scc_lexer_to_ring(&lexer, 8, true));
|
||||
// FIXME maybe using config to got download path and add include path
|
||||
scc_pproc_add_include_path_cstr(&pproc, "./.scc_include");
|
||||
scc_vec_foreach(config.include_paths, i) {
|
||||
scc_vec_foreach(config->include_paths, i) {
|
||||
scc_pproc_add_include_path_cstr(&pproc,
|
||||
scc_vec_at(config.include_paths, i));
|
||||
scc_vec_at(config->include_paths, i));
|
||||
}
|
||||
scc_lexer_tok_vec_t pproc_tok_vec;
|
||||
scc_vec_init(pproc_tok_vec);
|
||||
@@ -191,20 +146,10 @@ int main(int argc, const char **argv, const char **envp) {
|
||||
scc_pproc_add_object_macro(&pproc.macro_table,
|
||||
&pproc_predefined_macros[i], &pproc_tok_vec);
|
||||
}
|
||||
if (config.emit_stage == SCC_EMIT_STAGE_PP) {
|
||||
scc_lexer_tok_ring_t *tok_ring =
|
||||
scc_pproc_to_ring(&pproc, 8, true, true);
|
||||
if (fp == nullptr) {
|
||||
print_ring(tok_ring, config.verbose);
|
||||
} else {
|
||||
print_file(tok_ring, fp);
|
||||
}
|
||||
need_end = true;
|
||||
goto pproc_drop;
|
||||
}
|
||||
|
||||
scc_lexer_tok_ring_t *tok_ring =
|
||||
scc_pproc_to_ring(&pproc, 1024, false, false);
|
||||
LOG_INFO("=== phase 3/6: parsing '%s' ===", input_file);
|
||||
scc_parser_t parser;
|
||||
scc_ast_module_t ast_module;
|
||||
scc_ast_module_init(&ast_module);
|
||||
@@ -214,34 +159,11 @@ int main(int argc, const char **argv, const char **envp) {
|
||||
scc_ast_translation_unit_t *translation_unit =
|
||||
scc_parse_translation_unit(&parser);
|
||||
if (parser.errcode != 0) {
|
||||
return parser.errcode;
|
||||
}
|
||||
|
||||
scc_sema_drop(&sema_ctx);
|
||||
scc_parser_drop(&parser);
|
||||
pproc_drop:
|
||||
scc_pproc_drop(&pproc);
|
||||
lexer_drop:
|
||||
scc_lexer_drop(&lexer);
|
||||
sstream_drop:
|
||||
scc_sstream_drop(&sstream);
|
||||
if (error_code || need_end) {
|
||||
return error_code;
|
||||
}
|
||||
|
||||
if (config.emit_stage == SCC_EMIT_STAGE_AST) {
|
||||
scc_tree_dump_t tree_dump;
|
||||
if (fp == nullptr) {
|
||||
scc_tree_dump_init(&tree_dump, true);
|
||||
} else {
|
||||
scc_tree_dump_init(&tree_dump, false);
|
||||
}
|
||||
scc_ast_dump_node(&tree_dump, (scc_ast_node_t *)translation_unit);
|
||||
scc_tree_dump_flush(&tree_dump, tree_dump_output, GET_VALID_FP(fp));
|
||||
scc_tree_dump_drop(&tree_dump);
|
||||
return 0;
|
||||
error_code = parser.errcode;
|
||||
goto cleanup_pproc;
|
||||
}
|
||||
|
||||
LOG_INFO("=== phase 4/6: AST -> HIR ===");
|
||||
scc_ast2ir_ctx_t ast2ir_ctx;
|
||||
scc_hir_cprog_t cprog;
|
||||
scc_hir_cprog_init(&cprog, &SCC_TYPE_ABI_WIN_X64);
|
||||
@@ -250,112 +172,366 @@ sstream_drop:
|
||||
scc_ast2ir_run(&ast2ir_ctx, translation_unit);
|
||||
scc_ast2ir_ctx_drop(&ast2ir_ctx);
|
||||
|
||||
if (config.emit_stage == SCC_EMIT_STAGE_HIR) {
|
||||
scc_hir_dump_t ir_dump_ctx;
|
||||
scc_tree_dump_t tree_dump;
|
||||
if (fp == nullptr) {
|
||||
scc_tree_dump_init(&tree_dump, true);
|
||||
} else {
|
||||
scc_tree_dump_init(&tree_dump, false);
|
||||
}
|
||||
scc_hir_dump_init(&ir_dump_ctx, &tree_dump, &cprog);
|
||||
// scc_ir_dump_cprog(&ir_dump_ctx);
|
||||
scc_hir_dump_cprog_linear(&ir_dump_ctx);
|
||||
|
||||
scc_tree_dump_flush(&tree_dump, tree_dump_output, GET_VALID_FP(fp));
|
||||
scc_tree_dump_drop(&tree_dump);
|
||||
return 0;
|
||||
}
|
||||
|
||||
LOG_INFO("=== phase 5/6: HIR -> LIR -> MIR ===");
|
||||
// HIR -> LIR
|
||||
scc_lir_module_t lir_module;
|
||||
scc_lir_module_init(&lir_module);
|
||||
scc_hir2lir(&lir_module, &cprog);
|
||||
if (config.emit_stage == SCC_EMIT_STAGE_LIR) {
|
||||
scc_lir_dump_ctx_t lir_dump_ctx;
|
||||
scc_tree_dump_t tree_dump;
|
||||
if (fp == nullptr) {
|
||||
scc_tree_dump_init(&tree_dump, true);
|
||||
} else {
|
||||
scc_tree_dump_init(&tree_dump, false);
|
||||
}
|
||||
scc_lir_dump_init(&lir_dump_ctx, &tree_dump, &lir_module);
|
||||
// scc_ir_dump_cprog(&ir_dump_ctx);
|
||||
scc_lir_dump_module(&lir_dump_ctx);
|
||||
|
||||
scc_tree_dump_flush(&tree_dump, tree_dump_output, GET_VALID_FP(fp));
|
||||
scc_tree_dump_drop(&tree_dump);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// LIR -> MIR
|
||||
scc_mir_module_t mir_module;
|
||||
scc_mir_module_init(&mir_module);
|
||||
scc_lir2mir(&mir_module, &lir_module);
|
||||
|
||||
switch (config.emit_stage) {
|
||||
case SCC_EMIT_STAGE_MIR:
|
||||
return mir_dump(fp, &mir_module);
|
||||
case SCC_EMIT_STAGE_MIR_PASS_REG_ALLOC:
|
||||
scc_mir_pass(&mir_module, SCC_MIR_STAGE_REGALLOC);
|
||||
return mir_dump(fp, &mir_module);
|
||||
case SCC_EMIT_STAGE_MIR_PASS_FLAME_LAYOUT:
|
||||
scc_mir_pass(&mir_module, SCC_MIR_STAGE_FRAME_LAYOUT);
|
||||
return mir_dump(fp, &mir_module);
|
||||
case SCC_EMIT_STAGE_MIR_PASS_PROLOG_EPILOG:
|
||||
scc_mir_pass(&mir_module, SCC_MIR_STAGE_PROLOGUE_EPILOGUE);
|
||||
return mir_dump(fp, &mir_module);
|
||||
default:
|
||||
scc_mir_pass(&mir_module, SCC_MIR_STAGE_ANY);
|
||||
break;
|
||||
// MIR passes
|
||||
scc_mir_pass(&mir_module, SCC_MIR_STAGE_ANY);
|
||||
|
||||
LOG_INFO("=== phase 6/6: MIR -> SCCF ===");
|
||||
// MIR -> SCCF
|
||||
// NOTE: scc_ir2sccf calls sccf_builder_init(builder) internally
|
||||
scc_ir2sccf(builder, &mir_module);
|
||||
|
||||
// Cleanup per-file resources (reverse order)
|
||||
scc_mir_module_drop(&mir_module);
|
||||
scc_lir_module_drop(&lir_module);
|
||||
scc_hir_cprog_drop(&cprog);
|
||||
scc_sema_drop(&sema_ctx);
|
||||
scc_parser_drop(&parser);
|
||||
scc_pproc_drop(&pproc);
|
||||
scc_lexer_drop(&lexer);
|
||||
scc_sstream_drop(&sstream);
|
||||
|
||||
return 0;
|
||||
|
||||
cleanup_pproc:
|
||||
scc_pproc_drop(&pproc);
|
||||
scc_lexer_drop(&lexer);
|
||||
scc_sstream_drop(&sstream);
|
||||
return error_code;
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv, const char **envp) {
|
||||
init_platform();
|
||||
|
||||
#ifndef SCC_DEFAULT_ARGPARSE_LANG
|
||||
#define SCC_DEFAULT_ARGPARSE_LANG SCC_ARGPARSE_LANG_ZH
|
||||
#endif
|
||||
|
||||
scc_argparse_lang_t argparse_lang = SCC_DEFAULT_ARGPARSE_LANG;
|
||||
for (const char **env = envp; *env != nullptr; env++) {
|
||||
const char *env_str = *env;
|
||||
if (scc_strcmp(env_str, "LANG=zh_CN.UTF-8") == 0) {
|
||||
argparse_lang = SCC_ARGPARSE_LANG_ZH;
|
||||
}
|
||||
}
|
||||
|
||||
if (config.emit_stage == SCC_EMIT_STAGE_FLATBIN) {
|
||||
scc_mcode_t mcode = {0};
|
||||
scc_mcode_init(&mcode, SCC_MCODE_ARCH_X86_64);
|
||||
scc_ir2mcode(&mcode, nullptr, &mir_module);
|
||||
if (fp == nullptr) {
|
||||
LOG_WARN("emit flatbin can't write to stdout");
|
||||
scc_config_t config = {
|
||||
.verbose = 0,
|
||||
.output_file = nullptr,
|
||||
.entry_point_symbol = nullptr,
|
||||
.emit_stage = SCC_EMIT_STAGE_DEFAULT,
|
||||
.target_description = "x86_64-pc-windows-msvc",
|
||||
};
|
||||
scc_vec_init(config.input_files);
|
||||
scc_vec_init(config.include_paths);
|
||||
scc_vec_init(config.define_macros);
|
||||
scc_vec_init(config.log_configs);
|
||||
|
||||
scc_argparse_t argparse;
|
||||
setup_argparse(&argparse, &config, argparse_lang);
|
||||
int ret = scc_argparse_parse(&argparse, argc, argv);
|
||||
if (ret != 0) {
|
||||
scc_argparse_drop(&argparse);
|
||||
return 0;
|
||||
}
|
||||
scc_argparse_drop(&argparse);
|
||||
|
||||
// // Apply log configuration from --log and -v
|
||||
// scc_log_set_verbosity(config.verbose);
|
||||
// scc_vec_foreach(config.log_configs, i) {
|
||||
// scc_log_apply_config(scc_vec_at(config.log_configs, i));
|
||||
// }
|
||||
|
||||
usize num_inputs = scc_vec_size(config.input_files);
|
||||
if (num_inputs == 0) {
|
||||
LOG_ERROR("no input files");
|
||||
return 1;
|
||||
}
|
||||
|
||||
scc_file_t fp = nullptr;
|
||||
if (config.output_file) {
|
||||
cbool is_stdout = scc_strcmp(config.output_file, "-") == 0;
|
||||
if (!is_stdout) {
|
||||
fp = scc_fopen(config.output_file, SCC_FILE_WRITE);
|
||||
if (fp == nullptr) {
|
||||
LOG_FATAL("Failed to open file %s", config.output_file);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
fp = scc_stdout;
|
||||
}
|
||||
}
|
||||
|
||||
// Single-file mode: original fast path
|
||||
if (num_inputs == 1) {
|
||||
const char *input_file = scc_vec_at(config.input_files, 0);
|
||||
|
||||
scc_sstream_t sstream;
|
||||
int error_code = scc_sstream_init(&sstream, input_file, 1024);
|
||||
if (error_code) {
|
||||
return error_code;
|
||||
}
|
||||
|
||||
scc_lexer_t lexer;
|
||||
scc_lexer_init(&lexer, scc_sstream_to_ring(&sstream));
|
||||
if (config.emit_stage == SCC_EMIT_STAGE_LEX) {
|
||||
scc_lexer_tok_ring_t *tok_ring =
|
||||
scc_lexer_to_ring(&lexer, 8, fp == nullptr ? false : true);
|
||||
if (fp == nullptr) {
|
||||
print_ring(tok_ring, config.verbose);
|
||||
} else {
|
||||
print_file(tok_ring, fp);
|
||||
}
|
||||
scc_lexer_drop_ring(tok_ring);
|
||||
scc_lexer_drop(&lexer);
|
||||
scc_sstream_drop(&sstream);
|
||||
return 0;
|
||||
}
|
||||
usize mcode_size = scc_mcode_size(&mcode);
|
||||
usize ret = scc_fwrite(fp, scc_mcode_unsafe_data(&mcode), mcode_size);
|
||||
if (ret != mcode_size) {
|
||||
LOG_ERROR("write flatbin failed, write %zu but need write %zu\n",
|
||||
ret, mcode_size);
|
||||
return 1;
|
||||
|
||||
scc_pproc_t pproc;
|
||||
scc_pproc_init(&pproc, scc_lexer_to_ring(&lexer, 8, true));
|
||||
scc_pproc_add_include_path_cstr(&pproc, "./.scc_include");
|
||||
scc_vec_foreach(config.include_paths, i) {
|
||||
scc_pproc_add_include_path_cstr(
|
||||
&pproc, scc_vec_at(config.include_paths, i));
|
||||
}
|
||||
return 0;
|
||||
scc_lexer_tok_vec_t pproc_tok_vec;
|
||||
scc_vec_init(pproc_tok_vec);
|
||||
scc_lexer_tok_t tok = {
|
||||
.lexeme = scc_str_from_cstr("1"),
|
||||
.type = SCC_TOK_INT_LITERAL,
|
||||
.loc.name = "<internal>",
|
||||
.loc.line = 0,
|
||||
.loc.col = 0,
|
||||
.loc.offset = 0,
|
||||
};
|
||||
scc_vec_push(pproc_tok_vec, tok);
|
||||
scc_str_t pproc_predefined_macros[] = {
|
||||
scc_str_from_cstr("__SCC__"),
|
||||
scc_str_from_cstr("_WIN64"),
|
||||
scc_str_from_cstr("_WIN32"),
|
||||
scc_str_from_cstr("__x86_64__"),
|
||||
};
|
||||
for (usize i = 0; i < SCC_ARRLEN(pproc_predefined_macros); i += 1) {
|
||||
scc_vec_init(pproc_tok_vec);
|
||||
scc_lexer_tok_t coped_tok = scc_lexer_tok_copy(&tok);
|
||||
scc_vec_push(pproc_tok_vec, coped_tok);
|
||||
scc_pproc_add_object_macro(&pproc.macro_table,
|
||||
&pproc_predefined_macros[i],
|
||||
&pproc_tok_vec);
|
||||
}
|
||||
if (config.emit_stage == SCC_EMIT_STAGE_PP) {
|
||||
scc_lexer_tok_ring_t *tok_ring =
|
||||
scc_pproc_to_ring(&pproc, 8, true, true);
|
||||
if (fp == nullptr) {
|
||||
print_ring(tok_ring, config.verbose);
|
||||
} else {
|
||||
print_file(tok_ring, fp);
|
||||
}
|
||||
scc_pproc_drop(&pproc);
|
||||
scc_lexer_drop(&lexer);
|
||||
scc_sstream_drop(&sstream);
|
||||
return 0;
|
||||
}
|
||||
|
||||
scc_lexer_tok_ring_t *tok_ring =
|
||||
scc_pproc_to_ring(&pproc, 1024, false, false);
|
||||
scc_parser_t parser;
|
||||
scc_ast_module_t ast_module;
|
||||
scc_ast_module_init(&ast_module);
|
||||
scc_sema_ctx_t sema_ctx;
|
||||
scc_sema_init(&sema_ctx, &ast_module);
|
||||
scc_parser_init(&parser, tok_ring, &ast_module, &sema_ctx);
|
||||
scc_ast_translation_unit_t *translation_unit =
|
||||
scc_parse_translation_unit(&parser);
|
||||
if (parser.errcode != 0) {
|
||||
scc_sema_drop(&sema_ctx);
|
||||
scc_parser_drop(&parser);
|
||||
scc_pproc_drop(&pproc);
|
||||
scc_lexer_drop(&lexer);
|
||||
scc_sstream_drop(&sstream);
|
||||
return parser.errcode;
|
||||
}
|
||||
|
||||
scc_sema_drop(&sema_ctx);
|
||||
scc_parser_drop(&parser);
|
||||
scc_pproc_drop(&pproc);
|
||||
scc_lexer_drop(&lexer);
|
||||
scc_sstream_drop(&sstream);
|
||||
|
||||
if (config.emit_stage == SCC_EMIT_STAGE_AST) {
|
||||
scc_tree_dump_t tree_dump;
|
||||
if (fp == nullptr) {
|
||||
scc_tree_dump_init(&tree_dump, true);
|
||||
} else {
|
||||
scc_tree_dump_init(&tree_dump, false);
|
||||
}
|
||||
scc_ast_dump_node(&tree_dump, (scc_ast_node_t *)translation_unit);
|
||||
scc_tree_dump_flush(&tree_dump, tree_dump_output, GET_VALID_FP(fp));
|
||||
scc_tree_dump_drop(&tree_dump);
|
||||
return 0;
|
||||
}
|
||||
|
||||
scc_ast2ir_ctx_t ast2ir_ctx;
|
||||
scc_hir_cprog_t cprog;
|
||||
scc_hir_cprog_init(&cprog, &SCC_TYPE_ABI_WIN_X64);
|
||||
scc_ast2ir_ctx_init(&ast2ir_ctx, &SCC_TYPE_ABI_WIN_X64, &ast_module,
|
||||
&cprog);
|
||||
scc_ast2ir_run(&ast2ir_ctx, translation_unit);
|
||||
scc_ast2ir_ctx_drop(&ast2ir_ctx);
|
||||
|
||||
if (config.emit_stage == SCC_EMIT_STAGE_HIR) {
|
||||
scc_hir_dump_t ir_dump_ctx;
|
||||
scc_tree_dump_t tree_dump;
|
||||
if (fp == nullptr) {
|
||||
scc_tree_dump_init(&tree_dump, true);
|
||||
} else {
|
||||
scc_tree_dump_init(&tree_dump, false);
|
||||
}
|
||||
scc_hir_dump_init(&ir_dump_ctx, &tree_dump, &cprog);
|
||||
scc_hir_dump_cprog_linear(&ir_dump_ctx);
|
||||
|
||||
scc_tree_dump_flush(&tree_dump, tree_dump_output, GET_VALID_FP(fp));
|
||||
scc_tree_dump_drop(&tree_dump);
|
||||
return 0;
|
||||
}
|
||||
|
||||
scc_lir_module_t lir_module;
|
||||
scc_lir_module_init(&lir_module);
|
||||
scc_hir2lir(&lir_module, &cprog);
|
||||
if (config.emit_stage == SCC_EMIT_STAGE_LIR) {
|
||||
scc_lir_dump_ctx_t lir_dump_ctx;
|
||||
scc_tree_dump_t tree_dump;
|
||||
if (fp == nullptr) {
|
||||
scc_tree_dump_init(&tree_dump, true);
|
||||
} else {
|
||||
scc_tree_dump_init(&tree_dump, false);
|
||||
}
|
||||
scc_lir_dump_init(&lir_dump_ctx, &tree_dump, &lir_module);
|
||||
scc_lir_dump_module(&lir_dump_ctx);
|
||||
|
||||
scc_tree_dump_flush(&tree_dump, tree_dump_output, GET_VALID_FP(fp));
|
||||
scc_tree_dump_drop(&tree_dump);
|
||||
return 0;
|
||||
}
|
||||
|
||||
scc_mir_module_t mir_module;
|
||||
scc_mir_module_init(&mir_module);
|
||||
scc_lir2mir(&mir_module, &lir_module);
|
||||
|
||||
switch (config.emit_stage) {
|
||||
case SCC_EMIT_STAGE_MIR:
|
||||
return mir_dump(fp, &mir_module);
|
||||
case SCC_EMIT_STAGE_MIR_PASS_REG_ALLOC:
|
||||
scc_mir_pass(&mir_module, SCC_MIR_STAGE_REGALLOC);
|
||||
return mir_dump(fp, &mir_module);
|
||||
case SCC_EMIT_STAGE_MIR_PASS_FLAME_LAYOUT:
|
||||
scc_mir_pass(&mir_module, SCC_MIR_STAGE_FRAME_LAYOUT);
|
||||
return mir_dump(fp, &mir_module);
|
||||
case SCC_EMIT_STAGE_MIR_PASS_PROLOG_EPILOG:
|
||||
scc_mir_pass(&mir_module, SCC_MIR_STAGE_PROLOGUE_EPILOGUE);
|
||||
return mir_dump(fp, &mir_module);
|
||||
default:
|
||||
scc_mir_pass(&mir_module, SCC_MIR_STAGE_ANY);
|
||||
break;
|
||||
}
|
||||
|
||||
if (config.emit_stage == SCC_EMIT_STAGE_FLATBIN) {
|
||||
scc_mcode_t mcode = {0};
|
||||
scc_mcode_init(&mcode, SCC_MCODE_ARCH_X86_64);
|
||||
scc_ir2mcode(&mcode, nullptr, &mir_module);
|
||||
if (fp == nullptr) {
|
||||
LOG_WARN("emit flatbin can't write to stdout");
|
||||
return 0;
|
||||
}
|
||||
usize mcode_size = scc_mcode_size(&mcode);
|
||||
usize fwritten =
|
||||
scc_fwrite(fp, scc_mcode_unsafe_data(&mcode), mcode_size);
|
||||
if (fwritten != mcode_size) {
|
||||
LOG_ERROR("write flatbin failed, write %zu but need %zu",
|
||||
fwritten, mcode_size);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Single-file: compile to SCCF then directly to PE
|
||||
sccf_builder_t sccf_builder = {0};
|
||||
scc_ir2sccf(&sccf_builder, &mir_module);
|
||||
sccf_builder_set_entry_symbol_name(&sccf_builder,
|
||||
config.entry_point_symbol);
|
||||
const sccf_t *sccf = sccf_builder_to_sccf(&sccf_builder);
|
||||
if (config.emit_stage == SCC_EMIT_STAGE_SCCF) {
|
||||
if (fp == nullptr) {
|
||||
scc_printf("output exe at %s\n", config.output_file);
|
||||
} else {
|
||||
sccf_builder_to_file(&sccf_builder, config.output_file);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (config.emit_stage == SCC_EMIT_STAGE_DEFAULT ||
|
||||
config.emit_stage == SCC_EMIT_STAGE_TARGET) {
|
||||
scc_pe_builder_t pe_builder;
|
||||
sccf2pe(&pe_builder, sccf);
|
||||
if (fp == nullptr) {
|
||||
scc_printf("output exe at %s\n", config.output_file);
|
||||
} else {
|
||||
scc_pe_dump_to_file(&pe_builder, config.output_file);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Panic("unknown emit stage");
|
||||
return 1;
|
||||
}
|
||||
|
||||
sccf_builder_t sccf_builder = {0};
|
||||
sccf_builder_init(&sccf_builder);
|
||||
scc_ir2sccf(&sccf_builder, &mir_module);
|
||||
sccf_builder_set_entry_symbol_name(&sccf_builder,
|
||||
config.entry_point_symbol);
|
||||
const sccf_t *sccf = sccf_builder_to_sccf(&sccf_builder);
|
||||
if (config.emit_stage == SCC_EMIT_STAGE_SCCF) {
|
||||
// sccf_buffer_t buffer;
|
||||
// scc_vec_init(buffer);
|
||||
// sccf_builder_to_buffer(&sccf_builder, &buffer);
|
||||
if (fp == nullptr) {
|
||||
scc_printf("output exe at %s\n", config.output_file);
|
||||
} else {
|
||||
sccf_builder_to_file(&sccf_builder, config.output_file);
|
||||
}
|
||||
return 0;
|
||||
// Multi-file mode (num_inputs > 1)
|
||||
if (config.emit_stage != SCC_EMIT_STAGE_DEFAULT) {
|
||||
LOG_ERROR("--emit is not supported with multiple input files");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (config.emit_stage == SCC_EMIT_STAGE_DEFAULT ||
|
||||
config.emit_stage == SCC_EMIT_STAGE_TARGET) {
|
||||
scc_pe_builder_t pe_builder;
|
||||
sccf2pe(&pe_builder, sccf);
|
||||
if (fp == nullptr) {
|
||||
scc_printf("output exe at %s\n", config.output_file);
|
||||
} else {
|
||||
scc_pe_dump_to_file(&pe_builder, config.output_file);
|
||||
// First pass: compile each file to SCCF
|
||||
sccf_linker_t linker;
|
||||
sccf_linker_init(&linker);
|
||||
sccf_linker_set_entry_symbol_name(&linker, config.entry_point_symbol);
|
||||
|
||||
scc_vec_foreach(config.input_files, i) {
|
||||
const char *input = scc_vec_at(config.input_files, i);
|
||||
sccf_builder_t builder = {0};
|
||||
|
||||
int err = compile_file_to_sccf(input, &config, &builder);
|
||||
if (err != 0) {
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
|
||||
// Transfer this file's SCCF to the linker.
|
||||
// The builder data stays alive on the heap; the linker stores a shallow
|
||||
// copy. We must NOT drop/free the builder while the linker references
|
||||
// it.
|
||||
sccf_linker_add_sccf(&linker, sccf_builder_to_sccf(&builder));
|
||||
}
|
||||
|
||||
Panic("unknown emit stage");
|
||||
return 1;
|
||||
// Second pass: link all SCCF modules and emit PE
|
||||
const sccf_t *linked = sccf_linker_link(&linker);
|
||||
scc_pe_builder_t pe_builder;
|
||||
sccf2pe(&pe_builder, linked);
|
||||
if (fp == nullptr) {
|
||||
scc_printf("output exe at %s\n", config.output_file);
|
||||
} else {
|
||||
scc_pe_dump_to_file(&pe_builder, config.output_file);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user