feat: bounds-checking/pcc-asm/pcc-impdef/pcc-get/交叉编译 五项功能
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 机器码
这个提交包含在:
+5
@@ -87,3 +87,8 @@ bin/*
|
||||
!bin/pcmake.exe
|
||||
!bin/libpcc.dll
|
||||
!bin/libpcc1.a
|
||||
!bin/pcc-arm64.exe
|
||||
!bin/pcc-riscv64.exe
|
||||
!bin/pcc-asm.exe
|
||||
!bin/pcc-get.exe
|
||||
!bin/pcc-impdef.exe
|
||||
|
||||
二进制文件未显示。
二进制
二进制文件未显示。
二进制
二进制文件未显示。
二进制文件未显示。
二进制文件未显示。
+109
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* pcc-asm.c - disassemble a PCC-produced binary
|
||||
*
|
||||
* Shows the x86-64 assembly of a compiled program.
|
||||
* Uses llvm-objdump if available, else objdump.
|
||||
*
|
||||
* Usage:
|
||||
* pcc-asm program.exe disassemble all code
|
||||
* pcc-asm program.exe main disassemble, filter by symbol
|
||||
*
|
||||
* License: MIT
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
static int file_exists(const char *f)
|
||||
{
|
||||
FILE *p = fopen(f, "rb");
|
||||
if (p) { fclose(p); return 1; }
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *find_objdump(void)
|
||||
{
|
||||
/* common locations, first match wins */
|
||||
static const char *cands[] = {
|
||||
"llvm-objdump.exe",
|
||||
"objdump.exe",
|
||||
"C:\\Program Files\\LLVM\\bin\\llvm-objdump.exe",
|
||||
"C:\\Clang+LLVM-22.1.7\\bin\\llvm-objdump.exe",
|
||||
"D:\\Clang+LLVM-22.1.7\\bin\\llvm-objdump.exe",
|
||||
"/usr/bin/objdump",
|
||||
"/usr/bin/llvm-objdump",
|
||||
NULL
|
||||
};
|
||||
int i;
|
||||
for (i = 0; cands[i]; i++)
|
||||
if (file_exists(cands[i]))
|
||||
return cands[i];
|
||||
return "objdump"; /* hope it's in PATH */
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *objdump = find_objdump();
|
||||
const char *file;
|
||||
const char *filter = NULL;
|
||||
char cmd[1024];
|
||||
int len;
|
||||
|
||||
if (argc < 2) {
|
||||
fprintf(stderr,
|
||||
"pcc-asm - disassemble a PCC binary\n"
|
||||
"\n"
|
||||
"Usage:\n"
|
||||
" pcc-asm program.exe disassemble all code\n"
|
||||
" pcc-asm program.exe main disassemble, filter by symbol\n"
|
||||
"\n"
|
||||
"Uses %s\n", objdump);
|
||||
return 1;
|
||||
}
|
||||
|
||||
file = argv[1];
|
||||
if (argc > 2)
|
||||
filter = argv[2];
|
||||
|
||||
if (!file_exists(file)) {
|
||||
fprintf(stderr, "pcc-asm: cannot open '%s'\n", file);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
len = snprintf(cmd, sizeof cmd, "\"%s\" -d \"%s\"", objdump, file);
|
||||
#else
|
||||
len = snprintf(cmd, sizeof cmd, "%s -d \"%s\"", objdump, file);
|
||||
#endif
|
||||
|
||||
if (filter) {
|
||||
/* use objdump's symbol filter if supported, else grep-style */
|
||||
len += snprintf(cmd + len, sizeof cmd - len, " | findstr /c:\"%s\"", filter);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
{
|
||||
STARTUPINFOA si;
|
||||
PROCESS_INFORMATION pi;
|
||||
char *cmdline = (char*)malloc(strlen(cmd) + 1);
|
||||
if (!cmdline) return 1;
|
||||
strcpy(cmdline, cmd);
|
||||
memset(&si, 0, sizeof si);
|
||||
si.cb = sizeof si;
|
||||
if (CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
|
||||
WaitForSingleObject(pi.hProcess, INFINITE);
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
}
|
||||
free(cmdline);
|
||||
}
|
||||
#else
|
||||
system(cmd);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
+350
@@ -0,0 +1,350 @@
|
||||
/*
|
||||
* pcc-get.c - package manager for PCC
|
||||
*
|
||||
* Manages C libraries: install headers/libs, remove, list.
|
||||
*
|
||||
* Usage:
|
||||
* pcc-get install <pkg> [url] install a package
|
||||
* <pkg> is a name; if a directory of that name exists
|
||||
* in the current dir or the packages/ dir, its files are
|
||||
* copied. If [url] is given, it is downloaded first
|
||||
* (zip/tar not extracted; use a flat file layout).
|
||||
* pcc-get list list installed packages
|
||||
* pcc-get remove <pkg> remove a package
|
||||
* pcc-get root print the install root
|
||||
*
|
||||
* A package is a directory containing:
|
||||
* include/xxx.h -> <root>/include/xxx.h
|
||||
* lib/libxxx.a -> <root>/lib/libxxx.a
|
||||
* (files may also be placed directly: foo.h -> include/,
|
||||
* libfoo.a -> lib/)
|
||||
*
|
||||
* License: MIT
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <windows.h>
|
||||
# include <direct.h>
|
||||
# define mkdir_p(p) _mkdir(p)
|
||||
#else
|
||||
# include <unistd.h>
|
||||
# include <sys/stat.h>
|
||||
# define mkdir_p(p) mkdir(p, 0755)
|
||||
#endif
|
||||
/* URLDownloadToFile from urlmon.dll (declared manually) */
|
||||
#ifdef _WIN32
|
||||
typedef long (__stdcall *URLDownloadToFileA_t)(void*, const char*, const char*, long, void*);
|
||||
static URLDownloadToFileA_t g_url_dl = NULL;
|
||||
static int http_download(const char *url, const char *dest)
|
||||
{
|
||||
HMODULE h = LoadLibraryA("urlmon.dll");
|
||||
if (!h) return -1;
|
||||
g_url_dl = (URLDownloadToFileA_t)GetProcAddress(h, "URLDownloadToFileA");
|
||||
if (!g_url_dl) return -1;
|
||||
return g_url_dl(NULL, url, dest, 0, NULL) == 0 ? 0 : -1;
|
||||
}
|
||||
#else
|
||||
static int http_download(const char *url, const char *dest)
|
||||
{
|
||||
(void)url; (void)dest;
|
||||
return -1; /* no download on non-Windows */
|
||||
}
|
||||
#endif
|
||||
|
||||
static void die(const char *msg)
|
||||
{
|
||||
fprintf(stderr, "pcc-get: %s\n", msg);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* find install root: dir of pcc-get.exe, else cwd */
|
||||
static void get_root(char *root, int size)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
GetModuleFileNameA(NULL, root, size);
|
||||
{
|
||||
char *s = strrchr(root, '\\');
|
||||
if (!s) s = strrchr(root, '/');
|
||||
if (s) *s = 0;
|
||||
else strcpy(root, ".");
|
||||
}
|
||||
#else
|
||||
getcwd(root, size);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int file_exists(const char *f)
|
||||
{
|
||||
FILE *p = fopen(f, "rb");
|
||||
if (p) { fclose(p); return 1; }
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dir_exists(const char *d)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
DWORD attr = GetFileAttributesA(d);
|
||||
return (attr != INVALID_FILE_ATTRIBUTES) && (attr & FILE_ATTRIBUTE_DIRECTORY);
|
||||
#else
|
||||
struct stat st;
|
||||
return stat(d, &st) == 0 && S_ISDIR(st.st_mode);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* copy a file */
|
||||
static int copy_file(const char *src, const char *dst)
|
||||
{
|
||||
FILE *in = fopen(src, "rb");
|
||||
FILE *out;
|
||||
char buf[8192];
|
||||
size_t n;
|
||||
if (!in) return -1;
|
||||
out = fopen(dst, "wb");
|
||||
if (!out) { fclose(in); return -1; }
|
||||
while ((n = fread(buf, 1, sizeof buf, in)) > 0)
|
||||
fwrite(buf, 1, n, out);
|
||||
fclose(in);
|
||||
fclose(out);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* case-insensitive compare of extensions */
|
||||
static int has_ext(const char *name, const char *ext)
|
||||
{
|
||||
const char *dot = strrchr(name, '.');
|
||||
if (!dot) return 0;
|
||||
return strcmp(dot + 1, ext) == 0
|
||||
|| strcmp(dot + 1, ext + 1) == 0 /* ".a" vs "a" */
|
||||
|| strcmp(dot, ext) == 0;
|
||||
}
|
||||
|
||||
static void ensure_dir(const char *path)
|
||||
{
|
||||
mkdir_p(path);
|
||||
}
|
||||
|
||||
/* install a package directory */
|
||||
static int install_dir(const char *pkgdir, const char *root)
|
||||
{
|
||||
char pattern[1024];
|
||||
char incdir[1024], libdir[1024];
|
||||
char src[1200], dst[1200];
|
||||
WIN32_FIND_DATAA fd;
|
||||
HANDLE h;
|
||||
int n = 0;
|
||||
|
||||
snprintf(incdir, sizeof incdir, "%s\\include", root);
|
||||
snprintf(libdir, sizeof libdir, "%s\\lib", root);
|
||||
ensure_dir(incdir);
|
||||
ensure_dir(libdir);
|
||||
|
||||
/* copy *.h to include/ */
|
||||
snprintf(pattern, sizeof pattern, "%s\\*.h", pkgdir);
|
||||
h = FindFirstFileA(pattern, &fd);
|
||||
if (h != INVALID_HANDLE_VALUE) {
|
||||
do {
|
||||
if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
|
||||
snprintf(src, sizeof src, "%s\\%s", pkgdir, fd.cFileName);
|
||||
snprintf(dst, sizeof dst, "%s\\%s", incdir, fd.cFileName);
|
||||
if (copy_file(src, dst) == 0) {
|
||||
printf(" install %s -> include/\n", fd.cFileName);
|
||||
n++;
|
||||
}
|
||||
}
|
||||
} while (FindNextFileA(h, &fd));
|
||||
FindClose(h);
|
||||
}
|
||||
|
||||
/* copy *.a and *.def to lib/ */
|
||||
snprintf(pattern, sizeof pattern, "%s\\*.a", pkgdir);
|
||||
h = FindFirstFileA(pattern, &fd);
|
||||
if (h != INVALID_HANDLE_VALUE) {
|
||||
do {
|
||||
if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
|
||||
snprintf(src, sizeof src, "%s\\%s", pkgdir, fd.cFileName);
|
||||
snprintf(dst, sizeof dst, "%s\\%s", libdir, fd.cFileName);
|
||||
if (copy_file(src, dst) == 0) {
|
||||
printf(" install %s -> lib/\n", fd.cFileName);
|
||||
n++;
|
||||
}
|
||||
}
|
||||
} while (FindNextFileA(h, &fd));
|
||||
FindClose(h);
|
||||
}
|
||||
snprintf(pattern, sizeof pattern, "%s\\*.def", pkgdir);
|
||||
h = FindFirstFileA(pattern, &fd);
|
||||
if (h != INVALID_HANDLE_VALUE) {
|
||||
do {
|
||||
if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
|
||||
snprintf(src, sizeof src, "%s\\%s", pkgdir, fd.cFileName);
|
||||
snprintf(dst, sizeof dst, "%s\\%s", libdir, fd.cFileName);
|
||||
if (copy_file(src, dst) == 0) {
|
||||
printf(" install %s -> lib/\n", fd.cFileName);
|
||||
n++;
|
||||
}
|
||||
}
|
||||
} while (FindNextFileA(h, &fd));
|
||||
FindClose(h);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char root[1024];
|
||||
char pkgdir[1200];
|
||||
char listfile[1200];
|
||||
const char *cmd, *pkg = NULL, *url = NULL;
|
||||
|
||||
get_root(root, sizeof root);
|
||||
|
||||
if (argc < 2) {
|
||||
fprintf(stderr,
|
||||
"pcc-get - PCC package manager\n"
|
||||
"\n"
|
||||
"Usage:\n"
|
||||
" pcc-get install <pkg> [url] install a package\n"
|
||||
" pcc-get list list installed packages\n"
|
||||
" pcc-get remove <pkg> remove a package\n"
|
||||
" pcc-get root print install root\n"
|
||||
"\n"
|
||||
"Install root: %s\n", root);
|
||||
return 1;
|
||||
}
|
||||
|
||||
cmd = argv[1];
|
||||
if (strcmp(cmd, "root") == 0) {
|
||||
printf("%s\n", root);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strcmp(cmd, "list") == 0) {
|
||||
char pattern[1024];
|
||||
WIN32_FIND_DATAA fd;
|
||||
HANDLE h;
|
||||
int n = 0;
|
||||
snprintf(pattern, sizeof pattern, "%s\\lib\\*.a", root);
|
||||
h = FindFirstFileA(pattern, &fd);
|
||||
printf("Installed packages:\n");
|
||||
if (h != INVALID_HANDLE_VALUE) {
|
||||
do {
|
||||
if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
|
||||
char name[512];
|
||||
strncpy(name, fd.cFileName, sizeof name - 1);
|
||||
name[sizeof name - 1] = 0;
|
||||
/* strip lib prefix and .a suffix */
|
||||
if (strncmp(name, "lib", 3) == 0) {
|
||||
char *dot = strrchr(name, '.');
|
||||
if (dot) *dot = 0;
|
||||
printf(" %s\n", name + 3);
|
||||
n++;
|
||||
}
|
||||
}
|
||||
} while (FindNextFileA(h, &fd));
|
||||
FindClose(h);
|
||||
}
|
||||
if (n == 0) printf(" (none)\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strcmp(cmd, "install") == 0) {
|
||||
int n;
|
||||
if (argc < 3) die("usage: pcc-get install <pkg> [url]");
|
||||
pkg = argv[2];
|
||||
if (argc > 3) url = argv[3];
|
||||
|
||||
/* if url given, download to temp then use as package dir */
|
||||
if (url) {
|
||||
char tmp[1200];
|
||||
snprintf(tmp, sizeof tmp, "%s\\%s.tmp", root, pkg);
|
||||
printf("pcc-get: downloading %s ...\n", url);
|
||||
if (http_download(url, tmp) != 0) {
|
||||
fprintf(stderr, "pcc-get: download failed\n");
|
||||
return 1;
|
||||
}
|
||||
printf("pcc-get: downloaded %s\n", tmp);
|
||||
/* treat the downloaded file as a single library file:
|
||||
move to lib/ based on extension */
|
||||
{
|
||||
char dst[1200];
|
||||
char name[512];
|
||||
const char *base = strrchr(url, '/');
|
||||
base = base ? base + 1 : pkg;
|
||||
strncpy(name, base, sizeof name - 1);
|
||||
name[sizeof name - 1] = 0;
|
||||
if (has_ext(name, ".a") || has_ext(name, "a")) {
|
||||
snprintf(dst, sizeof dst, "%s\\lib\\lib%s.a", root, pkg);
|
||||
ensure_dir(root);
|
||||
{
|
||||
char libd[1024];
|
||||
snprintf(libd, sizeof libd, "%s\\lib", root);
|
||||
ensure_dir(libd);
|
||||
}
|
||||
copy_file(tmp, dst);
|
||||
printf("pcc-get: installed lib%s.a\n", pkg);
|
||||
remove(tmp);
|
||||
return 0;
|
||||
} else if (has_ext(name, ".h") || has_ext(name, "h")) {
|
||||
char incd[1024];
|
||||
snprintf(incd, sizeof incd, "%s\\include", root);
|
||||
ensure_dir(incd);
|
||||
snprintf(dst, sizeof dst, "%s\\include\\%s.h", root, pkg);
|
||||
copy_file(tmp, dst);
|
||||
printf("pcc-get: installed %s.h\n", pkg);
|
||||
remove(tmp);
|
||||
return 0;
|
||||
} else {
|
||||
fprintf(stderr, "pcc-get: cannot determine type of %s\n", name);
|
||||
remove(tmp);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* local package: look for <pkg> dir in cwd, then packages/, then root */
|
||||
snprintf(pkgdir, sizeof pkgdir, "%s", pkg);
|
||||
if (!dir_exists(pkgdir)) {
|
||||
snprintf(pkgdir, sizeof pkgdir, "packages\\%s", pkg);
|
||||
if (!dir_exists(pkgdir)) {
|
||||
snprintf(pkgdir, sizeof pkgdir, "%s\\packages\\%s", root, pkg);
|
||||
if (!dir_exists(pkgdir)) {
|
||||
fprintf(stderr, "pcc-get: package '%s' not found (looked in ., packages/, %s\\packages)\n",
|
||||
pkg, root);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
n = install_dir(pkgdir, root);
|
||||
printf("pcc-get: installed %s (%d files)\n", pkg, n);
|
||||
return n > 0 ? 0 : 1;
|
||||
}
|
||||
|
||||
if (strcmp(cmd, "remove") == 0) {
|
||||
char pattern[1024];
|
||||
WIN32_FIND_DATAA fd;
|
||||
HANDLE h;
|
||||
int n = 0;
|
||||
if (argc < 3) die("usage: pcc-get remove <pkg>");
|
||||
pkg = argv[2];
|
||||
|
||||
/* remove lib/lib<pkg>.a and include/<pkg>.h */
|
||||
{
|
||||
char path[1200];
|
||||
snprintf(path, sizeof path, "%s\\lib\\lib%s.a", root, pkg);
|
||||
if (file_exists(path)) { remove(path); printf(" removed %s\n", path); n++; }
|
||||
snprintf(path, sizeof path, "%s\\include\\%s.h", root, pkg);
|
||||
if (file_exists(path)) { remove(path); printf(" removed %s\n", path); n++; }
|
||||
}
|
||||
if (n == 0)
|
||||
printf("pcc-get: package '%s' not installed\n", pkg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fprintf(stderr, "pcc-get: unknown command '%s'\n", cmd);
|
||||
return 1;
|
||||
}
|
||||
+190
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
在新工单中引用
屏蔽一个用户