Compare commits

...

2 Commits

Author SHA1 Message Date
zzy
45c59e0b65 feat(ast2ir): 添加AST到IR转换功能并完善类型ABI支持
- 添加了ast2ir库用于将AST转换为IR中间表示
- 实现了Windows x64 ABI类型定义文件
- 完善了IR库中的类型定义,添加了无符号整数类型和操作符枚举
- 更新了IR转储功能以支持新的节点类型
- 在主程序中集成了AST到IR的转换流程
- 修改了PE目标文件生成功能以修正节区标志
- 更新了向量实现的日志和错误处理机制

fix(ir): 修复IR库中的操作符枚举和类型处理问题

- 修复了IR操作符枚举的命名空间问题,统一使用SCC_IR前缀
- 添加了无符号整数类型的哈希和比较支持
- 修正了常量整数节点的打印函数调用
- 更新了各种IR节点的转储输出格式
- 删除了测试文件中的冗余代码

refactor: 重构项目依赖配置和构建设置

- 启用了ast2ir和ir库的依赖配置
- 添加了def文件到.gitignore中
- 重命名了部分测试文件
2026-03-15 15:44:50 +08:00
zzy
6ebf0c48e3 feat(pe): 添加PE文件构建器功能
新增PE库的基础设施包括:
- 创建README.md文档,说明代码参考rust cargo的object库实现
- 配置cbuild.toml包依赖,添加scc_utils依赖项
- 定义scc_pe_builder.h头文件,包含PE构建器的数据结构和API函数
- 实现PE文件的段管理、头信息处理和文件写入功能
2026-03-15 11:53:24 +08:00
25 changed files with 1998 additions and 118 deletions

3
.gitignore vendored
View File

@@ -36,3 +36,6 @@ external/
# dot file and svg file
*.dot
*.svg
# dll def or other definition file
*.def

View File

@@ -8,6 +8,6 @@ dependencies = [
{ name = "pproc", path = "./libs/pproc" },
{ name = "parser", path = "./libs/parser" },
{ name = "ast", path = "./libs/ast" },
# { name = "ast2ir", path = "./libs/ast2ir" },
# { name = "ir", path = "./libs/ir" },
{ name = "ast2ir", path = "./libs/ast2ir" },
{ name = "ir", path = "./libs/ir" },
]

View File

@@ -4,6 +4,9 @@ version = "0.1.0"
authors = []
description = ""
# dependencies = []
dependencies = [
{ name = "scc_ast", path = "../ast" },
{ name = "scc_ir", path = "../ir" },
]
# features = {}
# default_features = []

View File

@@ -0,0 +1,141 @@
#ifndef __SCC_WIN_X64_TYPE_ABI_H__
#define __SCC_WIN_X64_TYPE_ABI_H__
#include "../scc_type_abi.h"
/**
* @brief Windows x64 ABI Type
* @details
* https://learn.microsoft.com/zh-cn/cpp/build/x64-software-conventions?view=msvc-180
*/
static const scc_type_abi_t scc_win_x64_type_abi[] = {
{
.ast_type = SCC_AST_BUILTIN_TYPE_UNKNOWN,
.ir_type = SCC_IR_TYPE_UNKNOWN,
.size = 0,
.alignment = 0,
},
{
.ast_type = SCC_AST_BUILTIN_TYPE_VOID,
.ir_type = SCC_IR_TYPE_VOID,
.size = 0,
.alignment = 0,
},
{
.ast_type = SCC_AST_BUILTIN_TYPE_BOOL,
.ir_type = SCC_IR_TYPE_U8,
.size = 1,
.alignment = 1,
},
{
.ast_type = SCC_AST_BUILTIN_TYPE_CHAR,
.ir_type = SCC_IR_TYPE_I8,
.size = 1,
.alignment = 1,
},
{
.ast_type = SCC_AST_BUILTIN_TYPE_SIGNED_CHAR,
.ir_type = SCC_IR_TYPE_I8,
.size = 1,
.alignment = 1,
},
{
.ast_type = SCC_AST_BUILTIN_TYPE_UNSIGNED_CHAR,
.ir_type = SCC_IR_TYPE_U8,
.size = 1,
.alignment = 1,
},
{
.ast_type = SCC_AST_BUILTIN_TYPE_SHORT,
.ir_type = SCC_IR_TYPE_I16,
.size = 2,
.alignment = 2,
},
{
.ast_type = SCC_AST_BUILTIN_TYPE_SIGNED_SHORT,
.ir_type = SCC_IR_TYPE_I16,
.size = 2,
.alignment = 2,
},
{
.ast_type = SCC_AST_BUILTIN_TYPE_UNSIGNED_SHORT,
.ir_type = SCC_IR_TYPE_U16,
.size = 2,
.alignment = 2,
},
{
.ast_type = SCC_AST_BUILTIN_TYPE_INT,
.ir_type = SCC_IR_TYPE_I32,
.size = 4,
.alignment = 4,
},
{
.ast_type = SCC_AST_BUILTIN_TYPE_SIGNED_INT,
.ir_type = SCC_IR_TYPE_I32,
.size = 4,
.alignment = 4,
},
{
.ast_type = SCC_AST_BUILTIN_TYPE_UNSIGNED_INT,
.ir_type = SCC_IR_TYPE_U32,
.size = 4,
.alignment = 4,
},
{
.ast_type = SCC_AST_BUILTIN_TYPE_LONG,
.ir_type = SCC_IR_TYPE_I32,
.size = 4,
.alignment = 4,
},
{
.ast_type = SCC_AST_BUILTIN_TYPE_SIGNED_LONG,
.ir_type = SCC_IR_TYPE_I32,
.size = 4,
.alignment = 4,
},
{
.ast_type = SCC_AST_BUILTIN_TYPE_UNSIGNED_LONG,
.ir_type = SCC_IR_TYPE_U32,
.size = 4,
.alignment = 4,
},
{
.ast_type = SCC_AST_BUILTIN_TYPE_LONG_LONG,
.ir_type = SCC_IR_TYPE_I64,
.size = 8,
.alignment = 8,
},
{
.ast_type = SCC_AST_BUILTIN_TYPE_SIGNED_LONG_LONG,
.ir_type = SCC_IR_TYPE_I64,
.size = 8,
.alignment = 8,
},
{
.ast_type = SCC_AST_BUILTIN_TYPE_UNSIGNED_LONG_LONG,
.ir_type = SCC_IR_TYPE_I64,
.size = 8,
.alignment = 8,
},
{
.ast_type = SCC_AST_BUILTIN_TYPE_FLOAT,
.ir_type = SCC_IR_TYPE_F32,
.size = 4,
.alignment = 4,
},
{
.ast_type = SCC_AST_BUILTIN_TYPE_DOUBLE,
.ir_type = SCC_IR_TYPE_F64,
.size = 8,
.alignment = 8,
},
{
// NULL
.ast_type = SCC_AST_BUILTIN_TYPE_UNKNOWN,
.ir_type = SCC_IR_TYPE_UNKNOWN,
.size = 0,
.alignment = 0,
},
};
#endif /* __SCC_WIN_X64_TYPE_ABI_H__ */

View File

@@ -1,10 +1,12 @@
#ifndef __SCC_AST2IR_H__
#define __SCC_AST2IR_H__
#include <lexer_token.h>
#include "scc_type_abi.h"
#include <scc_ast.h>
#include <scc_ir.h>
void scc_ast2ir(scc_ast_translation_unit_t *tu, scc_ir_builder_t *builder);
void scc_ast2ir_translation_unit(scc_ir_builder_t *builder,
scc_ast_translation_unit_t *tu,
const scc_type_abi_t *abi);
#endif /* __SCC_AST2IR_H__ */

View File

@@ -0,0 +1,14 @@
#ifndef __SCC_TYPE_ABI_H__
#define __SCC_TYPE_ABI_H__
#include <ast_def.h>
#include <ir_def.h>
typedef struct {
scc_ast_builtin_type_t ast_type;
scc_ir_type_tag_t ir_type;
usize size;
usize alignment;
} scc_type_abi_t;
#endif /* __SCC_TYPE_ABI_H__ */

View File

@@ -66,9 +66,11 @@ static scc_ir_type_ref_t ast_type_to_ir_type(scc_ir_builder_t *ctx,
scc_ir_type_ref_vec_t params;
scc_vec_init(params);
scc_vec_foreach(ast_type->function.param_types, i) {
scc_ast_type_t *param_type =
scc_ast_decl_t *decl_param =
scc_vec_at(ast_type->function.param_types, i);
scc_ir_type_ref_t tmp_type = ast_type_to_ir_type(ctx, param_type);
Assert(decl_param->base.type == SCC_AST_DECL_PARAM);
scc_ir_type_ref_t tmp_type =
ast_type_to_ir_type(ctx, decl_param->param.type);
scc_vec_push(params, tmp_type);
}
ir_type.data.function.params = params;
@@ -99,7 +101,8 @@ static scc_ir_node_ref_t ast_expr_to_ir(scc_ir_builder_t *ctx,
}
case SCC_AST_EXPR_INT_LITERAL: {
return scc_ir_ctx_get_i32_const(&ctx->ctx, expr->literal.value.i);
// TODO parse i32 value
return scc_ir_ctx_get_i32_const(&ctx->ctx, 0);
}
case SCC_AST_EXPR_BINARY: {
@@ -112,22 +115,22 @@ static scc_ir_node_ref_t ast_expr_to_ir(scc_ir_builder_t *ctx,
scc_ir_op_type_t op;
switch (expr->binary.op) {
/* clang-format off */
case SCC_AST_OP_ADD: op = IR_OP_ADD; break;
case SCC_AST_OP_SUB: op = IR_OP_SUB; break;
case SCC_AST_OP_MUL: op = IR_OP_MUL; break;
case SCC_AST_OP_DIV: op = IR_OP_DIV; break;
case SCC_AST_OP_MOD: op = IR_OP_MOD; break;
case SCC_AST_OP_LOGICAL_AND: op = IR_OP_AND; break;
case SCC_AST_OP_LOGICAL_OR: op = IR_OP_OR; break;
case SCC_AST_OP_BITWISE_XOR: op = IR_OP_XOR; break;
case SCC_AST_OP_LEFT_SHIFT: op = IR_OP_SHL; break;
case SCC_AST_OP_RIGHT_SHIFT: op = IR_OP_SHR; break;
case SCC_AST_OP_EQUAL: op = IR_OP_EQ; break;
case SCC_AST_OP_NOT_EQUAL: op = IR_OP_NEQ; break;
case SCC_AST_OP_LESS: op = IR_OP_LT; break;
case SCC_AST_OP_LESS_EQUAL: op = IR_OP_LE; break;
case SCC_AST_OP_GREATER: op = IR_OP_GT; break;
case SCC_AST_OP_GREATER_EQUAL: op = IR_OP_GE; break;
case SCC_AST_OP_ADD: op = SCC_IR_OP_ADD; break;
case SCC_AST_OP_SUB: op = SCC_IR_OP_SUB; break;
case SCC_AST_OP_MUL: op = SCC_IR_OP_MUL; break;
case SCC_AST_OP_DIV: op = SCC_IR_OP_DIV; break;
case SCC_AST_OP_MOD: op = SCC_IR_OP_MOD; break;
case SCC_AST_OP_LOGICAL_AND: op = SCC_IR_OP_AND; break;
case SCC_AST_OP_LOGICAL_OR: op = SCC_IR_OP_OR; break;
case SCC_AST_OP_BITWISE_XOR: op = SCC_IR_OP_XOR; break;
case SCC_AST_OP_LEFT_SHIFT: op = SCC_IR_OP_SHL; break;
case SCC_AST_OP_RIGHT_SHIFT: op = SCC_IR_OP_SHR; break;
case SCC_AST_OP_EQUAL: op = SCC_IR_OP_EQ; break;
case SCC_AST_OP_NOT_EQUAL: op = SCC_IR_OP_NEQ; break;
case SCC_AST_OP_LESS: op = SCC_IR_OP_LT; break;
case SCC_AST_OP_LESS_EQUAL: op = SCC_IR_OP_LE; break;
case SCC_AST_OP_GREATER: op = SCC_IR_OP_GT; break;
case SCC_AST_OP_GREATER_EQUAL: op = SCC_IR_OP_GE; break;
case SCC_AST_OP_ASSIGN: {
// 赋值表达式:存储右值到左值位置
return scc_ir_builder_store(ctx, lhs, rhs);
@@ -138,7 +141,7 @@ static scc_ir_node_ref_t ast_expr_to_ir(scc_ir_builder_t *ctx,
/* clang-format on */
default:
LOG_WARN("Unsupported binary operator: %d", expr->binary.op);
op = IR_OP_ADD; // 默认
op = SCC_IR_OP_ADD; // 默认
}
// 创建操作节点
@@ -151,20 +154,21 @@ static scc_ir_node_ref_t ast_expr_to_ir(scc_ir_builder_t *ctx,
// 映射一元操作符
switch (expr->unary.op) {
case SCC_TOK_SUB:
case SCC_AST_OP_SUB:
// 负号
// 实现为0 - operand
return scc_ir_builder_binop(ctx, IR_OP_SUB,
return scc_ir_builder_binop(ctx, SCC_IR_OP_SUB,
scc_ir_ctx_get_builtin_zero(&ctx->ctx),
operand);
case SCC_TOK_BIT_NOT:
case SCC_AST_OP_BITWISE_NOT:
// 按位取反
return scc_ir_builder_binop(ctx, IR_OP_NOT, operand, 0);
case SCC_TOK_NOT:
return scc_ir_builder_binop(ctx, SCC_IR_OP_NOT, operand, 0);
case SCC_AST_OP_LOGICAL_NOT:
// 逻辑非
// 实现为与0比较
return scc_ir_builder_binop(
ctx, IR_OP_EQ, scc_ir_ctx_get_builtin_zero(&ctx->ctx), operand);
return scc_ir_builder_binop(ctx, SCC_IR_OP_EQ,
scc_ir_ctx_get_builtin_zero(&ctx->ctx),
operand);
default:
LOG_WARN("Unsupported unary operator: %d", expr->unary.op);
return 0;
@@ -450,9 +454,9 @@ static void ast_stmt_to_ir(scc_ir_builder_t *ctx, scc_ast_stmt_t *stmt) {
// ast_stmt_to_ir(ctx, stmt->for_stmt.body);
// // 执行迭代表达式(如果存在)
// if (stmt->for_stmt.iter) {
// if (stmt->for_stmt.incr) {
// scc_ir_node_t dummy_node;
// ast_expr_to_ir(ctx, stmt->for_stmt.iter, &dummy_node);
// ast_expr_to_ir(ctx, stmt->for_stmt.incr, &dummy_node);
// }
// // 跳转回条件块
@@ -497,7 +501,7 @@ static void ast_decl_to_ir(scc_ir_builder_t *ctx, scc_ast_decl_t *decl) {
// 创建分配节点
scc_ir_node_ref_t alloc_val_node =
scc_ir_builder_alloca(ctx, ir_type, decl->var.name);
scc_ir_builder_alloca(ctx, ir_type, decl->name);
// 如果有初始化表达式
if (!decl->var.init) {
@@ -518,7 +522,7 @@ static void ast_decl_to_ir(scc_ir_builder_t *ctx, scc_ast_decl_t *decl) {
case SCC_AST_DECL_FUNC: {
// TODO params name
scc_ir_type_ref_t func_type = ast_type_to_ir_type(ctx, decl->func.type);
scc_ir_builder_begin_func(ctx, decl->func.name, func_type, null);
scc_ir_builder_begin_func(ctx, decl->name, func_type, null);
// 处理函数体(如果有)
if (decl->func.body) {
scc_ir_builder_begin_bblock(ctx, "entry");
@@ -535,17 +539,21 @@ static void ast_decl_to_ir(scc_ir_builder_t *ctx, scc_ast_decl_t *decl) {
}
}
// 主转换函数将AST翻译单元转换为IR程序
void scc_ast2ir(scc_ast_translation_unit_t *tu, scc_ir_builder_t *builder) {
/**
* @brief 将AST的翻译单元转换为IR
* @warning 需要初始化builder且保证tu合法
*
* @param builder
* @param tu
*/
void scc_ast2ir_translation_unit(scc_ir_builder_t *builder,
scc_ast_translation_unit_t *tu,
const scc_type_abi_t *abi) {
if (tu == null || builder == null) {
LOG_ERROR("Invalid argument");
return;
}
// 初始化上下文
scc_ir_builder_init(builder);
// 转换所有声明
scc_vec_foreach(tu->declarations, i) {
scc_ast_decl_t *decl = scc_vec_at(tu->declarations, i);
ast_decl_to_ir(builder, decl);

View File

View File

@@ -23,17 +23,26 @@ typedef ir_handle_t scc_ir_func_ref_t;
typedef SCC_VEC(scc_ir_func_ref_t) scc_ir_func_ref_vec_t;
typedef enum scc_ir_type_tag {
SCC_IR_TYPE_UNKNOWN,
SCC_IR_TYPE_VOID,
SCC_IR_TYPE_I1,
SCC_IR_TYPE_I8,
SCC_IR_TYPE_I16,
SCC_IR_TYPE_I32,
SCC_IR_TYPE_I64,
SCC_IR_TYPE_I128,
SCC_IR_TYPE_U8,
SCC_IR_TYPE_U16,
SCC_IR_TYPE_U32,
SCC_IR_TYPE_U64,
SCC_IR_TYPE_U128,
SCC_IR_TYPE_F16,
SCC_IR_TYPE_F32,
SCC_IR_TYPE_F64,
SCC_IR_TYPE_F128,
SCC_IR_TYPE_PTR,
SCC_IR_TYPE_ARRAY,
SCC_IR_TYPE_FUNC,
@@ -76,56 +85,61 @@ struct scc_ir_func {
typedef enum scc_ir_node_tag {
SCC_IR_NODE_NULL,
SCC_IR_NODE_CONST_INT,
SCC_IR_NODE_ALLOC,
SCC_IR_NODE_LOAD,
SCC_IR_NODE_STORE,
SCC_IR_NODE_GET_PTR,
SCC_IR_NODE_OP,
SCC_IR_NODE_BRANCH,
SCC_IR_NODE_JUMP,
SCC_IR_NODE_CALL,
SCC_IR_NODE_RET,
SCC_IR_NODE_CONV, ///< 类型转换
SCC_IR_NODE_FUNC_ARG_REF, ///< 函数参数引用
SCC_IR_NODE_BLOCK_ARG_REF, ///< 基本块参数引用
SCC_IR_NODE_ALLOC, ///< 分配内存(stack)
SCC_IR_NODE_GLOBAL_ALLOC, ///< 全局分配(bss)
SCC_IR_NODE_LOAD, ///< 加载数据
SCC_IR_NODE_STORE, ///< 存储数据
SCC_IR_NODE_GET_PTR, ///< 获取指针
SCC_IR_NODE_GET_ELEM_PTR, ///< 获取元素指针(used by array)
SCC_IR_NODE_OP, ///< 二元运算
SCC_IR_NODE_BRANCH, ///< 有条件分支
SCC_IR_NODE_JUMP, ///< 无条件跳转
SCC_IR_NODE_CALL, ///< 调用函数
SCC_IR_NODE_RET, ///< 函数返回
} scc_ir_node_tag_t;
typedef enum {
/// Empty op for init or nop
IR_OP_EMPTY,
SCC_IR_OP_EMPTY,
/// Not equal to.
IR_OP_NEQ,
SCC_IR_OP_NEQ,
/// Equal to.
IR_OP_EQ,
SCC_IR_OP_EQ,
/// Greater than.
IR_OP_GT,
SCC_IR_OP_GT,
/// Less than.
IR_OP_LT,
SCC_IR_OP_LT,
/// Greater than or equal to.
IR_OP_GE,
SCC_IR_OP_GE,
/// Less than or equal to.
IR_OP_LE,
SCC_IR_OP_LE,
/// Addition.
IR_OP_ADD,
SCC_IR_OP_ADD,
/// Subtraction.
IR_OP_SUB,
SCC_IR_OP_SUB,
/// Multiplication.
IR_OP_MUL,
SCC_IR_OP_MUL,
/// Division.
IR_OP_DIV,
SCC_IR_OP_DIV,
/// Modulo.
IR_OP_MOD,
SCC_IR_OP_MOD,
/// Bitwise AND.
IR_OP_AND,
SCC_IR_OP_AND,
/// Bitwise OR.
IR_OP_OR,
SCC_IR_OP_OR,
/// Bitwise XOR.
IR_OP_XOR,
SCC_IR_OP_XOR,
/// Bitwise NOT.
IR_OP_NOT,
SCC_IR_OP_NOT,
/// Shift left logical.
IR_OP_SHL,
SCC_IR_OP_SHL,
/// Shift right logical.
IR_OP_SHR,
SCC_IR_OP_SHR,
/// Shift right arithmetic.
IR_OP_SAR,
SCC_IR_OP_SAR,
} scc_ir_op_type_t;
struct scc_ir_node {
@@ -151,9 +165,17 @@ struct scc_ir_node {
u8 uint_any[16];
} const_uint;
// aggregate;
// func_arg_ref;
// block_arg_ref;
// global_alloc;
struct {
usize idx;
} arg_ref;
struct {
scc_ir_node_ref_vec_t elements;
} global_alloc;
struct {
scc_ir_node_ref_t operand;
scc_ir_type_ref_t target_type; // 目标类型
enum { CONV_SEXT, CONV_ZEXT, CONV_TRUNC } conv_type;
} conv;
struct {
scc_ir_node_ref_t target;
} load;

View File

@@ -70,7 +70,7 @@ void scc_ir_node_init(scc_ir_node_t *in, const char *name,
in->data.get_ptr.index = 0;
break;
case SCC_IR_NODE_OP:
in->data.op.op = IR_OP_EMPTY;
in->data.op.op = SCC_IR_OP_EMPTY;
in->data.op.lhs = 0;
in->data.op.rhs = 0;
break;

View File

@@ -7,4 +7,4 @@ scc_ir_type_t scc_ir_builtin_i32 = {
scc_ir_node_t scc_ir_builtin_zero = {
.tag = SCC_IR_NODE_CONST_INT,
.data.const_int.int_any = {0},
};
};

View File

@@ -22,7 +22,11 @@ static u32 hash_type(const scc_ir_type_t *key) {
switch (key->tag) {
case SCC_IR_TYPE_VOID:
case SCC_IR_TYPE_I1:
case SCC_IR_TYPE_U8:
case SCC_IR_TYPE_U16:
case SCC_IR_TYPE_U32:
case SCC_IR_TYPE_U64:
case SCC_IR_TYPE_U128:
case SCC_IR_TYPE_I8:
case SCC_IR_TYPE_I16:
case SCC_IR_TYPE_I32:
@@ -70,7 +74,11 @@ static int cmp_type(const scc_ir_type_t *key1, const scc_ir_type_t *key2) {
switch (key1->tag) {
case SCC_IR_TYPE_VOID:
case SCC_IR_TYPE_I1:
case SCC_IR_TYPE_U8:
case SCC_IR_TYPE_U16:
case SCC_IR_TYPE_U32:
case SCC_IR_TYPE_U64:
case SCC_IR_TYPE_U128:
case SCC_IR_TYPE_I8:
case SCC_IR_TYPE_I16:
case SCC_IR_TYPE_I32:

View File

@@ -31,13 +31,16 @@ static const char *get_node_type_str(scc_ir_node_tag_t tag) {
// 获取操作符字符串
static const char *get_op_str(scc_ir_op_type_t op) {
static const char *ops[] = {
[IR_OP_EMPTY] = "empty", [IR_OP_NEQ] = "!=", [IR_OP_EQ] = "==",
[IR_OP_GT] = ">", [IR_OP_LT] = "<", [IR_OP_GE] = ">=",
[IR_OP_LE] = "<=", [IR_OP_ADD] = "+", [IR_OP_SUB] = "-",
[IR_OP_MUL] = "*", [IR_OP_DIV] = "/", [IR_OP_MOD] = "%",
[IR_OP_AND] = "&", [IR_OP_OR] = "|", [IR_OP_XOR] = "^",
[IR_OP_NOT] = "~", [IR_OP_SHL] = "<<", [IR_OP_SHR] = ">>",
[IR_OP_SAR] = ">>a", // Arithmetic shift right
[SCC_IR_OP_EMPTY] = "empty", [SCC_IR_OP_NEQ] = "!=",
[SCC_IR_OP_EQ] = "==", [SCC_IR_OP_GT] = ">",
[SCC_IR_OP_LT] = "<", [SCC_IR_OP_GE] = ">=",
[SCC_IR_OP_LE] = "<=", [SCC_IR_OP_ADD] = "+",
[SCC_IR_OP_SUB] = "-", [SCC_IR_OP_MUL] = "*",
[SCC_IR_OP_DIV] = "/", [SCC_IR_OP_MOD] = "%",
[SCC_IR_OP_AND] = "&", [SCC_IR_OP_OR] = "|",
[SCC_IR_OP_XOR] = "^", [SCC_IR_OP_NOT] = "~",
[SCC_IR_OP_SHL] = "<<", [SCC_IR_OP_SHR] = ">>",
[SCC_IR_OP_SAR] = ">>a", // Arithmetic shift right
};
if (op >= 0 && op < sizeof(ops) / sizeof(ops[0]) && ops[op] != NULL) {
@@ -49,7 +52,9 @@ static const char *get_op_str(scc_ir_op_type_t op) {
// 获取类型标签字符串
static const char *get_type_tag_str(scc_ir_type_tag_t tag) {
static const char *type_tags[] = {
[SCC_IR_TYPE_VOID] = "void", [SCC_IR_TYPE_I1] = "i1",
[SCC_IR_TYPE_VOID] = "void", [SCC_IR_TYPE_U8] = "u8",
[SCC_IR_TYPE_U16] = "u16", [SCC_IR_TYPE_U32] = "u32",
[SCC_IR_TYPE_U64] = "u64", [SCC_IR_TYPE_U128] = "u128",
[SCC_IR_TYPE_I8] = "i8", [SCC_IR_TYPE_I16] = "i16",
[SCC_IR_TYPE_I32] = "i32", [SCC_IR_TYPE_I64] = "i64",
[SCC_IR_TYPE_I128] = "i128", [SCC_IR_TYPE_F16] = "f16",
@@ -82,7 +87,7 @@ static void dump_const_int_node(scc_ir_dump_ctx_t *ctx,
const scc_ir_node_t *node) {
scc_tree_dump_push_level(ctx->dump_ctx, true);
scc_tree_print_indent(ctx->dump_ctx);
scc_printf("%d\n", node->data.const_int.int32);
scc_tree_dump_printf(ctx->dump_ctx, "%d\n", node->data.const_int.int32);
scc_tree_dump_pop_level(ctx->dump_ctx);
}
@@ -189,13 +194,14 @@ static void dump_jump_node(scc_ir_dump_ctx_t *ctx, const scc_ir_node_t *node) {
scc_ir_bblock_t *target_bblock =
scc_ir_ctx_get_bblock(ctx->ir_ctx, node->data.jump.target_bblock);
if (target_bblock) {
scc_printf("to '%s'", target_bblock->label ? target_bblock->label
: "<unnamed>");
scc_tree_dump_printf(ctx->dump_ctx, "to '%s'",
target_bblock->label ? target_bblock->label
: "<unnamed>");
} else {
scc_printf("to invalid block");
scc_tree_dump_printf(ctx->dump_ctx, "to invalid block");
}
} else {
scc_printf("to NULL");
scc_tree_dump_printf(ctx->dump_ctx, "to NULL");
}
}
@@ -206,16 +212,17 @@ static void dump_call_node(scc_ir_dump_ctx_t *ctx, const scc_ir_node_t *node) {
scc_ir_func_t *callee =
scc_ir_ctx_get_func(ctx->ir_ctx, node->data.call.callee);
if (callee) {
scc_printf("func='%s'", callee->name ? callee->name : "<unnamed>");
scc_tree_dump_printf(ctx->dump_ctx, "func='%s'",
callee->name ? callee->name : "<unnamed>");
} else {
scc_printf("func=<invalid>");
scc_tree_dump_printf(ctx->dump_ctx, "func=<invalid>");
}
} else {
scc_printf("func=NULL");
scc_tree_dump_printf(ctx->dump_ctx, "func=NULL");
}
if (scc_vec_size(node->data.call.args) > 0) {
scc_printf("\n");
scc_tree_dump_printf(ctx->dump_ctx, "\n");
}
// 输出参数
@@ -261,14 +268,14 @@ void scc_ir_dump_node(scc_ir_dump_ctx_t *ctx, scc_ir_node_ref_t node_ref) {
}
if (node->type) {
scc_printf(" : ");
scc_tree_dump_printf(ctx->dump_ctx, " : ");
scc_ir_type_t *type = scc_ir_ctx_get_type(ctx->ir_ctx, node->type);
if (type) {
PRINT_VALUE(ctx->dump_ctx, "%s", get_type_tag_str(type->tag));
}
}
scc_printf("\n");
scc_tree_dump_printf(ctx->dump_ctx, "\n");
// 根据节点类型输出特定信息
switch (node->tag) {
@@ -305,7 +312,7 @@ void scc_ir_dump_node(scc_ir_dump_ctx_t *ctx, scc_ir_node_ref_t node_ref) {
break;
default:
PRINT_QUOTED_VALUE(ctx->dump_ctx, "unknown");
scc_printf("tag(%d)", node->tag);
scc_tree_dump_printf(ctx->dump_ctx, "tag(%d)", node->tag);
break;
}
}
@@ -325,7 +332,7 @@ void scc_ir_dump_type(scc_ir_dump_ctx_t *ctx, scc_ir_type_ref_t type_ref) {
scc_tree_print_indent(ctx->dump_ctx);
PRINT_NODE(ctx->dump_ctx, "Type: ");
PRINT_QUOTED_VALUE(ctx->dump_ctx, get_type_tag_str(type->tag));
scc_printf("\n");
scc_tree_dump_printf(ctx->dump_ctx, "\n");
// 递归转储子类型
switch (type->tag) {
@@ -398,7 +405,7 @@ void scc_ir_dump_bblock(scc_ir_dump_ctx_t *ctx,
PRINT_NODE(ctx->dump_ctx, "BasicBlock: ");
PRINT_QUOTED_VALUE(ctx->dump_ctx,
bblock->label ? bblock->label : "<unnamed>");
scc_printf("\n");
scc_tree_dump_printf(ctx->dump_ctx, "\n");
// 转储基本块中的指令
for (usize i = 0; i < scc_vec_size(bblock->instrs); i++) {
@@ -422,7 +429,7 @@ void scc_ir_dump_func(scc_ir_dump_ctx_t *ctx, scc_ir_func_ref_t func_ref) {
scc_tree_print_indent(ctx->dump_ctx);
PRINT_NODE(ctx->dump_ctx, "Function: ");
PRINT_QUOTED_VALUE(ctx->dump_ctx, func->name ? func->name : "<unnamed>");
scc_printf("\n");
scc_tree_dump_printf(ctx->dump_ctx, "\n");
// 输出函数类型
if (func->type) {
@@ -546,6 +553,7 @@ void scc_ir_dump_type_linear(scc_ir_dump_ctx_t *ctx,
} else {
PRINT_TYPE(ctx->dump_ctx, ")");
}
break;
default:
LOG_ERROR("invalid type tag");
break;

4
libs/target/pe/README.md Normal file
View File

@@ -0,0 +1,4 @@
代码参考了 rust cargo 里面的 object = { version = "0.38.0", features = ["all"] } 库的实现
并且从 winnt.h (10.0.17763.0) 里面获取头文件结构但是修改了部分原始结构以适配当前环境

View File

@@ -0,0 +1,9 @@
[package]
name = "scc_pe"
version = "0.1.0"
authors = []
description = ""
dependencies = [{ name = "scc_utils", path = "../../../runtime/scc_utils" }]
# features = {}
# default_features = []

View File

@@ -0,0 +1,80 @@
#ifndef __SCC_WINPE_H__
#define __SCC_WINPE_H__
#include "scc_pe_def.h"
typedef SCC_VEC(IMAGE_DATA_DIRECTORY) scc_winpe_image_data_directory_vec_t;
typedef SCC_VEC(IMAGE_SECTION_HEADER) scc_winpe_image_section_header_vec_t;
/**
* @brief
*
*/
typedef struct {
scc_pe_buffer_t buffer; ///< 镜像文件(File Data)数据
u32 section_alignment; ///< 文件镜像(Virtual Address)各个段的对齐方式
u32 file_alignment; ///< PE文件内(File Adderss)各个段对齐方式
u32 baseof_code; ///< 代码段基地址(Virtual Address)
u32 sizeof_code; ///< 代码段大小
u32 baseof_data; ///< 数据段基地址(Virtual Address)
u32 sizeof_init_data; ///< 初始化数据段大小
u32 sizeof_uninit_data; ///< 未初始化数据段大小
u32 file_offset; ///< 内部使用变量,用于追踪文件内偏移地址
u32 virtual_offset; ///< 内部使用变量,用于追踪镜像内偏移地址
u32 nt_headers_offset; ///< 内部使用变量,用于追踪NT头偏移地址
u32 sizeof_headers; ///< 内部使用变量,用于追踪完整镜像头大小
scc_winpe_image_data_directory_vec_t image_data_directory_vec;
scc_winpe_image_section_header_vec_t image_section_header_vec;
u16 section_header_num;
u32 symbol_offset;
u32 symbol_num;
cbool is_64;
} scc_pe_builder_t;
typedef struct {
u16 machine;
u32 time_date_stamp;
u16 characteristics;
u8 major_linker_version;
u8 minor_linker_version;
u32 address_of_entry_point;
u64 image_base;
u16 major_operating_system_version;
u16 minor_operating_system_version;
u16 major_image_version;
u16 minor_image_version;
u16 major_subsystem_version;
u16 minor_subsystem_version;
u16 subsystem;
u16 dll_characteristics;
u64 size_of_stack_reserve;
u64 size_of_stack_commit;
u64 size_of_heap_reserve;
u64 size_of_heap_commit;
} scc_pe_config_t;
void scc_pe_builder_init(scc_pe_builder_t *builder, bool is_64,
u32 section_alignment, u32 file_alignment);
void scc_pe_reserve_header(scc_pe_builder_t *builder, u32 num_of_section);
scc_pe_section_range scc_pe_reserve_section_header(scc_pe_builder_t *builder,
BYTE name[8],
u32 characteristics,
u32 virtual_size,
u32 data_size);
void scc_pe_write_header(scc_pe_builder_t *builder, scc_pe_config_t *config);
void scc_pe_write_section(scc_pe_builder_t *builder,
scc_pe_section_range *range, u8 *data,
usize data_size);
void scc_pe_dump_to_file(scc_pe_builder_t *builder, const char *file_path);
#endif /* __SCC_WINPE_H__ */

View File

@@ -0,0 +1,848 @@
/**
* @brief pe.h - PE/COFF 结构定义头文件
* 基于 winnt.h (10.0.17763.0) 和 object-0.38.0/src/pe.rs
*/
#ifndef __SCC_PE_DEF_H__
#define __SCC_PE_DEF_H__
// #include <winnt.h>
#include <scc_core.h>
// FIXME
/**
* @brief DUMMYUNIONNAME会在被支持空联合体名称的编译器中定义为空,
* 从而导致bug,所以自行定义
*
* @bug 可以有更好的方式解决这个问题
*/
#define DUMMYUNIONNAME DUMMYUNIONNAME
// 基本类型定义
typedef u8 BYTE;
typedef u16 WORD;
typedef u32 DWORD;
typedef u64 QWORD;
typedef i8 CHAR;
typedef i16 SHORT;
typedef i32 LONG;
typedef i64 LONGLONG;
typedef DWORD PBYTE; // TODO ?
#ifndef UNALIGNED
#define UNALIGNED
#endif
// 常量定义
#define IMAGE_DOS_SIGNATURE 0x5A4D // "MZ"
#define IMAGE_OS2_SIGNATURE 0x454E // "NE"
#define IMAGE_OS2_SIGNATURE_LE 0x454C // "LE"
#define IMAGE_VXD_SIGNATURE 0x454C // "LE"
#define IMAGE_NT_SIGNATURE 0x00004550 // "PE\0\0"
// DOS 头部结构
typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header
WORD e_magic; // Magic number
WORD e_cblp; // Bytes on last page of file
WORD e_cp; // Pages in file
WORD e_crlc; // Relocations
WORD e_cparhdr; // Size of header in paragraphs
WORD e_minalloc; // Minimum extra paragraphs needed
WORD e_maxalloc; // Maximum extra paragraphs needed
WORD e_ss; // Initial (relative) SS value
WORD e_sp; // Initial SP value
WORD e_csum; // Checksum
WORD e_ip; // Initial IP value
WORD e_cs; // Initial (relative) CS value
WORD e_lfarlc; // File address of relocation table
WORD e_ovno; // Overlay number
WORD e_res[4]; // Reserved words
WORD e_oemid; // OEM identifier (for e_oeminfo)
WORD e_oeminfo; // OEM information; e_oemid specific
WORD e_res2[10]; // Reserved words
DWORD e_lfanew; // File address of new exe header
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
// NT 头部标志
#define IMAGE_FILE_RELOCS_STRIPPED 0x0001 // Relocation info stripped from file.
#define IMAGE_FILE_EXECUTABLE_IMAGE \
0x0002 // File is executable (i.e. no unresolved external references).
#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 // Line numbers stripped from file.
#define IMAGE_FILE_LOCAL_SYMS_STRIPPED \
0x0008 // Local symbols stripped from file.
#define IMAGE_FILE_AGGRESIVE_WS_TRIM 0x0010 // Aggressively trim working set
#define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020 // App can handle >2gb addresses
#define IMAGE_FILE_BYTES_REVERSED_LO \
0x0080 // Bytes of machine word are reversed.
#define IMAGE_FILE_32BIT_MACHINE 0x0100 // 32 bit word machine.
#define IMAGE_FILE_DEBUG_STRIPPED \
0x0200 // Debugging info stripped from file in .DBG file
#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP \
0x0400 // If Image is on removable media, copy and run from the swap file.
#define IMAGE_FILE_NET_RUN_FROM_SWAP \
0x0800 // If Image is on Net, copy and run from the swap file.
#define IMAGE_FILE_SYSTEM 0x1000 // System File.
#define IMAGE_FILE_DLL 0x2000 // File is a DLL.
#define IMAGE_FILE_UP_SYSTEM_ONLY \
0x4000 // File should only be run on a UP machine
#define IMAGE_FILE_BYTES_REVERSED_HI \
0x8000 // Bytes of machine word are reversed.
// 机器类型定义
#define IMAGE_FILE_MACHINE_UNKNOWN 0x0000 // Unknown
#define IMAGE_FILE_MACHINE_TARGET_HOST \
0x0001 // Useful for indicating we want to interact with the host and not a
// WoW guest.
#define IMAGE_FILE_MACHINE_I386 0x014c // Intel 386.
#define IMAGE_FILE_MACHINE_R3000 0x0162 // MIPS little-endian, 0x160 big-endian
#define IMAGE_FILE_MACHINE_R4000 0x0166 // MIPS little-endian
#define IMAGE_FILE_MACHINE_R10000 0x0168 // MIPS little-endian
#define IMAGE_FILE_MACHINE_WCEMIPSV2 0x0169 // MIPS little-endian WCE v2
#define IMAGE_FILE_MACHINE_ALPHA 0x0184 // Alpha_AXP
#define IMAGE_FILE_MACHINE_SH3 0x01a2 // SH3 little-endian
#define IMAGE_FILE_MACHINE_SH3DSP 0x01a3 // SH3 DSP
#define IMAGE_FILE_MACHINE_SH3E 0x01a4 // SH3E little-endian
#define IMAGE_FILE_MACHINE_SH4 0x01a6 // SH4 little-endian
#define IMAGE_FILE_MACHINE_SH5 0x01a8 // SH5
#define IMAGE_FILE_MACHINE_ARM 0x01c0 // ARM Little-Endian
#define IMAGE_FILE_MACHINE_THUMB 0x01c2 // ARM Thumb/Thumb-2 Little-Endian
#define IMAGE_FILE_MACHINE_ARMNT 0x01c4 // ARM Thumb-2 Little-Endian
#define IMAGE_FILE_MACHINE_AM33 0x01d3 // Matsushita AM33
#define IMAGE_FILE_MACHINE_POWERPC 0x01F0 // IBM PowerPC Little-Endian
#define IMAGE_FILE_MACHINE_POWERPCFP 0x01f1 // IBM PowerPC FP
#define IMAGE_FILE_MACHINE_IA64 0x0200 // Intel 64
#define IMAGE_FILE_MACHINE_MIPS16 0x0266 // MIPS
#define IMAGE_FILE_MACHINE_ALPHA64 0x0284 // ALPHA64
#define IMAGE_FILE_MACHINE_MIPSFPU 0x0366 // MIPS
#define IMAGE_FILE_MACHINE_MIPSFPU16 0x0466 // MIPS
#define IMAGE_FILE_MACHINE_AXP64 IMAGE_FILE_MACHINE_ALPHA64
#define IMAGE_FILE_MACHINE_TRICORE 0x0520 // Infineon
#define IMAGE_FILE_MACHINE_CEF 0x0CEF // EFI Byte Code
#define IMAGE_FILE_MACHINE_EBC 0x0EBC // EFI Byte Code
#define IMAGE_FILE_MACHINE_AMD64 0x8664 // AMD64 (K8)
#define IMAGE_FILE_MACHINE_M32R 0x9041 // M32R little-endian
#define IMAGE_FILE_MACHINE_ARM64 0xAA64 // ARM64 Little-Endian
#define IMAGE_FILE_MACHINE_CEE 0xC0EE
// 文件头结构
#define IMAGE_SIZEOF_FILE_HEADER 20
typedef struct _IMAGE_FILE_HEADER {
WORD Machine;
WORD NumberOfSections;
DWORD TimeDateStamp;
DWORD PointerToSymbolTable;
DWORD NumberOfSymbols;
WORD SizeOfOptionalHeader;
WORD Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
// 数据目录结构
#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
typedef struct _IMAGE_DATA_DIRECTORY {
DWORD VirtualAddress;
DWORD Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
// 可选头部魔数
#define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b
#define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b
#define IMAGE_ROM_OPTIONAL_HDR_MAGIC 0x107
// 可选头部结构 (32位)
typedef struct _IMAGE_OPTIONAL_HEADER32 {
//
// 标准域
//
WORD Magic;
BYTE MajorLinkerVersion;
BYTE MinorLinkerVersion;
DWORD SizeOfCode;
DWORD SizeOfInitializedData;
DWORD SizeOfUninitializedData;
DWORD AddressOfEntryPoint;
DWORD BaseOfCode;
DWORD BaseOfData;
//
// NT 附加域
//
DWORD ImageBase;
DWORD SectionAlignment;
DWORD FileAlignment;
WORD MajorOperatingSystemVersion;
WORD MinorOperatingSystemVersion;
WORD MajorImageVersion;
WORD MinorImageVersion;
WORD MajorSubsystemVersion;
WORD MinorSubsystemVersion;
DWORD Win32VersionValue;
DWORD SizeOfImage;
DWORD SizeOfHeaders;
DWORD CheckSum;
WORD Subsystem;
WORD DllCharacteristics;
DWORD SizeOfStackReserve;
DWORD SizeOfStackCommit;
DWORD SizeOfHeapReserve;
DWORD SizeOfHeapCommit;
DWORD LoaderFlags;
DWORD NumberOfRvaAndSizes;
// IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
// 可选头部结构 (64位)
typedef struct _IMAGE_OPTIONAL_HEADER64 {
WORD Magic;
BYTE MajorLinkerVersion;
BYTE MinorLinkerVersion;
DWORD SizeOfCode;
DWORD SizeOfInitializedData;
DWORD SizeOfUninitializedData;
DWORD AddressOfEntryPoint;
DWORD BaseOfCode;
QWORD ImageBase;
DWORD SectionAlignment;
DWORD FileAlignment;
WORD MajorOperatingSystemVersion;
WORD MinorOperatingSystemVersion;
WORD MajorImageVersion;
WORD MinorImageVersion;
WORD MajorSubsystemVersion;
WORD MinorSubsystemVersion;
DWORD Win32VersionValue;
DWORD SizeOfImage;
DWORD SizeOfHeaders;
DWORD CheckSum;
WORD Subsystem;
WORD DllCharacteristics;
QWORD SizeOfStackReserve;
QWORD SizeOfStackCommit;
QWORD SizeOfHeapReserve;
QWORD SizeOfHeapCommit;
DWORD LoaderFlags;
DWORD NumberOfRvaAndSizes;
// IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64;
// NT 头部结构 (32位)
typedef struct _IMAGE_NT_HEADERS32 {
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
// NT 头部结构 (64位)
typedef struct _IMAGE_NT_HEADERS64 {
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER64 OptionalHeader;
} IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64;
#ifdef _WIN64
typedef IMAGE_NT_HEADERS64 IMAGE_NT_HEADERS;
typedef PIMAGE_NT_HEADERS64 PIMAGE_NT_HEADERS;
#else
typedef IMAGE_NT_HEADERS32 IMAGE_NT_HEADERS;
typedef PIMAGE_NT_HEADERS32 PIMAGE_NT_HEADERS;
#endif
// 子系统类型
#define IMAGE_SUBSYSTEM_UNKNOWN 0 // Unknown subsystem.
#define IMAGE_SUBSYSTEM_NATIVE 1 // Image doesn't require a subsystem.
#define IMAGE_SUBSYSTEM_WINDOWS_GUI \
2 // Image runs in the Windows GUI subsystem.
#define IMAGE_SUBSYSTEM_WINDOWS_CUI \
3 // Image runs in the Windows character subsystem.
#define IMAGE_SUBSYSTEM_OS2_CUI 5 // image runs in the OS/2 character subsystem.
#define IMAGE_SUBSYSTEM_POSIX_CUI \
7 // image runs in the Posix character subsystem.
#define IMAGE_SUBSYSTEM_NATIVE_WINDOWS 8 // image is a native Win9x driver.
#define IMAGE_SUBSYSTEM_WINDOWS_CE_GUI \
9 // Image runs in the Windows CE subsystem.
#define IMAGE_SUBSYSTEM_EFI_APPLICATION 10 // Image runs as an EFI application.
#define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER \
11 // Image runs as an EFI boot service driver.
#define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER \
12 // Image runs as an EFI runtime driver.
#define IMAGE_SUBSYSTEM_EFI_ROM 13 // Image is an EFI ROM image.
#define IMAGE_SUBSYSTEM_XBOX 14 // Image runs in an Xbox environment.
#define IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION 16 // Boot application.
// DLL 特性
#define IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA \
0x0020 // Image can handle a high entropy 64-bit virtual address space.
#define IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE 0x0040 // DLL can move.
#define IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY 0x0080 // Code Integrity Image
#define IMAGE_DLLCHARACTERISTICS_NX_COMPAT 0x0100 // Image is NX compatible
#define IMAGE_DLLCHARACTERISTICS_NO_ISOLATION \
0x0200 // Image understands isolation and doesn't want it
#define IMAGE_DLLCHARACTERISTICS_NO_SEH \
0x0400 // Image does not use SEH. No SE handler may reside in this image
#define IMAGE_DLLCHARACTERISTICS_NO_BIND 0x0800 // Do not bind this image.
#define IMAGE_DLLCHARACTERISTICS_APPCONTAINER \
0x1000 // Image should execute in an AppContainer
#define IMAGE_DLLCHARACTERISTICS_WDM_DRIVER 0x2000 // Driver uses WDM model
#define IMAGE_DLLCHARACTERISTICS_GUARD_CF \
0x4000 // Image supports Control Flow Guard.
#define IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE 0x8000
// 数据目录索引
#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 // Export Directory
#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 // Import Directory
#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 // Resource Directory
#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 // Exception Directory
#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 // Security Directory
#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 // Base Relocation Table
#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 // Debug Directory
#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7 // Architecture Specific Data
#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 // RVA of GP
#define IMAGE_DIRECTORY_ENTRY_TLS 9 // TLS Directory
#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 // Load Configuration Directory
#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT \
11 // Bound Import Directory in headers
#define IMAGE_DIRECTORY_ENTRY_IAT 12 // Import Address Table
#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 // Delay Load Import Descriptors
#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 // COM Runtime descriptor
// 节头大小
#define IMAGE_SIZEOF_SHORT_NAME 8
#define IMAGE_SIZEOF_SECTION_HEADER 40
// 节头部结构
typedef struct _IMAGE_SECTION_HEADER {
BYTE Name[IMAGE_SIZEOF_SHORT_NAME];
union {
DWORD PhysicalAddress;
DWORD VirtualSize;
} Misc;
DWORD VirtualAddress;
DWORD SizeOfRawData;
DWORD PointerToRawData;
DWORD PointerToRelocations;
DWORD PointerToLinenumbers;
WORD NumberOfRelocations;
WORD NumberOfLinenumbers;
DWORD Characteristics;
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
// 节特性标志
#define IMAGE_SCN_TYPE_NO_PAD 0x00000008 // Reserved.
#define IMAGE_SCN_CNT_CODE 0x00000020 // Section contains code.
#define IMAGE_SCN_CNT_INITIALIZED_DATA \
0x00000040 // Section contains initialized data.
#define IMAGE_SCN_CNT_UNINITIALIZED_DATA \
0x00000080 // Section contains uninitialized data.
#define IMAGE_SCN_LNK_OTHER 0x00000100 // Reserved.
#define IMAGE_SCN_LNK_INFO \
0x00000200 // Section contains comments or some other type of information.
#define IMAGE_SCN_LNK_REMOVE \
0x00000800 // Section contents will not become part of image.
#define IMAGE_SCN_LNK_COMDAT 0x00001000 // Section contents comdat.
#define IMAGE_SCN_NO_DEFER_SPEC_EXC \
0x00004000 // Reset speculative exceptions handling bits in the TLB entries
// for this section.
#define IMAGE_SCN_GPREL \
0x00008000 // Section content can be accessed relative to GP
#define IMAGE_SCN_MEM_FARDATA 0x00008000
#define IMAGE_SCN_MEM_PURGEABLE 0x00020000
#define IMAGE_SCN_MEM_16BIT 0x00020000
#define IMAGE_SCN_MEM_LOCKED 0x00040000
#define IMAGE_SCN_MEM_PRELOAD 0x00080000
#define IMAGE_SCN_ALIGN_1BYTES 0x00100000 //
#define IMAGE_SCN_ALIGN_2BYTES 0x00200000 //
#define IMAGE_SCN_ALIGN_4BYTES 0x00300000 //
#define IMAGE_SCN_ALIGN_8BYTES 0x00400000 //
#define IMAGE_SCN_ALIGN_16BYTES \
0x00500000 // Default alignment if no others are specified.
#define IMAGE_SCN_ALIGN_32BYTES 0x00600000 //
#define IMAGE_SCN_ALIGN_64BYTES 0x00700000 //
#define IMAGE_SCN_ALIGN_128BYTES 0x00800000 //
#define IMAGE_SCN_ALIGN_256BYTES 0x00900000 //
#define IMAGE_SCN_ALIGN_512BYTES 0x00A00000 //
#define IMAGE_SCN_ALIGN_1024BYTES 0x00B00000 //
#define IMAGE_SCN_ALIGN_2048BYTES 0x00C00000 //
#define IMAGE_SCN_ALIGN_4096BYTES 0x00D00000 //
#define IMAGE_SCN_ALIGN_8192BYTES 0x00E00000 //
#define IMAGE_SCN_ALIGN_MASK 0x00F00000
#define IMAGE_SCN_LNK_NRELOC_OVFL \
0x01000000 // Section contains extended relocations.
#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 // Section can be discarded.
#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 // Section is not cacheable.
#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 // Section is not pageable.
#define IMAGE_SCN_MEM_SHARED 0x10000000 // Section is shareable.
#define IMAGE_SCN_MEM_EXECUTE 0x20000000 // Section is executable.
#define IMAGE_SCN_MEM_READ 0x40000000 // Section is readable.
#define IMAGE_SCN_MEM_WRITE 0x80000000 // Section is writeable.
// 导入表相关
typedef struct _IMAGE_IMPORT_DESCRIPTOR {
union {
DWORD Characteristics; // 0 for terminating null import descriptor
DWORD OriginalFirstThunk; // RVA to original unbound IAT
// (PIMAGE_THUNK_DATA)
} DUMMYUNIONNAME;
DWORD TimeDateStamp; // 0 if not bound,
// -1 if bound, and real date\time stamp
// in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND)
// O.W. date/time stamp of DLL bound to (Old BIND)
DWORD ForwarderChain; // -1 if no forwarders
DWORD Name;
DWORD FirstThunk; // RVA to IAT (if bound this IAT has actual addresses)
} IMAGE_IMPORT_DESCRIPTOR;
typedef IMAGE_IMPORT_DESCRIPTOR UNALIGNED *PIMAGE_IMPORT_DESCRIPTOR;
// Thunk 数据结构
typedef struct _IMAGE_THUNK_DATA32 {
union {
DWORD ForwarderString; // PBYTE
DWORD Function; // PDWORD
DWORD Ordinal;
DWORD AddressOfData; // PIMAGE_IMPORT_BY_NAME
} u1;
} IMAGE_THUNK_DATA32;
typedef IMAGE_THUNK_DATA32 *PIMAGE_THUNK_DATA32;
typedef struct _IMAGE_THUNK_DATA64 {
union {
QWORD ForwarderString; // PBYTE
QWORD Function; // PDWORD
QWORD Ordinal;
QWORD AddressOfData; // PIMAGE_IMPORT_BY_NAME
} u1;
} IMAGE_THUNK_DATA64;
typedef IMAGE_THUNK_DATA64 *PIMAGE_THUNK_DATA64;
// 导入名称结构
typedef struct _IMAGE_IMPORT_BY_NAME {
WORD Hint;
BYTE Name[1];
} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;
// 导出表结构
typedef struct _IMAGE_EXPORT_DIRECTORY {
DWORD Characteristics;
DWORD TimeDateStamp;
WORD MajorVersion;
WORD MinorVersion;
DWORD Name;
DWORD Base;
DWORD NumberOfFunctions;
DWORD NumberOfNames;
DWORD AddressOfFunctions; // RVA from base of image
DWORD AddressOfNames; // RVA from base of image
DWORD AddressOfNameOrdinals; // RVA from base of image
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
// 基址重定位结构
#define IMAGE_SIZEOF_BASE_RELOCATION 8
typedef struct _IMAGE_BASE_RELOCATION {
DWORD VirtualAddress;
DWORD SizeOfBlock;
// WORD TypeOffset[1];
} IMAGE_BASE_RELOCATION;
typedef IMAGE_BASE_RELOCATION UNALIGNED *PIMAGE_BASE_RELOCATION;
// 基址重定位类型
#define IMAGE_REL_BASED_ABSOLUTE 0
#define IMAGE_REL_BASED_HIGH 1
#define IMAGE_REL_BASED_LOW 2
#define IMAGE_REL_BASED_HIGHLOW 3
#define IMAGE_REL_BASED_HIGHADJ 4
#define IMAGE_REL_BASED_MACHINE_SPECIFIC_5 5
#define IMAGE_REL_BASED_RESERVED 6
#define IMAGE_REL_BASED_MACHINE_SPECIFIC_7 7
#define IMAGE_REL_BASED_MACHINE_SPECIFIC_8 8
#define IMAGE_REL_BASED_MACHINE_SPECIFIC_9 9
#define IMAGE_REL_BASED_DIR64 10
// 调试目录结构
typedef struct _IMAGE_DEBUG_DIRECTORY {
DWORD Characteristics;
DWORD TimeDateStamp;
WORD MajorVersion;
WORD MinorVersion;
DWORD Type;
DWORD SizeOfData;
DWORD AddressOfRawData;
DWORD PointerToRawData;
} IMAGE_DEBUG_DIRECTORY, *PIMAGE_DEBUG_DIRECTORY;
// 调试类型
#define IMAGE_DEBUG_TYPE_UNKNOWN 0
#define IMAGE_DEBUG_TYPE_COFF 1
#define IMAGE_DEBUG_TYPE_CODEVIEW 2
#define IMAGE_DEBUG_TYPE_FPO 3
#define IMAGE_DEBUG_TYPE_MISC 4
#define IMAGE_DEBUG_TYPE_EXCEPTION 5
#define IMAGE_DEBUG_TYPE_FIXUP 6
#define IMAGE_DEBUG_TYPE_OMAP_TO_SRC 7
#define IMAGE_DEBUG_TYPE_OMAP_FROM_SRC 8
#define IMAGE_DEBUG_TYPE_BORLAND 9
#define IMAGE_DEBUG_TYPE_RESERVED10 10
#define IMAGE_DEBUG_TYPE_CLSID 11
#define IMAGE_DEBUG_TYPE_VC_FEATURE 12
#define IMAGE_DEBUG_TYPE_POGO 13
#define IMAGE_DEBUG_TYPE_ILTCG 14
#define IMAGE_DEBUG_TYPE_MPX 15
#define IMAGE_DEBUG_TYPE_REPRO 16
// TLS 目录结构
typedef struct _IMAGE_TLS_DIRECTORY32 {
DWORD StartAddressOfRawData;
DWORD EndAddressOfRawData;
DWORD AddressOfIndex; // PDWORD
DWORD AddressOfCallBacks; // PIMAGE_TLS_CALLBACK *
DWORD SizeOfZeroFill;
DWORD Characteristics;
} IMAGE_TLS_DIRECTORY32, *PIMAGE_TLS_DIRECTORY32;
typedef struct _IMAGE_TLS_DIRECTORY64 {
QWORD StartAddressOfRawData;
QWORD EndAddressOfRawData;
QWORD AddressOfIndex; // PDWORD
QWORD AddressOfCallBacks; // PIMAGE_TLS_CALLBACK *
DWORD SizeOfZeroFill;
DWORD Characteristics;
} IMAGE_TLS_DIRECTORY64, *PIMAGE_TLS_DIRECTORY64;
#ifdef _WIN64
typedef IMAGE_TLS_DIRECTORY64 IMAGE_TLS_DIRECTORY;
typedef PIMAGE_TLS_DIRECTORY64 PIMAGE_TLS_DIRECTORY;
#else
typedef IMAGE_TLS_DIRECTORY32 IMAGE_TLS_DIRECTORY;
typedef PIMAGE_TLS_DIRECTORY32 PIMAGE_TLS_DIRECTORY;
#endif
// 资源目录结构
typedef struct _IMAGE_RESOURCE_DIRECTORY {
DWORD Characteristics;
DWORD TimeDateStamp;
WORD MajorVersion;
WORD MinorVersion;
WORD NumberOfNamedEntries;
WORD NumberOfIdEntries;
// IMAGE_RESOURCE_DIRECTORY_ENTRY DirectoryEntries[];
} IMAGE_RESOURCE_DIRECTORY, *PIMAGE_RESOURCE_DIRECTORY;
#define IMAGE_RESOURCE_NAME_IS_STRING 0x80000000
#define IMAGE_RESOURCE_DATA_IS_DIRECTORY 0x80000000
typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY {
union {
struct {
DWORD NameOffset : 31;
DWORD NameIsString : 1;
};
DWORD Name;
WORD Id;
};
union {
DWORD OffsetToData;
struct {
DWORD OffsetToDirectory : 31;
DWORD DataIsDirectory : 1;
};
};
} IMAGE_RESOURCE_DIRECTORY_ENTRY, *PIMAGE_RESOURCE_DIRECTORY_ENTRY;
typedef struct _IMAGE_RESOURCE_DATA_ENTRY {
DWORD OffsetToData;
DWORD Size;
DWORD CodePage;
DWORD Reserved;
} IMAGE_RESOURCE_DATA_ENTRY, *PIMAGE_RESOURCE_DATA_ENTRY;
// 资源类型
#define RT_CURSOR 1
#define RT_BITMAP 2
#define RT_ICON 3
#define RT_MENU 4
#define RT_DIALOG 5
#define RT_STRING 6
#define RT_FONTDIR 7
#define RT_FONT 8
#define RT_ACCELERATOR 9
#define RT_RCDATA 10
#define RT_MESSAGETABLE 11
#define RT_GROUP_CURSOR 12
#define RT_GROUP_ICON 14
#define RT_VERSION 16
#define RT_DLGINCLUDE 17
#define RT_PLUGPLAY 19
#define RT_VXD 20
#define RT_ANICURSOR 21
#define RT_ANIICON 22
#define RT_HTML 23
#define RT_MANIFEST 24
// 加载配置目录结构
typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY32 {
DWORD Size;
DWORD TimeDateStamp;
WORD MajorVersion;
WORD MinorVersion;
DWORD GlobalFlagsClear;
DWORD GlobalFlagsSet;
DWORD CriticalSectionDefaultTimeout;
DWORD DeCommitFreeBlockThreshold;
DWORD DeCommitTotalFreeThreshold;
DWORD LockPrefixTable; // VA
DWORD MaximumAllocationSize;
DWORD VirtualMemoryThreshold;
DWORD ProcessAffinityMask;
DWORD ProcessHeapFlags;
WORD CsdVersion;
WORD DependentLoadFlags;
DWORD EditList; // VA
DWORD SecurityCookie; // VA
DWORD SEHandlerTable; // VA
DWORD SEHandlerCount;
DWORD GuardCFCheckFunctionPointer; // VA
DWORD GuardCFDispatchFunctionPointer; // VA
DWORD GuardCFFunctionTable; // VA
DWORD GuardCFFunctionCount;
DWORD GuardFlags;
} IMAGE_LOAD_CONFIG_DIRECTORY32, *PIMAGE_LOAD_CONFIG_DIRECTORY32;
typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY64 {
DWORD Size;
DWORD TimeDateStamp;
WORD MajorVersion;
WORD MinorVersion;
DWORD GlobalFlagsClear;
DWORD GlobalFlagsSet;
DWORD CriticalSectionDefaultTimeout;
QWORD DeCommitFreeBlockThreshold;
QWORD DeCommitTotalFreeThreshold;
QWORD LockPrefixTable; // VA
QWORD MaximumAllocationSize;
QWORD VirtualMemoryThreshold;
QWORD ProcessAffinityMask;
DWORD ProcessHeapFlags;
WORD CsdVersion;
WORD DependentLoadFlags;
QWORD EditList; // VA
QWORD SecurityCookie; // VA
QWORD SEHandlerTable; // VA
QWORD SEHandlerCount;
QWORD GuardCFCheckFunctionPointer; // VA
QWORD GuardCFDispatchFunctionPointer; // VA
QWORD GuardCFFunctionTable; // VA
QWORD GuardCFFunctionCount;
DWORD GuardFlags;
} IMAGE_LOAD_CONFIG_DIRECTORY64, *PIMAGE_LOAD_CONFIG_DIRECTORY64;
#ifdef _WIN64
typedef IMAGE_LOAD_CONFIG_DIRECTORY64 IMAGE_LOAD_CONFIG_DIRECTORY;
typedef PIMAGE_LOAD_CONFIG_DIRECTORY64 PIMAGE_LOAD_CONFIG_DIRECTORY;
#else
typedef IMAGE_LOAD_CONFIG_DIRECTORY32 IMAGE_LOAD_CONFIG_DIRECTORY;
typedef PIMAGE_LOAD_CONFIG_DIRECTORY32 PIMAGE_LOAD_CONFIG_DIRECTORY;
#endif
// GUID 定义
typedef struct _GUID {
DWORD Data1;
WORD Data2;
WORD Data3;
BYTE Data4[8];
} GUID, *PGUID;
// 符号相关定义
#define IMAGE_SIZEOF_SYMBOL 18
typedef struct _IMAGE_SYMBOL {
union {
BYTE ShortName[8];
struct {
DWORD Short; // if 0, use LongName
DWORD Long; // offset into string table
} Name;
PBYTE LongName[2];
} N;
DWORD Value;
SHORT SectionNumber;
WORD Type;
BYTE StorageClass;
BYTE NumberOfAuxSymbols;
} IMAGE_SYMBOL;
typedef IMAGE_SYMBOL UNALIGNED *PIMAGE_SYMBOL;
// 符号存储类
#define IMAGE_SYM_CLASS_END_OF_FUNCTION (BYTE) - 1
#define IMAGE_SYM_CLASS_NULL 0x0000
#define IMAGE_SYM_CLASS_AUTOMATIC 0x0001
#define IMAGE_SYM_CLASS_EXTERNAL 0x0002
#define IMAGE_SYM_CLASS_STATIC 0x0003
#define IMAGE_SYM_CLASS_REGISTER 0x0004
#define IMAGE_SYM_CLASS_EXTERNAL_DEF 0x0005
#define IMAGE_SYM_CLASS_LABEL 0x0006
#define IMAGE_SYM_CLASS_UNDEFINED_LABEL 0x0007
#define IMAGE_SYM_CLASS_MEMBER_OF_STRUCT 0x0008
#define IMAGE_SYM_CLASS_ARGUMENT 0x0009
#define IMAGE_SYM_CLASS_STRUCT_TAG 0x000A
#define IMAGE_SYM_CLASS_MEMBER_OF_UNION 0x000B
#define IMAGE_SYM_CLASS_UNION_TAG 0x000C
#define IMAGE_SYM_CLASS_TYPE_DEFINITION 0x000D
#define IMAGE_SYM_CLASS_UNDEFINED_STATIC 0x000E
#define IMAGE_SYM_CLASS_ENUM_TAG 0x000F
#define IMAGE_SYM_CLASS_MEMBER_OF_ENUM 0x0010
#define IMAGE_SYM_CLASS_REGISTER_PARAM 0x0011
#define IMAGE_SYM_CLASS_BIT_FIELD 0x0012
#define IMAGE_SYM_CLASS_FAR_EXTERNAL 0x0044
#define IMAGE_SYM_CLASS_BLOCK 0x0064
#define IMAGE_SYM_CLASS_FUNCTION 0x0065
#define IMAGE_SYM_CLASS_END_OF_STRUCT 0x0066
#define IMAGE_SYM_CLASS_FILE 0x0067
#define IMAGE_SYM_CLASS_SECTION 0x0068
#define IMAGE_SYM_CLASS_WEAK_EXTERNAL 0x0069
#define IMAGE_SYM_CLASS_CLR_TOKEN 0x006B
// 档案格式
#define IMAGE_ARCHIVE_START_SIZE 8
#define IMAGE_ARCHIVE_START "!<arch>\n"
#define IMAGE_ARCHIVE_END "`\n"
#define IMAGE_ARCHIVE_PAD "\n"
#define IMAGE_ARCHIVE_LINKER_MEMBER "/ "
#define IMAGE_ARCHIVE_LONGNAMES_MEMBER "// "
typedef struct _IMAGE_ARCHIVE_MEMBER_HEADER {
BYTE Name[16]; // File member name - `/' terminated.
BYTE Date[12]; // File member date - decimal.
BYTE UserID[6]; // File member user id - decimal.
BYTE GroupID[6]; // File member group id - decimal.
BYTE Mode[8]; // File member mode - octal.
BYTE Size[10]; // File member size - decimal.
BYTE EndHeader[2]; // String to end header.
} IMAGE_ARCHIVE_MEMBER_HEADER, *PIMAGE_ARCHIVE_MEMBER_HEADER;
#define IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR 60
// 重新定位类型
#define IMAGE_REL_I386_ABSOLUTE \
0x0000 // Reference is absolute, no relocation is necessary
#define IMAGE_REL_I386_DIR16 \
0x0001 // Direct 16-bit reference to the symbols virtual address
#define IMAGE_REL_I386_REL16 \
0x0002 // PC-relative 16-bit reference to the symbols virtual address
#define IMAGE_REL_I386_DIR32 \
0x0006 // Direct 32-bit reference to the symbols virtual address
#define IMAGE_REL_I386_DIR32NB \
0x0007 // Direct 32-bit reference to the symbols virtual address, base not
// included
#define IMAGE_REL_I386_SEG12 \
0x0009 // Direct 16-bit reference to the segment-selector bits of a 32-bit
// virtual address
#define IMAGE_REL_I386_SECTION 0x000A // Section table index
#define IMAGE_REL_I386_SECREL 0x000B // Offset within section
#define IMAGE_REL_I386_TOKEN 0x000C // clr token
#define IMAGE_REL_I386_SECREL7 \
0x000D // 7 bit offset from base of section containing target
#define IMAGE_REL_I386_REL32 \
0x0014 // PC-relative 32-bit reference to the symbols virtual address
// ARM 重新定位类型
#define IMAGE_REL_ARM_ABSOLUTE 0x0000 // No relocation required
#define IMAGE_REL_ARM_ADDR32 0x0001 // 32 bit address
#define IMAGE_REL_ARM_ADDR32NB 0x0002 // 32 bit address w/o image base
#define IMAGE_REL_ARM_BRANCH24 0x0003 // 24 bit offset << 2 & sign ext.
#define IMAGE_REL_ARM_BRANCH11 0x0004 // Thumb: 2 11 bit offsets
#define IMAGE_REL_ARM_TOKEN 0x0005 // clr token
#define IMAGE_REL_ARM_GPREL12 0x0006 // GP-relative addressing (ARM)
#define IMAGE_REL_ARM_GPREL7 0x0007 // GP-relative addressing (Thumb)
#define IMAGE_REL_ARM_BLX24 0x0008
#define IMAGE_REL_ARM_BLX11 0x0009
#define IMAGE_REL_ARM_SECTION 0x000E // Section table index
#define IMAGE_REL_ARM_SECREL 0x000F // Offset within section
#define IMAGE_REL_ARM_MOV32A 0x0010 // ARM: MOVW/MOVT
#define IMAGE_REL_ARM_MOV32T 0x0011 // Thumb: MOVW/MOVT
#define IMAGE_REL_ARM_BRANCH20T 0x0012 // Thumb: 32-bit conditional B
#define IMAGE_REL_ARM_BRANCH24T 0x0014 // Thumb: 32-bit B or BL
#define IMAGE_REL_ARM_BLX23T 0x0015 // Thumb: BLX immediate
// ARM64 重新定位类型
#define IMAGE_REL_ARM64_ABSOLUTE 0x0000 // No relocation required
#define IMAGE_REL_ARM64_ADDR32 0x0001 // 32 bit address (do not use this type)
#define IMAGE_REL_ARM64_ADDR32NB 0x0002 // 32 bit address w/o image base
#define IMAGE_REL_ARM64_BRANCH26 \
0x0003 // 26 bit offset << 2 & sign ext. for B & BL
#define IMAGE_REL_ARM64_PAGEBASE_REL21 0x0004 // ADRP
#define IMAGE_REL_ARM64_REL21 0x0005 // ADR
#define IMAGE_REL_ARM64_PAGEOFFSET_12A \
0x0006 // ADD/ADDS (immediate) with zero shift
#define IMAGE_REL_ARM64_PAGEOFFSET_12L \
0x0007 // LDR (indexed, unsigned immediate)
#define IMAGE_REL_ARM64_SECREL \
0x0008 // Offset within section -- legal only since 8.1
#define IMAGE_REL_ARM64_SECREL_LOW12A \
0x0009 // ADD/ADDS (immediate) with zero shift, for bit 0:11 of section
// offset
#define IMAGE_REL_ARM64_SECREL_HIGH12A \
0x000A // ADD/ADDS (immediate) with zero shift, for bit 12:23 of section
// offset
#define IMAGE_REL_ARM64_SECREL_LOW12L \
0x000B // LDR (indexed, unsigned immediate), for bit 0:11 of section offset
#define IMAGE_REL_ARM64_TOKEN 0x000C // clr token
#define IMAGE_REL_ARM64_SECTION 0x000D // Section table index
#define IMAGE_REL_ARM64_ADDR64 0x000E // 64 bit address
#define IMAGE_REL_ARM64_BRANCH19 \
0x000F // 19 bit offset << 2 & sign ext. for conditional B
#define IMAGE_REL_ARM64_BRANCH14 \
0x0010 // 14 bit offset << 2 & sign ext. for TBZ/TBNZ
// x64 重新定位类型
#define IMAGE_REL_AMD64_ABSOLUTE \
0x0000 // Reference is absolute, no relocation is necessary
#define IMAGE_REL_AMD64_ADDR64 0x0001 // 64-bit address (VA).
#define IMAGE_REL_AMD64_ADDR32 0x0002 // 32-bit address (VA).
#define IMAGE_REL_AMD64_ADDR32NB 0x0003 // 32-bit address w/o image base (RVA).
#define IMAGE_REL_AMD64_REL32 \
0x0004 // 32-bit relative address from byte following reloc
#define IMAGE_REL_AMD64_REL32_1 \
0x0005 // 32-bit relative address from byte distance 1 from reloc
#define IMAGE_REL_AMD64_REL32_2 \
0x0006 // 32-bit relative address from byte distance 2 from reloc
#define IMAGE_REL_AMD64_REL32_3 \
0x0007 // 32-bit relative address from byte distance 3 from reloc
#define IMAGE_REL_AMD64_REL32_4 \
0x0008 // 32-bit relative address from byte distance 4 from reloc
#define IMAGE_REL_AMD64_REL32_5 \
0x0009 // 32-bit relative address from byte distance 5 from reloc
#define IMAGE_REL_AMD64_SECTION 0x000A // Section index
#define IMAGE_REL_AMD64_SECREL \
0x000B // 32 bit offset from base of section containing target
#define IMAGE_REL_AMD64_SECREL7 \
0x000C // 7 bit unsigned offset from base of section containing target
#define IMAGE_REL_AMD64_TOKEN 0x000D // 32 bit metadata token
#define IMAGE_REL_AMD64_SREL32 \
0x000E // 32 bit signed span-dependent value emitted into object
#define IMAGE_REL_AMD64_PAIR \
0x000F // 32 bit signed span-dependent value applied at link time
#define IMAGE_REL_AMD64_SSPAN32 \
0x0010 // 32 bit signed span-dependent value applied at link time
///<
#include <scc_core.h>
#include <scc_utils.h>
typedef SCC_VEC(u8) scc_pe_buffer_t;
typedef struct {
u32 virual_address;
u32 virual_size;
u32 file_offset;
u32 file_size;
} scc_pe_section_range;
// FIXME 小端序? 当前简化为直接返回
#define SCC_LE16(x) (x)
#define SCC_LE32(x) (x)
#define SCC_LE64(x) (x)
#endif /* __SCC_PE_DEF_H__ */

View File

@@ -0,0 +1,77 @@
#ifndef __SCC_PE_IDATA_H__
#define __SCC_PE_IDATA_H__
#include "scc_pe_def.h"
typedef SCC_VEC(IMAGE_THUNK_DATA64) scc_winpe_lookup_table_vec_t;
/// @brief Hint Name Table Builder
typedef struct {
scc_pe_buffer_t data; ///< 具体数据
scc_hashtable_t str_map; ///< 符号名称映射到data的idx
u32 section_offset; ///< 在idata中的偏移
} scc_winpe_hnt_builder_t;
typedef struct {
u32 offset; ///< 相对代码段的偏移地址
i32 addend; ///< 可选的偏移量的附加值 可选默认为0
u8 size; ///< 引用的地址的大小
const char *library_name; ///< 库名称 eg. "Kernel32.dll"
const char *symbol_name; ///< 导入dll的符号名称 eg. "CreateFileW"
u16 ordinal; ///< 符号的序号 eg. 可选
} scc_winpe_extern_t;
typedef SCC_VEC(scc_winpe_extern_t) scc_winpe_extern_vec_t;
typedef SCC_VEC(const char *) scc_winpe_name_vec_t;
typedef struct {
const char *name;
scc_winpe_name_vec_t symbol_names;
} scc_winpe_idata_lib_t;
typedef SCC_VEC(scc_winpe_idata_lib_t) scc_winpe_idata_lib_vec_t;
typedef struct {
scc_pe_buffer_t buffer; ///< 导入表数据
scc_winpe_extern_vec_t externs;
scc_hashtable_t externs_set;
scc_winpe_hnt_builder_t hnt_builder;
scc_hashtable_t iat_map; ///< 符号名称映射到idata的虚拟镜像地址
scc_winpe_idata_lib_vec_t idata_libs;
} scc_winpe_idata_builder_t;
/**
* @brief PE格式导入表构建器初始化
* @warning 需要提前构造导入表所需的信息,不会检查导入表信息正确性
*
* @param builder
* @param idata_libs
*/
void scc_pe_idata_builder_init(scc_winpe_idata_builder_t *builder,
scc_winpe_idata_lib_vec_t *idata_libs);
/**
* @brief 获取导入表占据的大小
* @warning 必须初始化导入表构建器
*
* @param builder
* @return u32
*/
u32 scc_pe_reserve_idata(scc_winpe_idata_builder_t *builder);
/**
* @brief 构造导入表
* @warning 必须初始化导入表构建器
*
* @param builder
* @param idata_range
*/
scc_pe_buffer_t scc_pe_construct_idata(scc_winpe_idata_builder_t *builder,
scc_pe_section_range *idata_range);
// RVA Relative Virtual Address
static inline u64
scc_pe_idata_get_symbol_rva(scc_winpe_idata_builder_t *builder,
const char *symbol_name) {
return (u64)scc_hashtable_get(&builder->iat_map, symbol_name);
}
#endif

101
libs/target/pe/src/main.c Normal file
View File

@@ -0,0 +1,101 @@
#include <scc_pe_builder.h>
#include <scc_pe_idata.h>
#include <stdio.h>
int main() {
const char data[] = "Hello, World from SCC PE Builder!\n\0";
/* clang-format off */
const char code[] = {
// sub rsp, 0x28 ; 为函数调用分配栈空间
0x48, 0x83, 0xEC, 0x28,
// lea rcx, [rip + data_offset] ; 将字符串地址加载到RCX第一个参数
0x48, 0x8D, 0x0D, 0x00, 0x00, 0x00, 0x00,
// call qword ptr [rip + puts_iat] ; 通过IAT调用puts
0xFF, 0x15, 0x00, 0x00, 0x00, 0x00,
// add rsp, 0x28 ; 恢复栈空间
0x48, 0x83, 0xC4, 0x28,
// xor eax, eax ; 设置返回值为0
0x33, 0xC0,
// ret ; 返回
0xC3,
};
/* clang-format on */
scc_pe_builder_t builder = {0};
scc_pe_builder_init(&builder, true, 4096, 512);
scc_pe_reserve_header(&builder, 3);
scc_pe_section_range code_range = scc_pe_reserve_section_header(
&builder, (BYTE *)".text\0\0",
IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE,
sizeof(code), sizeof(code));
scc_pe_section_range data_range = scc_pe_reserve_section_header(
&builder, (BYTE *)".data\0\0",
IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |
IMAGE_SCN_MEM_WRITE,
sizeof(data), sizeof(data));
scc_winpe_idata_builder_t idata_builder;
scc_winpe_idata_lib_vec_t idata_libs;
scc_vec_init(idata_libs);
scc_winpe_idata_lib_t ucrtbase;
ucrtbase.name = "ucrtbase.dll";
scc_vec_init(ucrtbase.symbol_names);
scc_vec_push(ucrtbase.symbol_names, "puts");
scc_vec_push(idata_libs, ucrtbase);
scc_pe_idata_builder_init(&idata_builder, &idata_libs);
u32 idata_size = scc_pe_reserve_idata(&idata_builder);
scc_pe_section_range idata_range = scc_pe_reserve_section_header(
&builder, (BYTE *)".idata\0",
IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |
IMAGE_SCN_MEM_WRITE,
idata_size, idata_size);
scc_vec_at(builder.image_data_directory_vec, IMAGE_DIRECTORY_ENTRY_IMPORT) =
(IMAGE_DATA_DIRECTORY){.VirtualAddress = idata_range.virual_address,
.Size = idata_range.virual_size};
scc_pe_buffer_t idata_buffer =
scc_pe_construct_idata(&idata_builder, &idata_range);
u32 entry_point_offset = 0;
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,
};
// FIXME 需要确保宿主机为小端
*(u32 *)((u8 *)code + 7) =
(data_range.virual_address + 0) - (code_range.virual_address + 7 + 4);
*(u32 *)((u8 *)code + 13) =
(u64)scc_pe_idata_get_symbol_rva(&idata_builder, "puts") -
(code_range.virual_address + 13 + 4);
scc_pe_write_header(&builder, &config);
scc_pe_write_section(&builder, &code_range, (u8 *)code, sizeof(code));
scc_pe_write_section(&builder, &data_range, (u8 *)data, sizeof(data));
scc_pe_write_section(&builder, &idata_range,
scc_vec_unsafe_get_data(idata_buffer),
scc_vec_size(idata_buffer));
scc_pe_dump_to_file(&builder, "hello_world.exe");
}

View File

@@ -0,0 +1,369 @@
#include <scc_pe_builder.h>
#define reserve_align(offset, size) ((offset) + ((size) - 1)) & ~((size) - 1)
void scc_pe_builder_init(scc_pe_builder_t *builder, bool is_64,
u32 section_alignment, u32 file_alignment) {
scc_memset(builder, 0, sizeof(scc_pe_builder_t));
builder->is_64 = is_64;
builder->section_alignment = section_alignment;
builder->file_alignment = file_alignment;
builder->file_offset = 0;
}
static u32 reserve_file(scc_pe_builder_t *builder, u32 len, u32 align) {
if (len == 0) {
return len;
}
builder->file_offset = reserve_align(builder->file_offset, align);
u32 offset = builder->file_offset;
builder->file_offset += len;
LOG_INFO("reserve_file %u bytes at %u [%u]", len, offset,
builder->file_offset);
return offset;
}
static u32 reserve_virtual(scc_pe_builder_t *builder, u32 len, u32 align) {
if (len == 0) {
return len;
}
u32 offset = builder->virtual_offset;
builder->virtual_offset += len;
builder->virtual_offset = reserve_align(builder->virtual_offset, align);
LOG_INFO("reserve_virtual %u bytes at %u [%u]", len, offset,
builder->virtual_offset);
return offset;
}
static void padding_util(scc_pe_builder_t *builder, u32 len) {
if (builder->buffer.size > len) {
LOG_FATAL("padding_util less than buffer size [%u]:[%u]",
builder->buffer.size, len);
return;
}
for (usize i = builder->buffer.size; i < len; i++) {
scc_vec_push(builder->buffer, 0);
}
Assert(builder->buffer.size == len);
}
void scc_pe_reserve_dos_header_and_stub(scc_pe_builder_t *builder) {
Assert(builder->file_offset == 0);
reserve_file(builder, sizeof(IMAGE_DOS_HEADER), 1);
reserve_file(builder, 64, 1);
}
void scc_pe_reserve_nt_header(scc_pe_builder_t *builder,
usize data_directory_num) {
builder->nt_headers_offset =
reserve_file(builder,
builder->is_64 ? sizeof(IMAGE_NT_HEADERS64)
: sizeof(IMAGE_NT_HEADERS32),
8);
LOG_INFO("scc_pe_reserve_nt_header %u", builder->nt_headers_offset);
scc_vec_init(builder->image_data_directory_vec);
for (usize i = 0; i < data_directory_num; i += 1) {
scc_vec_push(builder->image_data_directory_vec,
(IMAGE_DATA_DIRECTORY){0});
}
reserve_file(builder, sizeof(IMAGE_DATA_DIRECTORY) * data_directory_num, 1);
}
void scc_pe_reserve_section_headers(scc_pe_builder_t *builder,
u32 num_of_section) {
builder->section_header_num = num_of_section;
reserve_file(builder, sizeof(IMAGE_SECTION_HEADER) * num_of_section, 1);
builder->file_offset =
reserve_align(builder->file_offset, builder->file_alignment);
builder->sizeof_headers = builder->file_offset;
reserve_virtual(builder, builder->file_offset, builder->section_alignment);
}
void scc_pe_reserve_header(scc_pe_builder_t *builder, u32 num_of_section) {
scc_pe_reserve_dos_header_and_stub(builder);
scc_pe_reserve_nt_header(builder, IMAGE_NUMBEROF_DIRECTORY_ENTRIES);
scc_pe_reserve_section_headers(builder, num_of_section);
}
void scc_pe_write_dos_header_and_stub(scc_pe_builder_t *builder) {
IMAGE_DOS_HEADER dos_header;
dos_header.e_magic = IMAGE_DOS_SIGNATURE;
dos_header.e_cblp = 0x90;
dos_header.e_cp = 3;
dos_header.e_crlc = 0;
dos_header.e_cparhdr = 4;
dos_header.e_minalloc = 0;
dos_header.e_maxalloc = 0xFFFF;
dos_header.e_ss = 0x00;
dos_header.e_sp = 0xB8;
dos_header.e_csum = 0;
dos_header.e_ip = 0x00;
dos_header.e_cs = 0x00;
dos_header.e_lfarlc = 0x40;
dos_header.e_ovno = 0x00;
for (int i = 0; i < 4; i++) {
dos_header.e_res[i] = 0x00;
}
dos_header.e_oemid = 0x00;
dos_header.e_oeminfo = 0x00;
for (int i = 0; i < 10; i++) {
dos_header.e_res2[i] = 0x00;
}
dos_header.e_lfanew = builder->nt_headers_offset;
for (usize i = 0; i < sizeof(dos_header); ++i) {
scc_vec_push(builder->buffer, ((u8 *)(&dos_header))[i]);
}
static const u8 dos_header_bytes[] = {
0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01,
0x4c, 0xcd, 0x21, 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f,
0x67, 0x72, 0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f, 0x74,
0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e, 0x20, 0x69, 0x6e, 0x20,
0x44, 0x4f, 0x53, 0x20, 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x0d, 0x0d,
0x0a, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
for (usize i = 0; i < sizeof(dos_header_bytes); i++) {
scc_vec_push(builder->buffer, ((u8 *)(&dos_header_bytes))[i]);
}
}
void scc_pe_write_nt_header_with_config(scc_pe_builder_t *builder,
const scc_pe_config_t *config) {
IMAGE_NT_HEADERS32 nt_headers32 = {0};
IMAGE_NT_HEADERS64 nt_headers64 = {0};
// 写入PE签名
DWORD *signature =
builder->is_64 ? &nt_headers64.Signature : &nt_headers32.Signature;
*signature = SCC_LE32(IMAGE_NT_SIGNATURE);
// 构建文件头
IMAGE_FILE_HEADER *file_header =
builder->is_64 ? &nt_headers64.FileHeader : &nt_headers32.FileHeader;
file_header->Machine = SCC_LE16(config->machine);
file_header->NumberOfSections = SCC_LE16(builder->section_header_num);
file_header->TimeDateStamp = SCC_LE32(config->time_date_stamp);
file_header->PointerToSymbolTable = SCC_LE32(builder->symbol_offset);
file_header->NumberOfSymbols = SCC_LE32(builder->symbol_num);
// 设置可选头大小
if (builder->is_64) {
file_header->SizeOfOptionalHeader =
SCC_LE16(sizeof(IMAGE_OPTIONAL_HEADER64) +
scc_vec_size(builder->image_data_directory_vec) *
sizeof(IMAGE_DATA_DIRECTORY));
} else {
file_header->SizeOfOptionalHeader =
SCC_LE16(sizeof(IMAGE_OPTIONAL_HEADER32) +
scc_vec_size(builder->image_data_directory_vec) *
sizeof(IMAGE_DATA_DIRECTORY));
}
file_header->Characteristics = SCC_LE16(config->characteristics);
// 根据是否为64位写入不同的可选头
if (builder->is_64) {
IMAGE_OPTIONAL_HEADER64 *optional = &nt_headers64.OptionalHeader;
optional->Magic = SCC_LE16(IMAGE_NT_OPTIONAL_HDR64_MAGIC);
optional->MajorLinkerVersion = config->major_linker_version;
optional->MinorLinkerVersion = config->minor_linker_version;
optional->SizeOfCode = SCC_LE32(builder->sizeof_code);
optional->SizeOfInitializedData = SCC_LE32(builder->sizeof_init_data);
optional->SizeOfUninitializedData =
SCC_LE32(builder->sizeof_uninit_data);
optional->AddressOfEntryPoint =
SCC_LE32(config->address_of_entry_point);
optional->BaseOfCode = SCC_LE32(builder->baseof_code);
optional->ImageBase = SCC_LE64(config->image_base);
optional->SectionAlignment = SCC_LE32(builder->section_alignment);
optional->FileAlignment = SCC_LE32(builder->file_alignment);
optional->MajorOperatingSystemVersion =
SCC_LE16(config->major_operating_system_version);
optional->MinorOperatingSystemVersion =
SCC_LE16(config->minor_operating_system_version);
optional->MajorImageVersion = SCC_LE16(config->major_image_version);
optional->MinorImageVersion = SCC_LE16(config->minor_image_version);
optional->MajorSubsystemVersion =
SCC_LE16(config->major_subsystem_version);
optional->MinorSubsystemVersion =
SCC_LE16(config->minor_subsystem_version);
optional->Win32VersionValue = SCC_LE32(0);
optional->SizeOfImage = SCC_LE32(builder->virtual_offset);
optional->SizeOfHeaders = SCC_LE32(builder->sizeof_headers);
optional->CheckSum = SCC_LE32(0);
optional->Subsystem = SCC_LE16(config->subsystem);
optional->DllCharacteristics = SCC_LE16(config->dll_characteristics);
optional->SizeOfStackReserve = SCC_LE64(config->size_of_stack_reserve);
optional->SizeOfStackCommit = SCC_LE64(config->size_of_stack_commit);
optional->SizeOfHeapReserve = SCC_LE64(config->size_of_heap_reserve);
optional->SizeOfHeapCommit = SCC_LE64(config->size_of_heap_commit);
optional->LoaderFlags = SCC_LE32(0);
optional->NumberOfRvaAndSizes =
SCC_LE32(scc_vec_size(builder->image_data_directory_vec));
} else {
IMAGE_OPTIONAL_HEADER32 *optional = &nt_headers32.OptionalHeader;
optional->Magic = SCC_LE16(IMAGE_NT_OPTIONAL_HDR32_MAGIC);
optional->MajorLinkerVersion = config->major_linker_version;
optional->MinorLinkerVersion = config->minor_linker_version;
optional->SizeOfCode = SCC_LE32(builder->sizeof_code);
optional->SizeOfInitializedData = SCC_LE32(builder->sizeof_init_data);
optional->SizeOfUninitializedData =
SCC_LE32(builder->sizeof_uninit_data);
optional->AddressOfEntryPoint =
SCC_LE32(config->address_of_entry_point);
optional->BaseOfCode = SCC_LE32(builder->baseof_code);
optional->BaseOfData = SCC_LE32(builder->baseof_data); // 32位特有的字段
optional->ImageBase =
SCC_LE32((uint32_t)(config->image_base & 0xFFFFFFFF));
optional->SectionAlignment = SCC_LE32(builder->section_alignment);
optional->FileAlignment = SCC_LE32(builder->file_alignment);
optional->MajorOperatingSystemVersion =
SCC_LE16(config->major_operating_system_version);
optional->MinorOperatingSystemVersion =
SCC_LE16(config->minor_operating_system_version);
optional->MajorImageVersion = SCC_LE16(config->major_image_version);
optional->MinorImageVersion = SCC_LE16(config->minor_image_version);
optional->MajorSubsystemVersion =
SCC_LE16(config->major_subsystem_version);
optional->MinorSubsystemVersion =
SCC_LE16(config->minor_subsystem_version);
optional->Win32VersionValue = SCC_LE32(0);
optional->SizeOfImage = SCC_LE32(builder->virtual_offset);
optional->SizeOfHeaders = SCC_LE32(builder->sizeof_headers);
optional->CheckSum = SCC_LE32(0);
optional->Subsystem = SCC_LE16(config->subsystem);
optional->DllCharacteristics = SCC_LE16(config->dll_characteristics);
optional->SizeOfStackReserve =
SCC_LE32((uint32_t)(config->size_of_stack_reserve & 0xFFFFFFFF));
optional->SizeOfStackCommit =
SCC_LE32((uint32_t)(config->size_of_stack_commit & 0xFFFFFFFF));
optional->SizeOfHeapReserve =
SCC_LE32((uint32_t)(config->size_of_heap_reserve & 0xFFFFFFFF));
optional->SizeOfHeapCommit =
SCC_LE32((uint32_t)(config->size_of_heap_commit & 0xFFFFFFFF));
optional->LoaderFlags = SCC_LE32(0);
optional->NumberOfRvaAndSizes =
SCC_LE32(scc_vec_size(builder->image_data_directory_vec));
}
if (builder->is_64) {
for (usize i = 0; i < sizeof(nt_headers64); i++) {
scc_vec_push(builder->buffer, ((u8 *)(&nt_headers64))[i]);
}
} else {
for (usize i = 0; i < sizeof(nt_headers32); i++) {
scc_vec_push(builder->buffer, ((u8 *)(&nt_headers32))[i]);
}
}
scc_vec_foreach(builder->image_data_directory_vec, i) {
IMAGE_DATA_DIRECTORY *data =
&scc_vec_at(builder->image_data_directory_vec, i);
for (usize i = 0; i < sizeof(IMAGE_DATA_DIRECTORY); i++) {
scc_vec_push(builder->buffer, ((u8 *)(data))[i]);
}
}
}
void scc_pe_write_section_headers(scc_pe_builder_t *builder) {
Assert(builder->section_header_num ==
builder->image_section_header_vec.size);
scc_vec_foreach(builder->image_section_header_vec, i) {
IMAGE_SECTION_HEADER *section_header =
&scc_vec_at(builder->image_section_header_vec, i);
for (usize j = 0; j < sizeof(IMAGE_SECTION_HEADER); j += 1) {
scc_vec_push(builder->buffer, ((u8 *)section_header)[j]);
}
}
}
void scc_pe_write_header(scc_pe_builder_t *builder, scc_pe_config_t *config) {
scc_vec_init(builder->buffer);
scc_pe_write_dos_header_and_stub(builder);
padding_util(builder, builder->nt_headers_offset);
scc_pe_write_nt_header_with_config(builder, config);
scc_pe_write_section_headers(builder);
}
scc_pe_section_range scc_pe_reserve_section_header(scc_pe_builder_t *builder,
BYTE name[8],
u32 characteristics,
u32 virtual_size,
u32 data_size) {
scc_pe_section_range range = {0};
range.virual_address =
reserve_virtual(builder, virtual_size, builder->section_alignment);
range.virual_size = virtual_size;
range.file_size = reserve_align(data_size, builder->file_alignment);
range.file_offset =
range.file_size != 0
? reserve_file(builder, range.file_size, builder->file_alignment)
: 0;
u32 aligned_virtual_size =
reserve_align(virtual_size, builder->file_alignment);
if (characteristics & IMAGE_SCN_CNT_CODE) {
if (!builder->baseof_code) {
builder->baseof_code = range.virual_address;
}
builder->sizeof_code += aligned_virtual_size;
} else if (characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) {
if (!builder->baseof_data) {
builder->baseof_data = range.virual_address;
}
builder->sizeof_init_data += aligned_virtual_size;
} else if (characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) {
if (!builder->baseof_data) {
builder->baseof_data = range.virual_address;
}
builder->sizeof_uninit_data += aligned_virtual_size;
}
IMAGE_SECTION_HEADER section_header = (IMAGE_SECTION_HEADER){
.Name[0] = name[0],
.Name[1] = name[1],
.Name[2] = name[2],
.Name[3] = name[3],
.Name[4] = name[4],
.Name[5] = name[5],
.Name[6] = name[6],
.Name[7] = name[7],
.Misc.VirtualSize = SCC_LE32(range.virual_size),
.VirtualAddress = SCC_LE32(range.virual_address),
.SizeOfRawData = SCC_LE32(range.file_size),
.PointerToRawData = SCC_LE32(range.file_offset),
.PointerToRelocations = SCC_LE32(0),
.PointerToLinenumbers = SCC_LE32(0),
.NumberOfRelocations = SCC_LE16(0),
.NumberOfLinenumbers = SCC_LE16(0),
.Characteristics = SCC_LE32(characteristics),
};
scc_vec_push(builder->image_section_header_vec, section_header);
return range;
}
void scc_pe_write_section(scc_pe_builder_t *builder,
scc_pe_section_range *range, u8 *data,
usize data_size) {
if (range == null || data == null || data_size == 0) {
return;
}
padding_util(builder, range->file_offset);
for (usize i = 0; i < data_size; i += 1) {
scc_vec_push(builder->buffer, data[i]);
}
usize size = scc_vec_size(builder->buffer);
size = reserve_align(size, builder->file_alignment);
padding_util(builder, size);
}
void scc_pe_dump_to_file(scc_pe_builder_t *builder, const char *file_path) {
scc_file_t fp = scc_fopen(file_path, SCC_FILE_WRITE);
scc_fwrite(fp, builder->buffer.data, builder->buffer.size);
scc_fclose(fp);
}

View File

@@ -0,0 +1,171 @@
#include <scc_pe_idata.h>
// RVA Relative Virtual Address
static inline IMAGE_IMPORT_DESCRIPTOR
image_import_descriptor_init(u32 import_lookup_table_rva, u32 name_rva,
u32 import_address_table_rva) {
IMAGE_IMPORT_DESCRIPTOR iid = {0};
iid.DUMMYUNIONNAME.OriginalFirstThunk = SCC_LE32(import_lookup_table_rva);
iid.TimeDateStamp = SCC_LE32(0);
iid.ForwarderChain = SCC_LE32(0);
iid.Name = SCC_LE32(name_rva);
iid.FirstThunk = SCC_LE32(import_address_table_rva);
return iid;
};
static void scc_winpe_hnt_builder_push(scc_winpe_hnt_builder_t *builder,
const char *name, u16 hint);
static void scc_winpe_hnt_builder_init(scc_winpe_hnt_builder_t *builder) {
scc_vec_init(builder->data);
builder->section_offset = 0;
scc_hashtable_init(&builder->str_map,
(scc_hashtable_hash_func_t)scc_strhash32,
(scc_hashtable_equal_func_t)scc_strcmp);
}
static void scc_winpe_hnt_builder_push(scc_winpe_hnt_builder_t *builder,
const char *name, u16 hint) {
///< 可选哈希表去重
if (scc_hashtable_get(&builder->str_map, name)) {
return;
}
scc_hashtable_set(&builder->str_map, name, (void *)(u64)builder->data.size);
/// FIXME WARNING需要转换为little endian
scc_vec_push(builder->data, hint & 0xff);
scc_vec_push(builder->data, hint >> 8);
while (*name) {
scc_vec_push(builder->data, *name);
name++;
}
scc_vec_push(builder->data, 0);
if (scc_vec_size(builder->data) % 2 != 0) {
scc_vec_push(builder->data, 0);
}
// return scc_vec_size(builder->data);
Assert(scc_vec_size(builder->data) % 2 == 0);
}
static u64 scc_winpe_hnt_get_offset(scc_winpe_hnt_builder_t *builder,
const char *name) {
return (u64)scc_hashtable_get(&builder->str_map, name);
}
void scc_pe_idata_builder_init(scc_winpe_idata_builder_t *builder,
scc_winpe_idata_lib_vec_t *idata_libs) {
scc_vec_init(builder->buffer);
builder->idata_libs = *idata_libs;
scc_winpe_hnt_builder_init(&builder->hnt_builder);
scc_hashtable_init(&builder->iat_map,
(scc_hashtable_hash_func_t)scc_strhash32,
(scc_hashtable_equal_func_t)scc_strcmp);
}
u32 scc_pe_reserve_idata(scc_winpe_idata_builder_t *builder) {
u32 idata_size = (scc_vec_size(builder->idata_libs) + 1) *
sizeof(IMAGE_IMPORT_DESCRIPTOR);
scc_vec_foreach(builder->idata_libs, i) {
scc_winpe_idata_lib_t *lib = &scc_vec_at(builder->idata_libs, i);
idata_size += (scc_vec_size(lib->symbol_names) + 1) * 2 *
sizeof(IMAGE_THUNK_DATA64);
scc_winpe_hnt_builder_push(&builder->hnt_builder, lib->name, 0);
scc_vec_foreach(lib->symbol_names, j) {
scc_winpe_hnt_builder_push(&builder->hnt_builder,
scc_vec_at(lib->symbol_names, j), 0);
}
}
builder->hnt_builder.section_offset = idata_size;
idata_size += scc_vec_size(builder->hnt_builder.data);
scc_vec_realloc(builder->buffer, idata_size);
scc_vec_size(builder->buffer) = idata_size;
return idata_size;
}
scc_pe_buffer_t scc_pe_construct_idata(scc_winpe_idata_builder_t *builder,
scc_pe_section_range *idata_range) {
u32 idata_rva = idata_range->virual_address;
u32 hnt_offset = builder->hnt_builder.section_offset;
usize import_file_count = scc_vec_size(builder->idata_libs);
usize current_offset =
(import_file_count + 1) * sizeof(IMAGE_IMPORT_DESCRIPTOR);
scc_vec_foreach(builder->idata_libs, i) {
scc_winpe_idata_lib_t *lib = &scc_vec_at(builder->idata_libs, i);
scc_winpe_lookup_table_vec_t lookup_table;
scc_vec_init(lookup_table);
scc_vec_foreach(lib->symbol_names, j) {
u64 name_offset = scc_winpe_hnt_get_offset(
&builder->hnt_builder, scc_vec_at(lib->symbol_names, j));
u64 name_rva = idata_rva + hnt_offset + name_offset;
IMAGE_THUNK_DATA64 lookup_table_entry = {.u1.AddressOfData =
name_rva};
scc_vec_push(lookup_table, lookup_table_entry);
}
scc_vec_push(lookup_table, (IMAGE_THUNK_DATA64){0});
usize table_size =
scc_vec_size(lookup_table) * sizeof(IMAGE_THUNK_DATA64);
usize ilt_offset = current_offset;
usize iat_offset = ilt_offset + table_size;
current_offset += table_size * 2;
scc_vec_foreach(lib->symbol_names, j) {
// 构造IAT链接
scc_hashtable_set(
&builder->iat_map, scc_vec_at(lib->symbol_names, j),
(void *)(usize)(idata_rva + j * sizeof(IMAGE_THUNK_DATA64)) +
iat_offset);
}
usize name_rva = idata_rva + hnt_offset +
scc_winpe_hnt_get_offset(&builder->hnt_builder,
lib->name); ///< hashtable get
// 构造并写入导入目录项
// The address of an ASCII string that contains the name of the DLL.
// This address is relative to the image base.
// https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#import-directory-table
// so add 2 to skip the two bytes of the Hint
IMAGE_IMPORT_DESCRIPTOR dir_entry = image_import_descriptor_init(
ilt_offset + idata_rva, name_rva + 2, iat_offset + idata_rva);
scc_memcpy(
&scc_vec_at(builder->buffer, i * sizeof(IMAGE_IMPORT_DESCRIPTOR)),
&dir_entry,
sizeof(IMAGE_IMPORT_DESCRIPTOR)); // FIXME 大小端
Assert(table_size ==
scc_vec_size(lookup_table) * sizeof(IMAGE_THUNK_DATA64));
// 转换为字节序列并写入
// FIXME 大小端
// 写入ILT表
scc_memcpy(&scc_vec_at(builder->buffer, ilt_offset),
&scc_vec_at(lookup_table, 0), table_size);
// 写入IAT表
scc_memcpy(&scc_vec_at(builder->buffer, iat_offset),
&scc_vec_at(lookup_table, 0), table_size);
}
// 添加NULL终止的目录项
IMAGE_IMPORT_DESCRIPTOR null_entry = image_import_descriptor_init(0, 0, 0);
scc_memcpy(&scc_vec_at(builder->buffer,
import_file_count * sizeof(IMAGE_IMPORT_DESCRIPTOR)),
&null_entry, sizeof(IMAGE_IMPORT_DESCRIPTOR));
// 填充Hint/Name表
scc_memcpy(&scc_vec_at(builder->buffer, hnt_offset),
&scc_vec_at(builder->hnt_builder.data, 0),
scc_vec_size(builder->hnt_builder.data));
return builder->buffer;
}

View File

@@ -9,9 +9,10 @@
#define __SCC_CORE_VEC_H__
#ifndef __SCC_CORE_VEC_USE_STD__
#include "scc_core_log.h"
#include "scc_core_impl.h"
#include "scc_core_type.h"
#define __scc_vec_realloc scc_realloc
#define __scc_vec_free scc_free
#else
@@ -27,7 +28,7 @@ typedef size_t usize;
#define LOG_FATAL(...) \
do { \
printf(__VA_ARGS__); \
exit(1); \
abort(); \
} while (0)
#endif
@@ -150,6 +151,8 @@ typedef size_t usize;
(vec).size = (vec).cap = 0; \
} while (0)
#define scc_vec_unsafe_get_data(vec) (vec).data
#define scc_vec_unsafe_from_array(vec, array) \
do { \
(vec).size = sizeof(array) / sizeof((array)[0]); \

View File

@@ -3,9 +3,9 @@
#include <scc_pproc.h>
#include <ast_dump.h>
#include <ir_dump.h>
#include <scc_ast2ir.h>
#include <scc_parser.h>
// #include <ir_dump.h>
// #include <scc_ast2ir.h>
typedef struct {
const char *input_file;
@@ -332,20 +332,29 @@ sstream_drop:
return 0;
}
// scc_ir_builder_t ir_builder;
// scc_ast2ir(translation_unit, &ir_builder);
scc_ir_builder_t ir_builder;
scc_ir_builder_init(&ir_builder);
#include <abi/win_x64_type_abi.h>
scc_ast2ir_translation_unit(&ir_builder, translation_unit,
scc_win_x64_type_abi);
// if (config.emit_ir) {
// scc_ir_dump_ctx_t ir_dump_ctx;
// scc_tree_dump_ctx_t tree_dump; // 仅为 ir dump 辅助
// scc_tree_dump_ctx_init(&tree_dump, true);
// scc_ir_dump_ctx_init(&ir_dump_ctx, &tree_dump, &ir_builder.cprog,
// &ir_builder.ctx);
// // scc_ir_dump_cprog(&ir_dump_ctx);
// scc_ir_dump_cprog_linear(&ir_dump_ctx);
// scc_tree_dump_ctx_drop(&tree_dump);
// return 0;
// }
if (config.emit_ir) {
scc_ir_dump_ctx_t ir_dump_ctx;
scc_tree_dump_ctx_t tree_dump;
if (fp == null) {
scc_tree_dump_ctx_init(&tree_dump, true, (void *)scc_fprintf,
(void *)scc_stdout);
} else {
scc_tree_dump_ctx_init(&tree_dump, false, (void *)scc_fprintf,
(void *)fp);
}
scc_ir_dump_ctx_init(&ir_dump_ctx, &tree_dump, &ir_builder.cprog,
&ir_builder.ctx);
// scc_ir_dump_cprog(&ir_dump_ctx);
scc_ir_dump_cprog_linear(&ir_dump_ctx);
scc_tree_dump_ctx_drop(&tree_dump);
return 0;
}
scc_printf("output exe at %s\n", config.output_file);
return 0;