1. -b bounds-checking 内存安全 - 编译 bcheck.o/bt-exe.o/bt-log.o 运行时 - 数组越界/野指针检测,精确定位文件和行号 - 测试: strcpy 溢出和数组越界均被捕获 2. pcc-asm 汇编查看工具 (bin/pcc-asm.exe) - 反汇编 pcc 生成的二进制 (调用 llvm-objdump) - 查看 x86-64 机器码与汇编指令 3. pcc-impdef DLL导入工具 (bin/pcc-impdef.exe) - 解析 PE 导出表生成 .def 文件 - 测试: kernel32.dll 1693 个导出全部正确解析 4. pcc-get 包管理器 (bin/pcc-get.exe) - install/remove/list/root 命令 - 支持本地包目录和 URL 下载安装 - 安装头文件到 include/、库到 lib/ - 测试: mymath 包安装→编译→链接→运行 全流程 5. 交叉编译演示 - 构建 ARM64 交叉编译器 (pcc-arm64.exe) - 构建 RISC-V 交叉编译器 (pcc-riscv64.exe) - 生成 elf64-littleaarch64 / elf64-littleriscv 对象 - 反汇编验证: 真正的 ARM64/RISC-V 机器码
191 行
6.0 KiB
C
191 行
6.0 KiB
C
/*
|
|
* pcc-impdef.c - create a .def file from a Windows DLL
|
|
*
|
|
* Parses the PE export directory of a DLL and writes an
|
|
* import definition (.def) file.
|
|
*
|
|
* Usage:
|
|
* pcc-impdef library.dll [-o output.def] [-v]
|
|
*
|
|
* License: MIT
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
typedef unsigned char u8;
|
|
typedef unsigned short u16;
|
|
typedef unsigned int u32;
|
|
|
|
/* read u32 from file data at offset (little-endian) */
|
|
static u32 rd32(const u8 *d, u32 off) {
|
|
return (u32)d[off] | ((u32)d[off+1] << 8) | ((u32)d[off+2] << 16) | ((u32)d[off+3] << 24);
|
|
}
|
|
|
|
static u16 rd16(const u8 *d, u32 off) {
|
|
return (u16)(d[off] | (d[off+1] << 8));
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
const char *infile = NULL;
|
|
const char *outfile = NULL;
|
|
int verbose = 0;
|
|
int i;
|
|
FILE *f;
|
|
long fsize;
|
|
u8 *data;
|
|
FILE *out = NULL;
|
|
u32 pe_off, opt_off, num_sections, sec_off;
|
|
u32 export_rva, export_size, names_rva, n_names;
|
|
u32 s;
|
|
int found_sec = 0;
|
|
u32 sec_rva = 0, sec_raw = 0, sec_vsize = 0;
|
|
|
|
/* --- parse args --- */
|
|
for (i = 1; i < argc; ++i) {
|
|
const char *a = argv[i];
|
|
if (a[0] == '-') {
|
|
if (strcmp(a, "-v") == 0)
|
|
verbose = 1;
|
|
else if (strcmp(a, "-o") == 0 && i + 1 < argc)
|
|
outfile = argv[++i];
|
|
else {
|
|
fprintf(stderr, "usage: pcc-impdef library.dll [-v] [-o outputfile]\n");
|
|
return 1;
|
|
}
|
|
} else if (!infile) {
|
|
infile = a;
|
|
} else {
|
|
fprintf(stderr, "usage: pcc-impdef library.dll [-v] [-o outputfile]\n");
|
|
return 1;
|
|
}
|
|
}
|
|
if (!infile) {
|
|
fprintf(stderr, "usage: pcc-impdef library.dll [-v] [-o outputfile]\n");
|
|
return 1;
|
|
}
|
|
|
|
/* --- read file --- */
|
|
f = fopen(infile, "rb");
|
|
if (!f) { fprintf(stderr, "pcc-impdef: cannot open '%s'\n", infile); return 1; }
|
|
fseek(f, 0, SEEK_END);
|
|
fsize = ftell(f);
|
|
fseek(f, 0, SEEK_SET);
|
|
data = (u8 *)malloc((size_t)fsize);
|
|
if (!data) { fprintf(stderr, "pcc-impdef: out of memory\n"); fclose(f); return 1; }
|
|
if (fread(data, 1, (size_t)fsize, f) != (size_t)fsize) {
|
|
fprintf(stderr, "pcc-impdef: read error\n"); fclose(f); free(data); return 1;
|
|
}
|
|
fclose(f);
|
|
|
|
/* --- PE header --- */
|
|
if (fsize < 0x40 || data[0] != 'M' || data[1] != 'Z') {
|
|
fprintf(stderr, "pcc-impdef: '%s' is not a PE file\n", infile);
|
|
free(data); return 1;
|
|
}
|
|
pe_off = rd32(data, 0x3C);
|
|
if (pe_off + 0x18 > (u32)fsize || rd32(data, pe_off) != 0x00004550) {
|
|
fprintf(stderr, "pcc-impdef: invalid PE header\n");
|
|
free(data); return 1;
|
|
}
|
|
opt_off = pe_off + 24;
|
|
num_sections = rd16(data, pe_off + 6);
|
|
sec_off = opt_off + 96; /* standard 32-byte opt header, but use size field */
|
|
|
|
/* optional header size tells where sections start */
|
|
sec_off = opt_off + rd16(data, pe_off + 20);
|
|
|
|
/* data directory (export is entry 0) - located after opt header fixed part */
|
|
{
|
|
u16 magic = rd16(data, opt_off);
|
|
u32 dd_off;
|
|
if (magic == 0x20B) /* PE32+ */
|
|
dd_off = opt_off + 112;
|
|
else /* PE32 */
|
|
dd_off = opt_off + 96;
|
|
export_rva = rd32(data, dd_off + 0);
|
|
export_size = rd32(data, dd_off + 4);
|
|
}
|
|
if (verbose)
|
|
printf("Export RVA: 0x%X size: 0x%X\n", export_rva, export_size);
|
|
|
|
if (export_rva == 0 || export_size == 0) {
|
|
fprintf(stderr, "pcc-impdef: no exports in '%s'\n", infile);
|
|
free(data); return 1;
|
|
}
|
|
|
|
/* find section containing the export RVA */
|
|
for (s = 0; s < num_sections; s++) {
|
|
u32 hdr = sec_off + s * 40;
|
|
u32 va = rd32(data, hdr + 12);
|
|
u32 vs = rd32(data, hdr + 8);
|
|
u32 rs = rd32(data, hdr + 16);
|
|
u32 rr = rd32(data, hdr + 20);
|
|
if (export_rva >= va && export_rva < va + vs) {
|
|
sec_rva = va; sec_raw = rr; sec_vsize = vs;
|
|
found_sec = 1;
|
|
break;
|
|
}
|
|
}
|
|
if (!found_sec) {
|
|
fprintf(stderr, "pcc-impdef: export RVA not in any section\n");
|
|
free(data); return 1;
|
|
}
|
|
|
|
/* export directory */
|
|
{
|
|
u32 ed = sec_raw + (export_rva - sec_rva);
|
|
if (ed + 40 > (u32)fsize) {
|
|
fprintf(stderr, "pcc-impdef: bad export directory\n");
|
|
free(data); return 1;
|
|
}
|
|
n_names = rd32(data, ed + 24);
|
|
names_rva = rd32(data, ed + 32);
|
|
|
|
/* names array: another RVA in same section */
|
|
{
|
|
u32 names_off = sec_raw + (names_rva - sec_rva);
|
|
u32 k;
|
|
const char *base = strrchr(infile, '\\');
|
|
if (!base) base = strrchr(infile, '/');
|
|
base = base ? base + 1 : infile;
|
|
|
|
if (!outfile) {
|
|
static char obuf[512];
|
|
char *dot;
|
|
strncpy(obuf, base, sizeof obuf - 1);
|
|
obuf[sizeof obuf - 1] = 0;
|
|
dot = strrchr(obuf, '.');
|
|
if (dot) *dot = 0;
|
|
strncat(obuf, ".def", sizeof obuf - strlen(obuf) - 1);
|
|
outfile = obuf;
|
|
}
|
|
out = fopen(outfile, "w");
|
|
if (!out) {
|
|
fprintf(stderr, "pcc-impdef: cannot create '%s'\n", outfile);
|
|
free(data); return 1;
|
|
}
|
|
|
|
fprintf(out, "LIBRARY %s\n\nEXPORTS\n", base);
|
|
for (k = 0; k < n_names; k++) {
|
|
u32 name_rva = rd32(data, names_off + k * 4);
|
|
u32 name_off;
|
|
if (name_rva >= sec_rva && name_rva < sec_rva + sec_vsize)
|
|
name_off = sec_raw + (name_rva - sec_rva);
|
|
else
|
|
name_off = name_rva; /* fallback */
|
|
if (name_off < (u32)fsize) {
|
|
fprintf(out, "%s\n", data + name_off);
|
|
if (verbose) printf(" export: %s\n", data + name_off);
|
|
}
|
|
}
|
|
fclose(out);
|
|
printf("pcc-impdef: wrote %s (%u exports)\n", outfile, n_names);
|
|
}
|
|
}
|
|
free(data);
|
|
return 0;
|
|
}
|