From 41d060d7e775030c99861aa4ea94bd86c89e7c6e Mon Sep 17 00:00:00 2001 From: zzy <2450266535@qq.com> Date: Thu, 21 May 2026 16:19:49 +0800 Subject: [PATCH] =?UTF-8?q?feat(lir):=20=E4=BF=AE=E6=94=B9HIR=E5=88=B0LIR?= =?UTF-8?q?=E8=BD=AC=E6=8D=A2=E4=BB=A5=E6=94=AF=E6=8C=81=E5=8F=AF=E5=8F=98?= =?UTF-8?q?=E5=8F=82=E6=95=B0=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 移除SCC_LIR_LEA指令类型,改用SCC_LIR_LOAD_ADDR - 在scc_lir_func_meta_t中添加is_va_arg字段用于标识可变参数函数 - 修改scc_hir2lir函数参数类型,移除const限定符 - 更新比较操作的指令映射逻辑,将条件信息存储在metadata中 - 调整代码结构,在各个switch case分支中统一使用"} break"格式 fix(x86-isel): 修复x86指令选择中的立即数和重定位处理 - 修改emit_direct_call函数以正确处理全局符号重定位 - 更新立即数字段访问从imm到imm0 - 添加新的重定位操作数类型SCC_X86_OPR_RELOC - 实现重定位目标类型的完整处理逻辑,包括基本块和符号 refactor(x86-mir): 重构x86操作数结构以支持重定位机制 - 将内存操作数的disp字段改为结构体形式包含displacement信息 - 移除不再使用的常用操作数构造器函数 - 保留并完善slot操作数构造器 - 更新内存操作数的调试输出格式 feat(ir2mcode): 添加重定位表支持以处理符号引用 - 定义新的重定位结构体scc_reloc_t用于记录重定位信息 - 修改scc_ir2mcode_emit_instr函数签名以传递重定位表 - 实现重定位补丁应用功能scc_ir2mcode_patch - 更新机器码生成流程以收集和处理重定位信息 refactor(ir2sccf): 重构SCEF文件生成以支持重定位处理 - 提取独立的emit_mir_module函数处理MIR模块的机器码生成 - 实现基本块间重定位的地址解析和补丁应用 - 改进符号重定位的处理机制 - 简化机器码段数据的最终处理流程 --- libs/ir/lir/include/scc_hir2lir.h | 2 +- libs/ir/lir/include/scc_lir.h | 2 +- libs/ir/lir/src/scc_hir2lir.c | 54 ++++----- libs/ir/lir/src/scc_lir_dump.c | 6 +- libs/ir/mir/include/arch/scc_x86_isel.h | 6 +- libs/ir/mir/include/arch/scc_x86_mir.h | 56 ++------- libs/ir/mir/src/arch/scc_x86_isel.c | 76 +++++++----- libs/ir/mir/src/target/win64_abi.c | 9 +- libs/ir2mcode/include/scc_ir2mcode.h | 25 +++- libs/ir2mcode/src/scc_ir2mcode.c | 77 ++++++++++-- libs/ir2mcode/src/scc_ir2sccf.c | 130 +++++++++++++------- libs/mcode/.gitignore | 2 + libs/mcode/include/x86/scc_x86_encode.h | 101 +++++++++++++++- libs/mcode/include/x86/scc_x86_patch.h | 137 ++++++++++++++++++++++ libs/mcode/src/scc_x86_encode.c | 115 +++++++++++------- libs/sccf/include/sccf.h | 3 +- libs/target/sccf2target/include/sccf2pe.h | 5 + libs/target/sccf2target/src/sccf2pe.c | 19 ++- src/main.c | 10 +- 19 files changed, 608 insertions(+), 227 deletions(-) create mode 100644 libs/mcode/.gitignore create mode 100644 libs/mcode/include/x86/scc_x86_patch.h diff --git a/libs/ir/lir/include/scc_hir2lir.h b/libs/ir/lir/include/scc_hir2lir.h index 2c3f6a0..d652576 100644 --- a/libs/ir/lir/include/scc_hir2lir.h +++ b/libs/ir/lir/include/scc_hir2lir.h @@ -5,6 +5,6 @@ #include "scc_lir_module.h" #include -void scc_hir2lir(scc_lir_module_t *module, const scc_hir_cprog_t *cprog); +void scc_hir2lir(scc_lir_module_t *module, scc_hir_cprog_t *cprog); #endif /* __SCC_IR2LIR_H__ */ diff --git a/libs/ir/lir/include/scc_lir.h b/libs/ir/lir/include/scc_lir.h index 9751f4a..d119bab 100644 --- a/libs/ir/lir/include/scc_lir.h +++ b/libs/ir/lir/include/scc_lir.h @@ -98,7 +98,6 @@ typedef enum { SCC_LIR_LOAD_ADDR, SCC_LIR_STORE, SCC_LIR_STORE_ADDR, - SCC_LIR_LEA, /* 整数算术 */ SCC_LIR_ADD, @@ -253,6 +252,7 @@ typedef scc_cfg_func_t scc_lir_func_t; typedef struct scc_lir_func_meta { int vregs_count; int frame_size; + int is_va_arg; scc_lir_attr_t attr; } scc_lir_func_meta_t; #define SCC_LIR_FUNC_META(func) ((scc_lir_func_meta_t *)(func)->meta) diff --git a/libs/ir/lir/src/scc_hir2lir.c b/libs/ir/lir/src/scc_hir2lir.c index 817216c..1a0d0d0 100644 --- a/libs/ir/lir/src/scc_hir2lir.c +++ b/libs/ir/lir/src/scc_hir2lir.c @@ -234,7 +234,7 @@ static scc_lir_op_t map_binop(scc_hir_op_type_t op, cbool is_float) { case SCC_HIR_OP_SAR: return SCC_LIR_SAR; default: - return map_cmp_cond(op, is_float); + return SCC_LIR_CMP; } } return SCC_LIR_NOP; @@ -263,15 +263,19 @@ static void translate_hir_value(ir2lir_ctx_t *ctx, scc_hir_value_t *value, scc_lir_val_t rhs = ir_value_to_lir_operand(ctx, value->data.op.rhs); scc_lir_op_t op = map_binop(value->data.op.op, is_float); - scc_lir_instr_t instr = {.op = op, - .size = size, - .ext = ext, - .to = SCC_LIR_VREG(dst_vreg), - .arg0 = lhs, - .arg1 = rhs}; + scc_lir_instr_t instr = { + .op = op, + .size = size, + .ext = ext, + .to = SCC_LIR_VREG(dst_vreg), + .arg0 = lhs, + .arg1 = rhs, + }; + if (op == SCC_LIR_CMP) { + instr.metadata.cond = map_cmp_cond(value->data.op.op, is_float); + } scc_lir_builder_add_instr(ctx, &instr); - break; - } + } break; case SCC_HIR_VALUE_TAG_LOAD: { scc_lir_val_t addr = ir_value_to_lir_operand(ctx, value->data.load.target); @@ -281,8 +285,7 @@ static void translate_hir_value(ir2lir_ctx_t *ctx, scc_hir_value_t *value, .to = SCC_LIR_VREG(dst_vreg), .arg0 = addr}; scc_lir_builder_add_instr(ctx, &instr); - break; - } + } break; case SCC_HIR_VALUE_TAG_STORE: { scc_lir_val_t data = ir_value_to_lir_operand(ctx, value->data.store.value); @@ -291,8 +294,7 @@ static void translate_hir_value(ir2lir_ctx_t *ctx, scc_hir_value_t *value, scc_lir_instr_t instr = { .op = SCC_LIR_STORE, .size = size, .arg0 = data, .arg1 = addr}; scc_lir_builder_add_instr(ctx, &instr); - break; - } + } break; case SCC_HIR_VALUE_TAG_GET_ELEM_PTR: { // 将指针运算转换为 LEA scc_lir_val_t base = @@ -333,15 +335,14 @@ static void translate_hir_value(ir2lir_ctx_t *ctx, scc_hir_value_t *value, scc_lir_val_t addr = SCC_LIR_ADDR(dst_vreg, -1, index.data.reg, elem_size); // 更简单的做法:使用 LEA 指令,参数为 base 和 index,由后端展开 - scc_lir_instr_t instr = {.op = SCC_LIR_LEA, + scc_lir_instr_t instr = {.op = SCC_LIR_LOAD_ADDR, .size = SCC_LIR_SIZE_64, .to = SCC_LIR_VREG(dst_vreg), .arg0 = base, .arg1 = index}; // 实际需要将 index * elem_size 的信息编码,这里简化,假设后端处理 scc_lir_builder_add_instr(ctx, &instr); - break; - } + } break; case SCC_HIR_VALUE_TAG_ALLOC: { // alloca 指令:分配栈空间 scc_hir_type_t *alloc_ty = @@ -355,8 +356,7 @@ static void translate_hir_value(ir2lir_ctx_t *ctx, scc_hir_value_t *value, .to = SCC_LIR_VREG(dst_vreg), .metadata.alloca = {alloc_size, alloc_size}}; scc_lir_builder_add_instr(ctx, &instr); - break; - } + } break; case SCC_HIR_VALUE_TAG_CALL: { scc_hir_func_t *callee = scc_hir_module_get_func( ctx->hir_module, value->data.call.callee.func_ref); @@ -381,8 +381,7 @@ static void translate_hir_value(ir2lir_ctx_t *ctx, scc_hir_value_t *value, // metadata.call.args 指针仍指向 malloc 内存, // 这会导致内存泄漏。实际实现中应使用 arena // 分配或随函数释放。此处为示例简化。 - break; - } + } break; case SCC_HIR_VALUE_TAG_BRANCH: { scc_lir_val_t cond = ir_value_to_lir_operand(ctx, value->data.branch.cond); @@ -392,15 +391,13 @@ static void translate_hir_value(ir2lir_ctx_t *ctx, scc_hir_value_t *value, .metadata.br = {value->data.branch.true_bblock, value->data.branch.false_bblock}}; scc_lir_builder_add_instr(ctx, &instr); - break; - } + } break; case SCC_HIR_VALUE_TAG_JUMP: { scc_lir_instr_t instr = {.op = SCC_LIR_JMP, .metadata.jmp_target = value->data.jump.target_bblock}; scc_lir_builder_add_instr(ctx, &instr); - break; - } + } break; case SCC_HIR_VALUE_TAG_RET: { scc_lir_val_t ret_val; if (value->data.ret.ret_val != SCC_HIR_REF_nullptr) { @@ -411,8 +408,7 @@ static void translate_hir_value(ir2lir_ctx_t *ctx, scc_hir_value_t *value, scc_lir_instr_t instr = {.op = SCC_LIR_RET, .metadata.ret_val = ret_val}; scc_lir_builder_add_instr(ctx, &instr); - break; - } + } break; case SCC_HIR_VALUE_TAG_CONV: { // 类型转换:使用 MOV 指令配合扩展/截断 scc_lir_val_t src = @@ -429,8 +425,7 @@ static void translate_hir_value(ir2lir_ctx_t *ctx, scc_hir_value_t *value, .to = SCC_LIR_VREG(dst_vreg), .arg0 = src}; scc_lir_builder_add_instr(ctx, &instr); - break; - } + } break; default: // 不生成指令的节点(如 CONST_INT, FUNC_ARG_REF)不会调用本函数 break; @@ -447,6 +442,7 @@ static void translate_func(ir2lir_ctx_t *ctx, scc_hir_func_t *ir_func) { .attr = SCC_LIR_ATTR_NONE, .frame_size = 0, .vregs_count = 0, + .is_va_arg = false, }; scc_vec_push(ctx->lir_module->func_metas, lir_func_meta); ctx->current_func = ir_func; @@ -483,7 +479,7 @@ static void translate_func(ir2lir_ctx_t *ctx, scc_hir_func_t *ir_func) { scc_hashtable_drop(&ctx->value_to_vreg); } -void scc_hir2lir(scc_lir_module_t *module, const scc_hir_cprog_t *cprog) { +void scc_hir2lir(scc_lir_module_t *module, scc_hir_cprog_t *cprog) { Assert(module != nullptr && cprog != nullptr); // FIXME diff --git a/libs/ir/lir/src/scc_lir_dump.c b/libs/ir/lir/src/scc_lir_dump.c index f6815e1..2d2c6e4 100644 --- a/libs/ir/lir/src/scc_lir_dump.c +++ b/libs/ir/lir/src/scc_lir_dump.c @@ -18,8 +18,6 @@ static const char *op_to_string(scc_lir_op_t op) { return "store"; case SCC_LIR_STORE_ADDR: return "store.addr"; - case SCC_LIR_LEA: - return "lea"; case SCC_LIR_ADD: return "add"; case SCC_LIR_SUB: @@ -236,7 +234,6 @@ void scc_lir_dump_ins(scc_lir_dump_ctx_t *ctx, const scc_lir_instr_t *ins) { scc_tree_dump_append(td, " <- "); dump_operand(ctx, &ins->arg0); break; - case SCC_LIR_LEA: case SCC_LIR_NEG: case SCC_LIR_NOT: case SCC_LIR_FNEG: @@ -419,7 +416,8 @@ void scc_lir_dump_func(scc_lir_dump_ctx_t *ctx, const scc_lir_func_t *func) { scc_lir_func_meta_t *meta = SCC_LIR_FUNC_META(func); // 函数头部 scc_tree_dump_begin_line(td); - scc_tree_dump_node(td, "func @%s", func->name ? func->name : ""); + scc_tree_dump_node(td, "func @%s%s", func->name ? func->name : "", + meta->is_va_arg ? "(...)" : "()"); scc_tree_dump_append_fmt(td, " (vregs: %u, frame: %d)", meta->vregs_count, meta->frame_size); if (meta->attr != SCC_LIR_ATTR_NONE) { diff --git a/libs/ir/mir/include/arch/scc_x86_isel.h b/libs/ir/mir/include/arch/scc_x86_isel.h index fa37fa0..4fea7e1 100644 --- a/libs/ir/mir/include/arch/scc_x86_isel.h +++ b/libs/ir/mir/include/arch/scc_x86_isel.h @@ -25,10 +25,10 @@ scc_x86_operand_value_t scc_x86_lir_val_to_mir_op(scc_x86_64_isel_t *isel, const scc_lir_val_t *val); static inline void emit_direct_call(scc_x86_64_isel_t *isel, const char *callee) { - (void)callee; scc_mir_x86_instr_t instr = {0}; - scc_mir_x86_instr_1(&instr, SCC_X86_IFORM_CALL_NEAR_RELBRZ, - scc_x86_op_relbr(0), scc_pos_create()); + scc_x86_operand_value_t op = scc_x86_op_reloc_global_relbr(callee, 0); + scc_mir_x86_instr_1(&instr, SCC_X86_IFORM_CALL_NEAR_RELBRZ, op, + scc_pos_create()); scc_vec_push(isel->instrs, instr); } diff --git a/libs/ir/mir/include/arch/scc_x86_mir.h b/libs/ir/mir/include/arch/scc_x86_mir.h index 6acff6e..ebc3e8a 100644 --- a/libs/ir/mir/include/arch/scc_x86_mir.h +++ b/libs/ir/mir/include/arch/scc_x86_mir.h @@ -43,15 +43,23 @@ static inline void scc_x86_op_set_preg(scc_x86_operand_value_t *op, op->reg = preg; } -// ── 未解析栈槽编码 (base=INVALID, disp=slot_id) ────────────────────── +// slot_id 编码为 base=INVALID, disp=slot_id +static inline scc_x86_operand_value_t scc_x86_op_slot(int slot_id) { + scc_x86_operand_value_t o = {.kind = SCC_X86_OPR_MEM}; + o.mem.base = SCC_X86_REG_INVALID; + o.mem.index = SCC_X86_REG_INVALID; + o.mem.scale = 1; + o.mem.disp.displacement = slot_id; + o.mem.disp.displacement_bits = 0; + return o; +} static inline bool scc_x86_op_is_slot(const scc_x86_operand_value_t *op) { return op->kind == SCC_X86_OPR_MEM && op->mem.base == SCC_X86_REG_INVALID; } static inline int scc_x86_op_slot_id(const scc_x86_operand_value_t *op) { - return op->mem.disp; + return op->mem.disp.displacement; } -// ── 指令构建辅助 ────────────────────────────────────────────────────── static inline void scc_mir_x86_instr_0(scc_mir_x86_instr_t *out, int opcode, scc_pos_t pos) { out->x86_instr.opcode = opcode; @@ -89,46 +97,4 @@ static inline void scc_mir_x86_instr_3(scc_mir_x86_instr_t *out, int opcode, out->x86_instr.src_loc = pos; } -// ── 常用操作数构造器 ────────────────────────────────────────────────── -static inline scc_x86_operand_value_t scc_x86_op_preg(scc_x86_reg_t reg) { - scc_x86_operand_value_t o = {.kind = SCC_X86_OPR_REG, .reg = reg}; - return o; -} -static inline scc_x86_operand_value_t scc_x86_op_vreg(int vreg) { - scc_x86_operand_value_t o = { - .kind = SCC_X86_OPR_REG, - .reg = (scc_x86_reg_t)((int)SCC_X86_REG_COUNT + vreg)}; - return o; -} -static inline scc_x86_operand_value_t scc_x86_op_relbr(i32 rel) { - scc_x86_operand_value_t o = {.kind = SCC_X86_OPR_RELBR, .imm = rel}; - return o; -} -static inline scc_x86_operand_value_t scc_x86_op_imm(i64 imm) { - scc_x86_operand_value_t o = {.kind = SCC_X86_OPR_IMM, .imm = imm}; - return o; -} -// slot_id 编码为 base=INVALID, disp=slot_id -static inline scc_x86_operand_value_t scc_x86_op_slot(int slot_id) { - scc_x86_operand_value_t o = {.kind = SCC_X86_OPR_MEM}; - o.mem.base = SCC_X86_REG_INVALID; - o.mem.index = SCC_X86_REG_INVALID; - o.mem.scale = 1; - o.mem.disp = slot_id; - return o; -} -static inline scc_x86_operand_value_t scc_x86_op_symbol(const char *sym) { - scc_x86_operand_value_t o = {.kind = SCC_X86_OPR_IMM, - .imm = (i64)(usize)sym}; - (void)o; - // symbol 暂用一个近似值占位,编码阶段处理重定位 - return o; -} -static inline scc_x86_operand_value_t -scc_x86_op_block(scc_cfg_bblock_id_t bid) { - scc_x86_operand_value_t o = {.kind = SCC_X86_OPR_RELBR, .imm = 0}; - (void)bid; - return o; -} - #endif /* __SCC_X86_MIR_H__ */ diff --git a/libs/ir/mir/src/arch/scc_x86_isel.c b/libs/ir/mir/src/arch/scc_x86_isel.c index ca0592f..3de6bc8 100644 --- a/libs/ir/mir/src/arch/scc_x86_isel.c +++ b/libs/ir/mir/src/arch/scc_x86_isel.c @@ -32,17 +32,34 @@ void scc_x86_instr_dump(scc_tree_dump_t *td, const scc_mir_x86_instr_t *instr) { scc_tree_dump_append_fmt(td, "$%s", preg_name(op->reg)); break; case SCC_X86_OPR_IMM: - scc_tree_dump_append_fmt(td, "%ld", op->imm); + scc_tree_dump_append_fmt(td, "%ld", op->imm0); break; case SCC_X86_OPR_MEM: if (scc_x86_op_is_slot(op)) scc_tree_dump_append_fmt(td, "[slot:%d]", scc_x86_op_slot_id(op)); else - scc_tree_dump_append_fmt(td, "[sp%+d]", op->mem.disp); + scc_tree_dump_append_fmt( + td, "[sp %c %llu]", + op->mem.disp.displacement >= 0 ? '+' : '-', + op->mem.disp.displacement < 0 ? -op->mem.disp.displacement + : op->mem.disp.displacement); break; case SCC_X86_OPR_RELBR: - scc_tree_dump_append(td, "label"); + scc_tree_dump_append(td, ""); + break; + case SCC_X86_OPR_RELOC: + switch (op->reloc.target) { + case SCC_X86_RELOC_TARGET_BBLOCK: + scc_tree_dump_append_fmt(td, "<#BB%d>", op->reloc.bblock_id); + break; + case SCC_X86_RELOC_TARGET_SYMBOL: + scc_tree_dump_append_fmt(td, "<%s>", op->reloc.global_name); + break; + default: + scc_tree_dump_append_fmt(td, ""); + break; + } break; default: break; @@ -75,7 +92,8 @@ scc_x86_operand_value_t scc_x86_lir_val_to_mir_op(scc_x86_64_isel_t *isel, op = scc_x86_op_imm(*(i64 *)&val->data.fimm); break; case SCC_LIR_INSTR_KIND_SYMBOL: - op = scc_x86_op_symbol(val->data.symbol); + // 默认作为绝对地址立即数(后续可优化为 RIP 相对) + op = scc_x86_op_reloc_global_imm(val->data.symbol, 0); break; case SCC_LIR_INSTR_KIND_ARG: Assert(isel->abi_lowering.lower_param); @@ -94,33 +112,41 @@ static scc_x86_operand_value_t new_vreg_temp(scc_x86_64_isel_t *isel) { void scc_x86_emit_move(scc_x86_64_isel_t *isel, scc_x86_operand_value_t dst, scc_x86_operand_value_t src, u8 size) { + scc_x86_operand_kind_t dst_kind = dst.kind; + if (dst_kind == SCC_X86_OPR_RELOC) { + dst_kind = dst.reloc.kind; + } + scc_x86_operand_kind_t src_kind = src.kind; + if (src_kind == SCC_X86_OPR_RELOC) { + src_kind = src.reloc.kind; + } - if (dst.kind == SCC_X86_OPR_REG) { - if (src.kind == SCC_X86_OPR_REG) { + if (dst_kind == SCC_X86_OPR_REG) { + if (src_kind == SCC_X86_OPR_REG) { add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_GPRV_8B, dst, src); - } else if (src.kind == SCC_X86_OPR_IMM) { + } else if (src_kind == SCC_X86_OPR_IMM) { add_instr_2(isel, (size == 8) ? SCC_X86_IFORM_MOV_GPRV_IMMZ : SCC_X86_IFORM_MOV_GPRV_IMMV, dst, src); - } else if (src.kind == SCC_X86_OPR_IMM && src.imm == 0) { + } else if (src_kind == SCC_X86_OPR_IMM && src.imm0 == 0) { // 特殊:符号作为立即数地址 add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_IMMZ, dst, src); - } else if (src.kind == SCC_X86_OPR_MEM) { + } else if (src_kind == SCC_X86_OPR_MEM) { add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_MEMV, dst, src); } else { UNREACHABLE(); } - } else if (dst.kind == SCC_X86_OPR_MEM) { - if (src.kind == SCC_X86_OPR_REG) { + } else if (dst_kind == SCC_X86_OPR_MEM) { + if (src_kind == SCC_X86_OPR_REG) { add_instr_2(isel, SCC_X86_IFORM_MOV_MEMV_GPRV, dst, src); - } else if (src.kind == SCC_X86_OPR_IMM) { + } else if (src_kind == SCC_X86_OPR_IMM) { add_instr_2(isel, SCC_X86_IFORM_MOV_MEMV_IMMZ, dst, src); - } else if (src.kind == SCC_X86_OPR_IMM) { + } else if (src_kind == SCC_X86_OPR_IMM) { scc_x86_operand_value_t temp = new_vreg_temp(isel); add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_IMMZ, temp, src); add_instr_2(isel, SCC_X86_IFORM_MOV_MEMV_GPRV, dst, temp); - } else if (src.kind == SCC_X86_OPR_MEM) { + } else if (src_kind == SCC_X86_OPR_MEM) { scc_x86_operand_value_t temp = new_vreg_temp(isel); scc_x86_emit_move(isel, temp, src, size); scc_x86_emit_move(isel, dst, temp, size); @@ -217,16 +243,6 @@ static void emit_binary_op(scc_x86_64_isel_t *isel, scc_lir_op_t op, add_instr_2(isel, iform, dst, src1); } -static void emit_spill_load(scc_x86_64_isel_t *isel, int vreg, int slot) { - scc_x86_operand_value_t dst = scc_x86_op_vreg(vreg); - add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_MEMV, dst, scc_x86_op_slot(slot)); -} - -static void emit_spill_store(scc_x86_64_isel_t *isel, int vreg, int slot) { - scc_x86_operand_value_t src = scc_x86_op_vreg(vreg); - add_instr_2(isel, SCC_X86_IFORM_MOV_MEMV_GPRV, scc_x86_op_slot(slot), src); -} - static void sel_mir(scc_x86_64_isel_t *isel, const scc_lir_instr_t *instr) { scc_x86_operand_value_t dst = scc_x86_lir_val_to_mir_op(isel, &instr->to); scc_x86_operand_value_t src0 = @@ -241,17 +257,16 @@ static void sel_mir(scc_x86_64_isel_t *isel, const scc_lir_instr_t *instr) { scc_x86_emit_move(isel, dst, src0, size); break; case SCC_LIR_LOAD: + // TODO check valid scc_x86_emit_move(isel, dst, src0, size); break; case SCC_LIR_STORE: + // TODO check valid scc_x86_emit_move(isel, src1, src0, size); break; - case SCC_LIR_STORE_ADDR: TODO(); break; - - case SCC_LIR_LEA: case SCC_LIR_LOAD_ADDR: add_instr_2(isel, SCC_X86_IFORM_LEA_GPRV_AGEN, dst, src0); break; @@ -374,9 +389,9 @@ static void sel_mir(scc_x86_64_isel_t *isel, const scc_lir_instr_t *instr) { /* ---- 条件分支 ---- */ case SCC_LIR_BR: { scc_x86_operand_value_t true_bb = - scc_x86_op_block(instr->metadata.br.true_target); + scc_x86_op_reloc_block(instr->metadata.br.true_target, 0); scc_x86_operand_value_t false_bb = - scc_x86_op_block(instr->metadata.br.false_target); + scc_x86_op_reloc_block(instr->metadata.br.false_target, 0); add_instr_2(isel, SCC_X86_IFORM_TEST_GPRV_GPRV, src0, src0); add_instr_1(isel, SCC_X86_IFORM_JNZ_RELBRZ, true_bb); @@ -385,7 +400,7 @@ static void sel_mir(scc_x86_64_isel_t *isel, const scc_lir_instr_t *instr) { case SCC_LIR_JMP: { scc_x86_operand_value_t jmp_bb = - scc_x86_op_block(instr->metadata.jmp_target); + scc_x86_op_reloc_block(instr->metadata.jmp_target, 0); add_instr_1(isel, SCC_X86_IFORM_JMP_RELBRZ, jmp_bb); } break; @@ -458,6 +473,7 @@ void scc_isel_x86_64(scc_mir_module_t *mir_module, Assert(func_meta != nullptr); scc_mir_func_meta_init(func_meta); func_meta->vregs_count = SCC_LIR_FUNC_META(func)->vregs_count; + func_meta->need_va_args = SCC_LIR_FUNC_META(func)->is_va_arg; func->meta = func_meta; isel->func = func; diff --git a/libs/ir/mir/src/target/win64_abi.c b/libs/ir/mir/src/target/win64_abi.c index c24d779..678c526 100644 --- a/libs/ir/mir/src/target/win64_abi.c +++ b/libs/ir/mir/src/target/win64_abi.c @@ -29,8 +29,13 @@ static void frame_alloc_impl(scc_frame_layout_t *ctx, ctx->offset += slot->size; slot->offset = ctx->offset; } - op->mem.base = SCC_X86_REG_RSP; - op->mem.disp = -slot->offset; + *op = scc_x86_op_mem((scc_x86_mem_t){ + .seg = SCC_X86_REG_INVALID, + .base = SCC_X86_REG_RSP, + .disp = {.displacement = -slot->offset}, + .index = SCC_X86_REG_INVALID, + .scale = 1, + }); } } } diff --git a/libs/ir2mcode/include/scc_ir2mcode.h b/libs/ir2mcode/include/scc_ir2mcode.h index 5622b11..60331a2 100644 --- a/libs/ir2mcode/include/scc_ir2mcode.h +++ b/libs/ir2mcode/include/scc_ir2mcode.h @@ -3,9 +3,30 @@ #include #include + +typedef struct scc_reloc { + usize offset; // 占位位置 + u8 size; // 占位字节数(可选,用于校验) + int arch_type; // 架构相关的重定位类型(由后端解释) + enum { + SCC_RELOC_TARGET_NONE, + SCC_RELOC_TARGET_SYMBOL, + SCC_RELOC_TARGET_BBLOCK, + } target_kind; + union { + const char *symbol; + int bblock_id; + }; + i64 addend; +} scc_reloc_t; + +typedef SCC_VEC(scc_reloc_t) scc_reloc_vec_t; + // FIXME target choice -void scc_ir2mcode_emit_instr(scc_mcode_t *mcode, +void scc_ir2mcode_emit_instr(scc_mcode_t *mcode, scc_reloc_vec_t *relocs, const scc_mir_instr_t *mir_instr); -void scc_ir2mcode(scc_mcode_t *mcode, const scc_mir_module_t *mir_module); +void scc_ir2mcode_patch(scc_mcode_t *mcode, scc_reloc_t *reloc, i64 value); +void scc_ir2mcode(scc_mcode_t *mcode, scc_reloc_vec_t *relocs, + const scc_mir_module_t *mir_module); #endif /* __SCC_IR2MCODE_H__ */ diff --git a/libs/ir2mcode/src/scc_ir2mcode.c b/libs/ir2mcode/src/scc_ir2mcode.c index b18cc33..939e1b9 100644 --- a/libs/ir2mcode/src/scc_ir2mcode.c +++ b/libs/ir2mcode/src/scc_ir2mcode.c @@ -5,30 +5,91 @@ #include #include #include +#include #include -void mir_x86_to_mcode(scc_mcode_t *mcode, const scc_mir_x86_instr_t *_ins) { +void mir_x86_to_mcode(scc_mcode_t *mcode, scc_reloc_vec_t *relocs, + const scc_mir_x86_instr_t *_ins) { + Assert(mcode != nullptr && _ins != nullptr); + int skip_reloc = relocs == nullptr; scc_x86_instr_t *ins = (void *)_ins; if (ins->opcode < 0 || ins->opcode >= SCC_X86_IFORM_COUNT) { return; } scc_x86_operand_value_t ops[8] = {0}; + scc_reloc_t reloc = {0}; for (int i = 0; i < ins->num_operands; i++) { - if (scc_x86_op_is_vreg(&ins->operands[i])) + scc_x86_operand_value_t *op_ptr = &ins->operands[i]; + if (scc_x86_op_is_vreg(op_ptr)) Panic("can't convert vreg to mcode"); - if (scc_x86_op_is_slot(&ins->operands[i])) + if (scc_x86_op_is_slot(op_ptr)) Panic("can't convert unresolved slot to mcode"); - ops[i] = ins->operands[i]; + ops[i] = *op_ptr; + if (op_ptr->kind == SCC_X86_OPR_RELOC) { + ops[i].kind = op_ptr->reloc.kind; + switch (op_ptr->reloc.kind) { + case SCC_X86_OPR_RELBR: + ops[i].imm0 = 0; + break; + default: + TODO(); + break; + } + if (skip_reloc) { + continue; + } + if (skip_reloc != SCC_RELOC_TARGET_NONE) { + LOG_FATAL("can't using twice reloc in one instr"); + continue; + } + reloc.addend = op_ptr->reloc.addend; + reloc.arch_type = (int)op_ptr->reloc.kind; + reloc.size = 0; + reloc.offset = scc_mcode_size(mcode); + if (op_ptr->reloc.target == SCC_X86_RELOC_TARGET_SYMBOL) { + reloc.target_kind = SCC_RELOC_TARGET_SYMBOL; + reloc.symbol = op_ptr->reloc.global_name; + } else if (op_ptr->reloc.target == SCC_X86_RELOC_TARGET_BBLOCK) { + reloc.target_kind = SCC_RELOC_TARGET_BBLOCK; + reloc.bblock_id = op_ptr->reloc.bblock_id; + } else { + TODO(); + } + } } scc_x86_encode_inst(mcode, ins->opcode, ops); + if (!skip_reloc && reloc.target_kind != SCC_RELOC_TARGET_NONE) { + reloc.offset = scc_mcode_size(mcode); + scc_vec_push(*relocs, reloc); + } } -void scc_ir2mcode_emit_instr(scc_mcode_t *mcode, +void mir_x86_patch(scc_mcode_t *mcode, scc_reloc_t *reloc, i64 value) { + // return; + scc_x86_patch_type_t patch_type = SCC_X86_PATCH_NONE; + switch (reloc->arch_type) { + case SCC_X86_OPR_RELBR: + patch_type = SCC_X86_PATCH_PC32; + break; + default: + Panic("unsupported reloc type"); + break; + } + scc_x86_patch(mcode, patch_type, reloc->offset + reloc->addend, value); +} + +void scc_ir2mcode_emit_instr(scc_mcode_t *mcode, scc_reloc_vec_t *relocs, const scc_mir_instr_t *mir_instr) { - mir_x86_to_mcode(mcode, (const scc_mir_x86_instr_t *)mir_instr); + mir_x86_to_mcode(mcode, relocs, (const scc_mir_x86_instr_t *)mir_instr); } -void scc_ir2mcode(scc_mcode_t *mcode, const scc_mir_module_t *mir_module) { +void scc_ir2mcode_patch(scc_mcode_t *mcode, scc_reloc_t *reloc, i64 value) { + mir_x86_patch(mcode, reloc, value); +} + +void scc_ir2mcode(scc_mcode_t *mcode, scc_reloc_vec_t *relocs, + const scc_mir_module_t *mir_module) { + Assert(mir_module != nullptr && mcode != nullptr); scc_vec_foreach(mir_module->cfg_module.funcs, i) { if (i == 0) continue; @@ -42,7 +103,7 @@ void scc_ir2mcode(scc_mcode_t *mcode, const scc_mir_module_t *mir_module) { scc_vec_foreach(*instrs, i) { const scc_mir_instr_t *ins = scc_vec_sized_at_ptr(*instrs, mir_module->instr_size, i); - scc_ir2mcode_emit_instr(mcode, ins); + scc_ir2mcode_emit_instr(mcode, relocs, ins); } } } diff --git a/libs/ir2mcode/src/scc_ir2sccf.c b/libs/ir2mcode/src/scc_ir2sccf.c index 27cdb09..de247b4 100644 --- a/libs/ir2mcode/src/scc_ir2sccf.c +++ b/libs/ir2mcode/src/scc_ir2sccf.c @@ -37,6 +37,70 @@ static inline void scc_ir_symbol_to_sect_data(const scc_cfg_symbol_t *symbol, // } } +static void emit_mir_module(sccf_builder_t *builder, scc_mcode_t *mcode, + scc_mir_module_t *mir_module) { + + scc_hashtable_t bblock_offset; + + scc_vec_foreach(mir_module->cfg_module.funcs, i) { + if (i == 0) + continue; + scc_mir_func_t *func = &scc_vec_at(mir_module->cfg_module.funcs, i); + + sccf_sym_t *sym = sccf_builder_get_symbol_unsafe(builder, func->name); + Assert(sym != nullptr); + sym->sccf_sect_offset = scc_mcode_size(mcode); + + scc_hashtable_usize_init(&bblock_offset); + scc_reloc_vec_t relocs; + scc_vec_init(relocs); + scc_vec_foreach(func->bblocks, i) { + scc_cfg_bblock_id_t id = scc_vec_at(func->bblocks, i); + const scc_cfg_bblock_t *bb = + scc_cfg_module_unsafe_get_bblock(&mir_module->cfg_module, id); + + // 插入bblock的offset + scc_hashtable_set(&bblock_offset, (void *)(usize)id, + (void *)scc_mcode_size(mcode)); + + scc_mir_instr_vec_t *instrs = SCC_MIR_BBLOCK_VALUES_PTR(bb); + scc_vec_foreach(*instrs, i) { + const scc_mir_instr_t *ins = + scc_vec_sized_at_ptr(*instrs, mir_module->instr_size, i); + // FIXME reloc symbol needed + scc_ir2mcode_emit_instr(mcode, &relocs, ins); + } + } + + scc_vec_foreach(relocs, i) { + scc_reloc_t *reloc = &scc_vec_at(relocs, i); + if (reloc->target_kind == SCC_RELOC_TARGET_BBLOCK) { + reloc->target_kind = SCC_RELOC_TARGET_NONE; + usize addr = (usize)scc_hashtable_get( + &bblock_offset, (void *)(usize)reloc->bblock_id); + scc_ir2mcode_patch(mcode, reloc, addr); + } else if (reloc->target_kind == SCC_RELOC_TARGET_SYMBOL) { + usize sym_idx = + sccf_builder_get_symbol_idx(builder, reloc->symbol); + Assert(sym_idx != 0); + sccf_builder_add_reloc(builder, + (sccf_reloc_t){ + .addend = reloc->addend, + .offset = reloc->offset, + .reloc_type = reloc->arch_type, + .sect_type = SCCF_SECT_CODE, + .sym_idx = sym_idx, + }); + } else { + TODO(); + } + } + scc_vec_free(relocs); + // 重定向bblock的reloc + scc_hashtable_drop(&bblock_offset); + } +} + void scc_ir2sccf(sccf_builder_t *builder, scc_mir_module_t *mir_module) { // mir_module->symbol_metas // mir_module->cfg_module.funcs @@ -74,54 +138,36 @@ void scc_ir2sccf(sccf_builder_t *builder, scc_mir_module_t *mir_module) { sccf_sect_data_t sect_code = {0}; scc_vec_init(sect_code); scc_mcode_t mcode = {0}; + // TODO choice arch scc_mcode_init(&mcode, SCC_MCODE_ARCH_X86_64); - scc_vec_foreach(mir_module->cfg_module.funcs, i) { - if (i == 0) - continue; - scc_mir_func_t *func = &scc_vec_at(mir_module->cfg_module.funcs, i); + emit_mir_module(builder, &mcode, mir_module); + scc_vec_unsafe_from_buffer(sect_code, (u8 *)scc_mcode_unsafe_data(&mcode), + scc_mcode_size(&mcode)); - sccf_sym_t *sym = sccf_builder_get_symbol_unsafe(builder, func->name); - Assert(sym != nullptr); - sym->sccf_sect_offset = scc_vec_size(mcode.mcode); + scc_vec_foreach(builder->relocs, i) { + sccf_reloc_t *reloc = &scc_vec_at(builder->relocs, i); + if (reloc->sym_idx == 0) { + Panic("relocate to an invalid symbol"); + } + sccf_sym_t *sym = &scc_vec_at(builder->symtab, reloc->sym_idx); + if (sym->sccf_sym_type != SCCF_SYM_TYPE_EXTERN) { - scc_vec_foreach(func->bblocks, i) { - scc_cfg_bblock_id_t id = scc_vec_at(func->bblocks, i); - const scc_cfg_bblock_t *bb = - scc_cfg_module_unsafe_get_bblock(&mir_module->cfg_module, id); - scc_mir_instr_vec_t *instrs = SCC_MIR_BBLOCK_VALUES_PTR(bb); - scc_vec_foreach(*instrs, i) { - const scc_mir_instr_t *ins = - scc_vec_sized_at_ptr(*instrs, mir_module->instr_size, i); - // FIXME reloc symbol needed - scc_ir2mcode_emit_instr(&mcode, ins); + if (sym->sccf_sect_type == SCCF_SECT_CODE && + sym->sccf_sym_type == SCCF_SYM_TYPE_FUNC) { + i64 target_off = sym->sccf_sect_offset; + + scc_ir2mcode_patch(&mcode, + &(scc_reloc_t){ + .target_kind = SCC_RELOC_TARGET_SYMBOL, + .arch_type = reloc->reloc_type, + .offset = reloc->offset, + .addend = reloc->addend, + }, + target_off); + reloc->reloc_type = SCCF_RELOC_TYPE_EMPTY; } } } - scc_vec_unsafe_from_buffer(sect_code, scc_vec_unsafe_get_data(mcode.mcode), - scc_vec_size(mcode.mcode)); - - // u8 *buf = scc_vec_unsafe_get_data(ctx->sect_mcode.mcode); - // scc_vec_foreach(ctx->builder->relocs, i) { - // sccf_reloc_t *reloc = &scc_vec_at(ctx->builder->relocs, i); - // if (reloc->sym_idx == 0) { - // Panic("relocate to an invalid symbol"); - // } - // sccf_sym_t *sym = &scc_vec_at(ctx->builder->symtab, reloc->sym_idx); - // if (sym->sccf_sym_type != SCCF_SYM_TYPE_EXTERN) { - // Assert(reloc->reloc_type == SCCF_RELOC_TYPE_REL); - - // if (sym->sccf_sect_type == SCCF_SECT_CODE && - // sym->sccf_sym_type == SCCF_SYM_TYPE_FUNC) { - // i64 target_off = sym->sccf_sect_offset; - // i64 next_off = reloc->offset + reloc->addend; - // i32 rel = (i32)(target_off - next_off); - // // FIXME 写入到指令的偏移字段(小端) - // *(i32 *)(&buf[reloc->offset]) = rel; - - // reloc->reloc_type = SCCF_RELOC_TYPE_EMPTY; - // } - // } - // } sccf_builder_add_text_section(builder, §_code); sccf_builder_add_data_section(builder, §_data); diff --git a/libs/mcode/.gitignore b/libs/mcode/.gitignore new file mode 100644 index 0000000..7043ff1 --- /dev/null +++ b/libs/mcode/.gitignore @@ -0,0 +1,2 @@ + +*.json diff --git a/libs/mcode/include/x86/scc_x86_encode.h b/libs/mcode/include/x86/scc_x86_encode.h index 68de93c..fc888cd 100644 --- a/libs/mcode/include/x86/scc_x86_encode.h +++ b/libs/mcode/include/x86/scc_x86_encode.h @@ -6,21 +6,116 @@ #include "scc_x86_reg.h" typedef struct { + i64 displacement; + u32 displacement_bits; +} scc_x86_disp_t; + +typedef struct { + scc_x86_reg_t seg; scc_x86_reg_t base; scc_x86_reg_t index; - u8 scale; /* 1,2,4,8 */ - i32 disp; + u32 scale; + scc_x86_disp_t disp; } scc_x86_mem_t; +typedef enum { + SCC_X86_RELOC_TARGET_SYMBOL, + SCC_X86_RELOC_TARGET_BBLOCK, +} scc_x86_reloc_target_t; + +typedef struct scc_x86_reloc_op { + scc_x86_operand_kind_t kind; // 原始操作数类型 + scc_x86_reloc_target_t target; + union { + i64 imm; + int bblock_id; // 如果 kind == RELBR + const char *global_name; // 如果 kind == SYMBOL + }; + i64 addend; // 额外常量偏移,用于 sym+addend +} scc_x86_reloc_op_t; + typedef struct { scc_x86_operand_kind_t kind; union { scc_x86_reg_t reg; - i64 imm; + i32 brdisp; + i64 simm0; + u64 imm0; + u8 imm1; scc_x86_mem_t mem; + scc_x86_reloc_op_t reloc; }; } scc_x86_operand_value_t; +static inline scc_x86_operand_value_t scc_x86_op_preg(scc_x86_reg_t reg) { + scc_x86_operand_value_t o = {.kind = SCC_X86_OPR_REG, .reg = reg}; + return o; +} +static inline scc_x86_operand_value_t scc_x86_op_vreg(int vreg) { + scc_x86_operand_value_t o = { + .kind = SCC_X86_OPR_REG, + .reg = (scc_x86_reg_t)((int)SCC_X86_REG_COUNT + vreg)}; + return o; +} +static inline scc_x86_operand_value_t scc_x86_op_relbr(i32 rel) { + scc_x86_operand_value_t o = {.kind = SCC_X86_OPR_RELBR, .brdisp = rel}; + return o; +} +static inline scc_x86_operand_value_t scc_x86_op_imm(i64 imm) { + scc_x86_operand_value_t o = {.kind = SCC_X86_OPR_IMM, .simm0 = imm}; + return o; +} +static inline scc_x86_operand_value_t scc_x86_op_mem(scc_x86_mem_t mem) { + scc_x86_operand_value_t o = {.kind = SCC_X86_OPR_MEM, .mem = mem}; + return o; +} + +// 1. 全局符号重定位(绝对地址加载:MOV reg, imm32/64) +static inline scc_x86_operand_value_t +scc_x86_op_reloc_global_imm(const char *sym, i64 addend) { + scc_x86_operand_value_t op = {.kind = SCC_X86_OPR_RELOC}; + op.reloc.kind = SCC_X86_OPR_IMM; + op.reloc.target = SCC_X86_RELOC_TARGET_SYMBOL; + op.reloc.global_name = sym; + op.reloc.addend = addend; + return op; +} + +// 2. 全局符号重定位(相对跳转/调用:CALL/JMP rel32) +static inline scc_x86_operand_value_t +scc_x86_op_reloc_global_relbr(const char *sym, i64 addend) { + scc_x86_operand_value_t op = {.kind = SCC_X86_OPR_RELOC}; + op.reloc.kind = SCC_X86_OPR_RELBR; + op.reloc.target = SCC_X86_RELOC_TARGET_SYMBOL; + op.reloc.global_name = sym; + op.reloc.addend = addend; + return op; +} + +// 3. 基本块重定位(相对跳转) +static inline scc_x86_operand_value_t scc_x86_op_reloc_block(int bid, + i64 addend) { + scc_x86_operand_value_t op = {.kind = SCC_X86_OPR_RELOC}; + op.reloc.kind = SCC_X86_OPR_RELBR; + op.reloc.target = SCC_X86_RELOC_TARGET_BBLOCK; + op.reloc.bblock_id = bid; + op.reloc.addend = addend; + return op; +} + +// 4. 如果需要支持符号的内存寻址(如 [RIP + sym]),可扩展 kind = +// SCC_X86_OPR_MEM +static inline scc_x86_operand_value_t +scc_x86_op_reloc_global_mem(const char *sym, i64 addend) { + scc_x86_operand_value_t op = {.kind = SCC_X86_OPR_RELOC}; + op.reloc.kind = SCC_X86_OPR_MEM; + op.reloc.target = SCC_X86_RELOC_TARGET_SYMBOL; + op.reloc.global_name = sym; + op.reloc.addend = addend; + // 编码时需生成 RIP 相对寻址的 ModRM/SIB + return op; +} + /* 按 iform 发射一条指令,ops 数组长度需与 iform 定义的操作数数目一致 */ int scc_x86_encode_inst(scc_mcode_t *mcode, scc_x86_iform_t iform, const scc_x86_operand_value_t *ops); diff --git a/libs/mcode/include/x86/scc_x86_patch.h b/libs/mcode/include/x86/scc_x86_patch.h new file mode 100644 index 0000000..a918181 --- /dev/null +++ b/libs/mcode/include/x86/scc_x86_patch.h @@ -0,0 +1,137 @@ +#ifndef __SCC_X86_PATCH_H__ +#define __SCC_X86_PATCH_H__ +#include "scc_x86_encode.h" + +// x86-64 重定位类型(由底层 patch 函数处理) +typedef enum { + SCC_X86_PATCH_NONE, + SCC_X86_PATCH_PC32, // 32 位 PC 相对偏移(CALL/JMP/Jcc) + SCC_X86_PATCH_ABS64, // 64 位绝对地址(MOV reg, imm64) + SCC_X86_PATCH_ABS32, // 32 位绝对地址(MOV reg, imm32) + SCC_X86_PATCH_DISP8, // 8 位内存位移([RIP+disp8] 或 [base+disp8]) + SCC_X86_PATCH_DISP32, // 32 位内存位移([RIP+disp32]) +} scc_x86_patch_type_t; + +static inline void patch_bytes(scc_mcode_t *mcode, usize offset, + const void *data, usize size) { + u8 *buf = (u8 *)scc_mcode_unsafe_data(mcode); + usize total = scc_mcode_size(mcode); + if (offset + size > total) { + Panic("patch offset out of range: offset=%zu size=%zu total=%zu", + offset, size, total); + } + scc_memcpy(buf + offset, data, size); +} + +/* ---------- 实现补丁接口 ---------- */ + +static inline int scc_x86_patch_disp(scc_mcode_t *mcode, usize offset, + scc_x86_disp_t disp) { + if (!mcode || disp.displacement_bits == 0) + return -1; + usize bytes = disp.displacement_bits / 8; + if (bytes == 0) { + bytes = 4; // RELBR 32 + } + if (bytes != 1 && bytes != 2 && bytes != 4 && bytes != 8) { + Panic("invalid displacement bits: %u", disp.displacement_bits); + } + // 将 displacement 截断到对应宽度(小端写入) + i64 val = disp.displacement; + switch (bytes) { + case 1: { + u8 v = (u8)val; + patch_bytes(mcode, offset, &v, 1); + break; + } + case 2: { + u16 v = (u16)val; + patch_bytes(mcode, offset, &v, 2); + break; + } + case 4: { + u32 v = (u32)val; + patch_bytes(mcode, offset, &v, 4); + break; + } + case 8: + patch_bytes(mcode, offset, &val, 8); + break; + } + return 0; +} + +static inline int scc_x86_patch_brdisp(scc_mcode_t *mcode, usize offset, + scc_x86_operand_value_t disp) { + if (disp.kind != SCC_X86_OPR_RELBR && disp.kind != SCC_X86_OPR_RELOC) { + Panic("patch_brdisp called with non-branch operand kind %d", disp.kind); + } + i32 brdisp; + if (disp.kind == SCC_X86_OPR_RELBR) + brdisp = disp.brdisp; + else + brdisp = (i32)disp.reloc.imm; // 从重定位占位中获取值(上层会先填好) + patch_bytes(mcode, offset, &brdisp, 4); + return 0; +} + +static inline int scc_x86_patch_imm0(scc_mcode_t *mcode, usize offset, + scc_x86_operand_value_t imm0) { + // 注意:原声明未提供大小参数,我们假定调用者保证了正确的宽度。 + // 此处默认写入 8 字节(最常用)。若需要其他宽度,请使用扩展版本。 + if (imm0.kind != SCC_X86_OPR_IMM && imm0.kind != SCC_X86_OPR_RELOC) { + Panic("patch_imm0 called with non-immediate operand kind %d", + imm0.kind); + } + u64 val; + if (imm0.kind == SCC_X86_OPR_IMM) + val = imm0.imm0; + else + val = (u64)imm0.reloc.imm; // 从重定位占位中获取 + patch_bytes(mcode, offset, &val, 8); + return 0; +} + +/* ---------- 扩展:带大小的立即数 patch(推荐上层使用) ---------- */ +static inline int scc_x86_patch_imm0_ex(scc_mcode_t *mcode, usize offset, + u64 value, usize size) { + if (size != 1 && size != 2 && size != 4 && size != 8) + return -1; + switch (size) { + case 1: { + u8 v = (u8)value; + patch_bytes(mcode, offset, &v, 1); + break; + } + case 2: { + u16 v = (u16)value; + patch_bytes(mcode, offset, &v, 2); + break; + } + case 4: { + u32 v = (u32)value; + patch_bytes(mcode, offset, &v, 4); + break; + } + case 8: + patch_bytes(mcode, offset, &value, 8); + break; + } + return 0; +} + +static inline void scc_x86_patch(scc_mcode_t *mcode, + scc_x86_patch_type_t patch_type, u64 offset, + i64 value) { + switch (patch_type) { + case SCC_X86_PATCH_PC32: + scc_x86_patch_brdisp(mcode, offset - 4, + scc_x86_op_relbr(value - offset)); + break; + default: + TODO(); + break; + } +} + +#endif /* __SCC_X86_PATCH_H__ */ diff --git a/libs/mcode/src/scc_x86_encode.c b/libs/mcode/src/scc_x86_encode.c index fb0c70e..e284a75 100644 --- a/libs/mcode/src/scc_x86_encode.c +++ b/libs/mcode/src/scc_x86_encode.c @@ -1,9 +1,14 @@ -#include -#include #include #include #include +#if 1 +#ifdef LOG_INFO +#undef LOG_INFO +#endif +#define LOG_INFO(...) +#endif + /* ---------- 内部辅助 ---------- */ static inline void emit_u8(scc_mcode_t *m, uint8_t v) { scc_mcode_add_u8(m, v); @@ -54,13 +59,13 @@ static int infer_operand_width(const scc_x86_iform_info_t *info, } const char *eosz = info->encode.eosz; int default_64 = info->encode.default_64b; - if (!strcmp(eosz, "o16")) + if (!scc_strcmp(eosz, "o16")) return 16; - if (!strcmp(eosz, "o32")) + if (!scc_strcmp(eosz, "o32")) return 32; - if (!strcmp(eosz, "o64")) + if (!scc_strcmp(eosz, "o64")) return 64; - if (!strcmp(eosz, "oszall") || !strcmp(eosz, "osznot16")) + if (!scc_strcmp(eosz, "oszall") || !scc_strcmp(eosz, "osznot16")) return default_64 ? 64 : 32; return 32; } @@ -69,16 +74,11 @@ static int infer_operand_width(const scc_x86_iform_info_t *info, static int need_rexw(const scc_x86_encoding_t *enc, scc_x86_reg_t reg_op, scc_x86_reg_t rm_op, scc_x86_reg_t base, scc_x86_reg_t idx) { - /* 强制要求 / 明确禁止 优先级最高 */ if (enc->rex_w == 1) return 1; if (enc->rex_w == 0) return 0; - /* 指令已隐含 64 位语义(如 PUSH/POP),但仍可能被 64 位操作数需要 W?例如 - * PUSH r64 不需要 W,但 PUSH r/m64 也不需要。总之 default_64b - * 时一般无需额外 W,但若操作数明确是 64 位且模板没有禁止,我们仍加上以兼容 - * movabs 等 */ int has_64bit_op = 0; if (reg_op != SCC_X86_REG_INVALID && scc_reg_width(reg_op) == 64) has_64bit_op = 1; @@ -90,9 +90,6 @@ static int need_rexw(const scc_x86_encoding_t *enc, scc_x86_reg_t reg_op, has_64bit_op = 1; if (enc->default_64b) { - /* 对于默认 64 位的指令(如 CALL, JMP),有些仍需要 REX.W - * 访问扩展寄存器,但若 reg/rm 本身是 64 位且需要 REX.B/R 则一并设置 W - * 来保证编码正确?这里简单处理:只要访问扩展寄存器就加 W */ return (reg_op != SCC_X86_REG_INVALID && reg_rex_bit(reg_op)) || (rm_op != SCC_X86_REG_INVALID && reg_rex_bit(rm_op)) || (base != SCC_X86_REG_INVALID && reg_rex_bit(base)) || @@ -101,7 +98,6 @@ static int need_rexw(const scc_x86_encoding_t *enc, scc_x86_reg_t reg_op, : 0; } - /* 普通指令:有 64 位操作数即加 W */ return has_64bit_op; } @@ -109,8 +105,7 @@ static int need_66_prefix(const scc_x86_encoding_t *enc, scc_x86_reg_t reg_op, scc_x86_reg_t rm_op) { if (enc->osz_required) return 1; - // 如果强制指定了操作大小,不自动加66 - if (!strcmp(enc->eosz, "o32") || !strcmp(enc->eosz, "o64")) + if (!scc_strcmp(enc->eosz, "o32") || !scc_strcmp(enc->eosz, "o64")) return 0; if (reg_op != SCC_X86_REG_INVALID && scc_reg_width(reg_op) == 16) return 1; @@ -215,17 +210,17 @@ static void emit_immediate(scc_mcode_t *m, const scc_x86_encoding_t *enc, int64_t imm_val, int op_width) { const char *oc2 = tmpl[imm_idx].oc2; int imm_size = enc->imm_size; - if (!strcmp(oc2, "b")) + if (!scc_strcmp(oc2, "b")) imm_size = 1; - else if (!strcmp(oc2, "w")) + else if (!scc_strcmp(oc2, "w")) imm_size = 2; - else if (!strcmp(oc2, "z")) + else if (!scc_strcmp(oc2, "z")) imm_size = (op_width <= 16) ? op_width / 8 : (op_width <= 32 ? 4 : 4); - else if (!strcmp(oc2, "v")) + else if (!scc_strcmp(oc2, "v")) imm_size = op_width / 8; - else if (!strcmp(oc2, "d") || !strcmp(oc2, "ss")) + else if (!scc_strcmp(oc2, "d") || !scc_strcmp(oc2, "ss")) imm_size = 4; - else if (!strcmp(oc2, "q")) + else if (!scc_strcmp(oc2, "q")) imm_size = 8; LOG_INFO("[IMM] val=%lld size=%d", imm_val, imm_size); @@ -268,9 +263,9 @@ static void emit_modrm_sib_disp(scc_mcode_t *m, if (ops[i].kind == SCC_X86_OPR_REG) { LOG_INFO("[OPD] %d: REG kind, name=\"%s\" reg=%d", i, tname, ops[i].reg); - if (strncmp(tname, "REG0", 4) == 0) + if (scc_strcmp(tname, "REG0") == 0) reg_r = ops[i].reg; - else if (strncmp(tname, "REG1", 4) == 0) + else if (scc_strcmp(tname, "REG1") == 0) reg_b = ops[i].reg; else { if (reg_r == SCC_X86_REG_INVALID) @@ -282,7 +277,7 @@ static void emit_modrm_sib_disp(scc_mcode_t *m, has_mem = 1; memdesc = ops[i].mem; } else if (ops[i].kind == SCC_X86_OPR_IMM) { - imm_val = ops[i].imm; + imm_val = ops[i].imm0; imm_idx = i; } } @@ -296,7 +291,7 @@ static void emit_modrm_sib_disp(scc_mcode_t *m, else if (enc->modrm_reg_fix >= 0) modrm |= (enc->modrm_reg_fix & 7) << 3; - int32_t disp = memdesc.disp; + int32_t disp = memdesc.disp.displacement; int dsize = disp_size(disp, memdesc.base); modrm |= (dsize == 0) ? 0 : (dsize == 8) ? 0x40 : 0x80; @@ -341,22 +336,38 @@ static void emit_modrm_sib_disp(scc_mcode_t *m, } } } else { - modrm = 0xC0; - if (enc->modrm_reg_fix >= 0) - modrm |= (enc->modrm_reg_fix & 7) << 3; - else if (reg_r != SCC_X86_REG_INVALID) - modrm |= (reg_low3(reg_r) & 7) << 3; + // 特殊情况:只有一个显式寄存器操作数,且 reg_fix/rm_fix 均未指定,且 + // mod_fix == 3 此时操作数应放在 rm 字段,reg 字段固定为 0(例如 SETZ + // 指令) + int is_single_reg_op = + (info->num_explicit_ops == 1 && enc->modrm_reg_fix == -1 && + enc->modrm_rm_fix == -1 && enc->mod_fix == 3); + if (is_single_reg_op && reg_r != SCC_X86_REG_INVALID && + reg_b == SCC_X86_REG_INVALID) { + // 操作数作为 rm,reg 部分为 0 + modrm = 0xC0 | (reg_low3(reg_r) & 7); + emit_u8(m, modrm); + LOG_INFO("[MODRM] single reg operand treated as rm, emit 0x%02x", + modrm); + } else { + modrm = 0xC0; + if (enc->modrm_reg_fix >= 0) + modrm |= (enc->modrm_reg_fix & 7) << 3; + else if (reg_r != SCC_X86_REG_INVALID) + modrm |= (reg_low3(reg_r) & 7) << 3; - if (enc->modrm_rm_fix >= 0) { - modrm |= enc->modrm_rm_fix & 7; - } else if (reg_b != SCC_X86_REG_INVALID) { - modrm |= reg_low3(reg_b) & 7; - } else if (enc->modrm_reg_fix >= 0 && reg_r != SCC_X86_REG_INVALID) { - modrm |= reg_low3(reg_r) & 7; - } else if (reg_r != SCC_X86_REG_INVALID) { - modrm |= reg_low3(reg_r) & 7; + if (enc->modrm_rm_fix >= 0) { + modrm |= enc->modrm_rm_fix & 7; + } else if (reg_b != SCC_X86_REG_INVALID) { + modrm |= reg_low3(reg_b) & 7; + } else if (enc->modrm_reg_fix >= 0 && + reg_r != SCC_X86_REG_INVALID) { + modrm |= reg_low3(reg_r) & 7; + } else if (reg_r != SCC_X86_REG_INVALID) { + modrm |= reg_low3(reg_r) & 7; + } + emit_u8(m, modrm); } - emit_u8(m, modrm); } LOG_INFO("[MODRM] emit byte 0x%02x", modrm); @@ -394,12 +405,12 @@ int scc_x86_encode_inst(scc_mcode_t *mcode, scc_x86_iform_t iform, for (int i = 0; i < num_ops; i++) { const char *tname = tmpl[i].name; if (ops[i].kind == SCC_X86_OPR_REG) { - if (strncmp(tname, "REG0", 4) == 0) { + if (scc_strcmp(tname, "REG0") == 0) { if (enc->modrm_reg_fix >= 0) rm_field = ops[i].reg; // reg固定 → REG0为rm else reg_field = ops[i].reg; // 否则为reg - } else if (strncmp(tname, "REG1", 4) == 0) { + } else if (scc_strcmp(tname, "REG1") == 0) { if (enc->modrm_rm_fix >= 0) reg_field = ops[i].reg; // rm固定 → REG1为reg else @@ -416,11 +427,25 @@ int scc_x86_encode_inst(scc_mcode_t *mcode, scc_x86_iform_t iform, idx_reg = ops[i].mem.index; } else if (ops[i].kind == SCC_X86_OPR_IMM || ops[i].kind == SCC_X86_OPR_RELBR) { - imm_val = ops[i].imm; + imm_val = ops[i].imm0; imm_idx = i; } } + // ===== 新增:特殊处理 SETZ 类指令(只有一个寄存器操作数,mod_fix=3 且 + // reg_fix/rm_fix 未指定)===== + if (enc->has_modrm && info->num_explicit_ops == 1 && + enc->modrm_reg_fix == -1 && enc->modrm_rm_fix == -1 && + enc->mod_fix == 3) { + if (reg_field != SCC_X86_REG_INVALID && + rm_field == SCC_X86_REG_INVALID) { + // 将操作数从 reg_field 移到 rm_field + rm_field = reg_field; + reg_field = SCC_X86_REG_INVALID; + } + } + // ======================================================================== + int op_width = infer_operand_width(info, ops); LOG_INFO("[OPWIDTH] %d bits", op_width); @@ -446,4 +471,4 @@ int scc_x86_encode_inst(scc_mcode_t *mcode, scc_x86_iform_t iform, } return 0; -} \ No newline at end of file +} diff --git a/libs/sccf/include/sccf.h b/libs/sccf/include/sccf.h index 7df435a..3b2010e 100644 --- a/libs/sccf/include/sccf.h +++ b/libs/sccf/include/sccf.h @@ -72,11 +72,12 @@ typedef enum { SCCF_SECT_RELOCS = 7, ///< 重定位表 } sccf_sect_type_t; -/** 重定位类型 */ +/** 重定位类型 (可以被platform任意修改)在此只提供一个样例模板占位符 */ typedef enum { SCCF_RELOC_TYPE_EMPTY = 0, ///< 空展位符 SCCF_RELOC_TYPE_ABS = 1, ///< 绝对地址 SCCF_RELOC_TYPE_REL = 2, ///< 相对地址 + SCCF_RELOC_TYPE_COUNT = 3, ///< 重定位类型数量 } sccf_reloc_type_t; /** diff --git a/libs/target/sccf2target/include/sccf2pe.h b/libs/target/sccf2target/include/sccf2pe.h index 337c7fb..718272a 100644 --- a/libs/target/sccf2target/include/sccf2pe.h +++ b/libs/target/sccf2target/include/sccf2pe.h @@ -1,4 +1,9 @@ +#ifndef __SCCF2PE_H__ +#define __SCCF2PE_H__ + #include #include void sccf2pe(scc_pe_builder_t *builder, const sccf_t *sccf); + +#endif /* __SCCF2PE_H__ */ diff --git a/libs/target/sccf2target/src/sccf2pe.c b/libs/target/sccf2target/src/sccf2pe.c index ba82982..a343248 100644 --- a/libs/target/sccf2target/src/sccf2pe.c +++ b/libs/target/sccf2target/src/sccf2pe.c @@ -1,6 +1,7 @@ #include #include #include +#include typedef struct { scc_hashtable_t str2libsym; @@ -199,6 +200,10 @@ void sccf2pe(scc_pe_builder_t *builder, const sccf_t *sccf) { .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) { @@ -220,14 +225,16 @@ void sccf2pe(scc_pe_builder_t *builder, const sccf_t *sccf) { } Assert(rva != 0); - if (reloc->reloc_type == SCCF_RELOC_TYPE_ABS) { - TODO(); - } - rva -= code_range.virual_address + reloc->offset + reloc->addend; Assert(code_data != nullptr); - // FIXME 需要确保宿主机与目标机器大小端一致 - *(u32 *)(scc_vec_unsafe_get_data(*code_data) + reloc->offset) = rva; + // FIXME patch type + // if (reloc->reloc_type == SCCF_RELOC_TYPE_ABS) { + // TODO(); + // } + scc_x86_patch(&mcode, SCC_X86_PATCH_PC32, + code_range.virual_address + reloc->offset + reloc->addend, + rva); } + *(scc_mcode_buff_t *)code_data = mcode.code; scc_pe_write_header(builder, &config); if (code_data != nullptr) { diff --git a/src/main.c b/src/main.c index 975a03f..da739d2 100644 --- a/src/main.c +++ b/src/main.c @@ -307,16 +307,16 @@ sstream_drop: 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, &mir_module); + scc_ir2mcode(&mcode, nullptr, &mir_module); if (fp == nullptr) { LOG_WARN("emit flatbin can't write to stdout"); return 0; } - usize ret = scc_fwrite(fp, scc_vec_unsafe_get_data(mcode.mcode), - scc_vec_size(mcode.mcode)); - if (ret != scc_vec_size(mcode.mcode)) { + 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, scc_vec_size(mcode.mcode)); + ret, mcode_size); return 1; } return 0;