summaryrefslogtreecommitdiff
path: root/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'main.c')
-rw-r--r--main.c424
1 files changed, 255 insertions, 169 deletions
diff --git a/main.c b/main.c
index 3942f98..cf3ebdf 100644
--- a/main.c
+++ b/main.c
@@ -1,9 +1,5 @@
#define VERSION "0.0"
-#define MAX_HEADERS 2000
-#define MAX_LIBS 2000
-#define MAX_INCLUDES 2000
-
#if __GNUC__
#define UNUSED __attribute__((unused))
#else
@@ -124,9 +120,11 @@ static void show_help_text_and_exit(const char *program_name) {
"\t-i <header file> Add a header file to be processed.\n"
"\t-I <include directory> Add an include directory when preprocessing header files.\n"
"\t-l <dynamic library> Set the dynamic library file you want to replace.\n"
- "\t-o <output C file> Set the output file.\n"
+ "\t-o <output name> Set the output file name.\n"
+ "\t-C <argument> Add an argument for the C preprocessor.\n"
);
printf(
+ "\t--no-warn Disable warnings if a function isn't found in a header file.\n"
"\t--help Show this help text and exit.\n"
"\t--version Show version number and exit.\n"
"Environment variables:\n"
@@ -233,17 +231,16 @@ static void symbol_hash_table_free(SymbolHashTable *table) {
}
int main(int argc, char **argv) {
- static int headers[MAX_HEADERS];
- static int includes[MAX_INCLUDES];
char *preprocessed_headers;
size_t preprocessed_headers_len = 0;
const char *preprocessor_program = C_PREPROCESSOR_DEFAULT;
- const char *output_filename = NULL;
+ const char *output_name = NULL;
const char *input_filename = NULL;
+ int no_warn = 0;
SymbolHashTable all_symbols = {0}; /* all symbols in all provided libraries */
- int i, n_headers = 0, n_includes = 0;
+ int i;
{
char *p = getenv("C_PREPROCESSOR");
@@ -251,88 +248,86 @@ int main(int argc, char **argv) {
preprocessor_program = p;
}
- /* parse arguments */
- for (i = 1; i < argc; ++i) {
- if (argv[i][0] == '-') {
- switch (argv[i][1]) {
- case 'i':
- if (n_headers >= MAX_HEADERS) {
- fprintf(stderr, "Too many headers!\n");
- exit(-1);
- } else if (i < argc-1) {
- headers[n_headers++] = i+1;
- ++i;
- } else {
- fprintf(stderr, "-i must be followed by a file name.\n");
- exit(-1);
- }
- break;
- case 'l':
- if (input_filename) {
- fprintf(stderr, "-l specified multiple times.\n");
- exit(-1);
- } else if (i < argc-1) {
- input_filename = argv[i+1];
- ++i;
- } else {
- fprintf(stderr, "-l must be followed by a file name.\n");
- exit(-1);
- }
- break;
- case 'I':
- if (n_includes >= MAX_INCLUDES) {
- fprintf(stderr, "Too many includes!\n");
- exit(-1);
- } else if (i < argc-1) {
- includes[n_includes++] = i+1;
- ++i;
- } else {
- fprintf(stderr, "-I must be followed by a directory name.\n");
- exit(-1);
- }
- break;
- case 'o':
- if (output_filename) {
- fprintf(stderr, "-o specified twice.\n");
- exit(-1);
- } else if (i < argc-1) {
- output_filename = argv[i+1];
- ++i;
- } else {
- fprintf(stderr, "-o must be followed by a file name.\n");
- exit(-1);
- }
- break;
- case '-':
- if (strcmp(argv[i], "--help") == 0) {
- show_help_text_and_exit(argv[0]);
- } else if (strcmp(argv[i], "--version") == 0) {
- printf(VERSION_TEXT);
- exit(0);
+ {
+ /* parse arguments */
+ for (i = 1; i < argc; ++i) {
+ if (argv[i][0] == '-') {
+ switch (argv[i][1]) {
+ case 'i':
+ if (i < argc-1) {
+ ++i;
+ } else {
+ fprintf(stderr, "-i must be followed by a file name.\n");
+ exit(-1);
+ }
+ break;
+ case 'l':
+ if (i < argc-1) {
+ input_filename = argv[i+1];
+ ++i;
+ } else {
+ fprintf(stderr, "-l must be followed by a file name.\n");
+ exit(-1);
+ }
+ break;
+ case 'I':
+ if (i < argc-1) {
+ ++i;
+ } else {
+ fprintf(stderr, "-I must be followed by a directory name.\n");
+ exit(-1);
+ }
+ break;
+ case 'C':
+ if (i < argc-1) {
+ ++i;
+ } else {
+ fprintf(stderr, "-I must be followed by a directory name.\n");
+ exit(-1);
+ }
+ break;
+ case 'o':
+ if (output_name) {
+ fprintf(stderr, "-o specified twice.\n");
+ exit(-1);
+ } else if (i < argc-1) {
+ output_name = argv[i+1];
+ ++i;
+ } else {
+ fprintf(stderr, "-o must be followed by a file name.\n");
+ exit(-1);
+ }
+ break;
+ case '-':
+ if (strcmp(argv[i], "--help") == 0) {
+ show_help_text_and_exit(argv[0]);
+ } else if (strcmp(argv[i], "--version") == 0) {
+ printf(VERSION_TEXT);
+ exit(0);
+ } else if (strcmp(argv[i], "--no-warn") == 0) {
+ no_warn = 1;
+ } else goto unrecognized;
+ break;
+ default:
+ unrecognized:
+ fprintf(stderr, "Unrecognized flag: '%s'.\n", argv[i]);
+ break;
}
- break;
+ } else {
+ fprintf(stderr, "Stray argument (#%d): '%s'.\n", i, argv[i]);
+ exit(-1);
}
- } else {
- fprintf(stderr, "Stray argument (#%d): '%s'.\n", i, argv[i]);
- exit(-1);
+ }
+ if (!input_filename) {
+ show_help_text_and_exit(argv[0]);
}
}
- if (!output_filename) {
- output_filename = "out.c";
+ if (!output_name) {
+ output_name = "out";
}
- if (!input_filename || n_headers == 0) {
- show_help_text_and_exit(argv[0]);
- }
- /* check that files exist */
- for (i = 0; i < n_headers; ++i) {
- if (!file_is_readable(argv[headers[i]])) {
- fprintf(stderr, "Can't open provided header file: '%s'.\n", argv[headers[i]]);
- exit(1);
- }
- }
if (!file_is_readable(input_filename)) {
fprintf(stderr, "Can't open provided dynamic library file: '%s'.\n", input_filename);
exit(1);
@@ -471,7 +466,9 @@ int main(int argc, char **argv) {
perror("Couldn't create compiler process");
exit(2);
case 0: {
- static char *cc_argv[2*MAX_INCLUDES + 10];
+ #define MAX_CC_ARGV 4000
+ static char *cc_argv[MAX_CC_ARGV+1];
+ int a = 0;
/* child */
close(pipefd[1]); /* don't need write end of pipe */
if (dup2(pipefd[0], 0) == -1) {
@@ -482,15 +479,28 @@ int main(int argc, char **argv) {
perror("Couldn't redirect C compiler's stdout to file");
exit(2);
}
- cc_argv[0] = (char *)preprocessor_program;
- cc_argv[1] = "-E";
- cc_argv[2] = "-";
- cc_argv[3] = "-D";
- cc_argv[4] = "SDL_DISABLE_IMMINTRIN_H";
- for (i = 0; i < n_includes; ++i) {
- cc_argv[5+2*i+0] = "-I";
- cc_argv[5+2*i+1] = argv[includes[i]];
+
+ cc_argv[a++] = (char *)preprocessor_program;
+ cc_argv[a++] = "-E";
+ cc_argv[a++] = "-";
+ for (i = 1; i < argc-1; ++i) {
+ if (strcmp(argv[i], "-I") == 0) {
+ if (a + 2 > MAX_CC_ARGV) {
+ fprintf(stderr, "Too many compiler arguments.\n");
+ exit(-1);
+ }
+ cc_argv[a++] = "-I";
+ cc_argv[a++] = argv[i+1];
+ } else if (strcmp(argv[i], "-C") == 0) {
+ if (a + 1 > MAX_CC_ARGV) {
+ fprintf(stderr, "Too many compiler arguments.\n");
+ exit(-1);
+ }
+ cc_argv[a++] = argv[i+1];
+ }
+ if (argv[i][0] == '-' && argv[i][1] != '-') ++i;
}
+ cc_argv[a++] = NULL;
if (execv(preprocessor_program, cc_argv) == -1) {
perror("Couldn't start C compiler");
exit(2);
@@ -502,31 +512,51 @@ int main(int argc, char **argv) {
/* parent */
close(pipefd[0]); /* don't need read end of pipe */
- for (i = 0; i < n_headers; ++i) {
- const char *header = argv[headers[i]];
- int fd = open(header, O_RDONLY);
- char buf[4096];
- ssize_t bytes_read;
-
- if (fd == -1) {
- char prefix[128];
- sprintf(prefix, "Couldn't open %.100s", header);
- perror(prefix);
- exit(2);
- }
-
- while ((bytes_read = read(fd, buf, sizeof buf)) > 0) {
- write(pipefd[1], buf, (size_t)bytes_read);
- }
+ for (i = 1; i < argc-1; ++i) {
+ if (strcmp(argv[i], "-i") == 0) {
+ const char *header = argv[i+1];
+ int fd = open(header, O_RDONLY);
+ char buf[4096];
+ ssize_t bytes_read;
+
+ if (fd == -1) {
+ /* check include directories */
+ char path[520];
+ int j;
+ for (j = 1; j < argc-1; ++j) {
+ if (strcmp(argv[j], "-I") == 0) {
+ const char *dir = argv[j+1];
+ sprintf(path, "%.256s/%.256s", dir, header);
+ fd = open(path, O_RDONLY);
+ if (fd != -1) break;
+ }
+ if (argv[j][0] == '-' && argv[j][1] != '-') ++j;
+ }
+
+ if (fd == -1) {
+ char prefix[128];
+ sprintf(prefix, "Couldn't open %.100s", header);
+ perror(prefix);
+ kill(SIGKILL, compiler_process);
+ exit(2);
+ }
+ }
+
+ while ((bytes_read = read(fd, buf, sizeof buf)) > 0) {
+ write(pipefd[1], buf, (size_t)bytes_read);
+ }
- if (bytes_read < 0) {
- char prefix[128];
- sprintf(prefix, "Error reading %.100s", header);
- perror(prefix);
- exit(2);
- }
+ if (bytes_read < 0) {
+ char prefix[128];
+ sprintf(prefix, "Error reading %.100s", header);
+ perror(prefix);
+ kill(SIGKILL, compiler_process);
+ exit(2);
+ }
- close(fd);
+ close(fd);
+ }
+ if (argv[i][0] == '-' && argv[i][1] != '-') ++i;
}
close(pipefd[1]);
@@ -572,15 +602,76 @@ int main(int argc, char **argv) {
{
- FILE *output = fopen(output_filename, "w");
+ FILE *c_output;
+ FILE *nasm_output;
size_t c = 0;
const char *semicolon;
- if (!output) {
- perror("Couldn't open output file");
- exit(1);
+
+ {
+ char filename[1024];
+
+ sprintf(filename, "%.1000s.c", output_name);
+ c_output = fopen(filename, "w");
+ if (!c_output) {
+ perror("Couldn't open C output file");
+ exit(1);
+ }
+
+ sprintf(filename, "%.1000s.asm", output_name);
+ nasm_output = fopen(filename, "w");
+ if (!nasm_output) {
+ perror("Couldn't open nasm output file");
+ exit(1);
+ }
}
+ for (i = 1; i < argc-1; ++i) {
+ if (strcmp(argv[i], "-i") == 0) {
+ fprintf(c_output, "#include <%s>\n", argv[i+1]);
+ }
+ if (argv[i][0] == '-' && argv[i][1] != '-') ++i;
+ }
+
+ fprintf(c_output, "#define DLSUB_REAL_DL_NAME \"%s\"\n", input_filename);
+
+ fprintf(c_output,
+ "static void dlsub_init(void);\n"
+ "\n"
+ "#if __unix__\n"
+ "#include <dlfcn.h>\n"
+ "#define DLSUB_GET_DLHANDLE(filename) dlopen(filename, RTLD_LAZY)\n"
+ "#define DLSUB_GET_SYM(handle, name) ((void(*)(void))dlsym(handle, name))\n"
+ "#define DLSUB_EXPORT\n"
+ "static void __attribute__((constructor)) dlsub_constructor(void) {\n"
+ "\tdlsub_init();\n"
+ "}\n"
+ );
+ fprintf(c_output,
+ "#elif _WIN32\n"
+ "extern void *__stdcall LoadLibraryA(const char *);\n"
+ "extern int (*__stdcall GetProcAddress(void *, const char *))(void);\n"
+ "#define DLSUB_GET_DLHANDLE LoadLibraryA\n"
+ "#define DLSUB_GET_SYM GetProcAddress\n"
+ "#define DLSUB_EXPORT __declspec((dllexport))\n"
+ "unsigned __stdcall DllMain(void *instDLL, unsigned reason, void *_reserved) {\n"
+ "\t(void)instDLL; (void)_reserved;\n"
+ "\tswitch (reason) {\n"
+ "\tcase 1: /* DLL loaded */\n"
+ "\t\tdlsub_init();\n"
+ "\t\tbreak;\n"
+ "\tcase 0: /* DLL unloaded */\n"
+ "\t\tbreak;\n"
+ "}\n"
+ );
+ fprintf(c_output,
+ "#else\n"
+ "#error \"Unrecognized OS.\"\n"
+ "#endif\n"
+ );
+
+ fprintf(c_output, "\n\n");
+
while ((semicolon = memchr(preprocessed_headers + c, ';', preprocessed_headers_len - c))) {
char statement_data[1024], *statement = statement_data;
@@ -640,9 +731,9 @@ int main(int argc, char **argv) {
/* remove duplicate/unnecessary whitespace */
for (in = statement, out = statement; *in; ++in) {
- if (in[0] == ' ' && strchr(" ()*,", in[1])) {
+ if (in[0] == ' ' && strchr(" (){}*,", in[1])) {
continue;
- } else if (strchr(" ()*,", in[0]) && in[1] == ' ') {
+ } else if (strchr(" (){}*,", in[0]) && in[1] == ' ') {
*out++ = *in;
while (in[1] == ' ') ++in;
} else {
@@ -659,6 +750,11 @@ int main(int argc, char **argv) {
statement[strlen(statement)-1] = '\0';
}
+ while (statement[0] == '}') {
+ /* this can happen with inline functions */
+ ++statement;
+ }
+
/* remove "extern" at beginning */
if (strncmp(statement, "extern ", 7) == 0) {
statement += 7;
@@ -684,10 +780,8 @@ int main(int argc, char **argv) {
memmove(attr, p, (size_t)(statement + strlen(statement) + 1 - p));
}
}
-
- /* @TODO(windows): remove __cdecl, et al. */
}
-
+
if (
/* these conditions aren't airtight but practically speaking they're good */
strlen(statement) < 5 /* shortest possible function declaration is A f(); */
@@ -735,9 +829,9 @@ int main(int argc, char **argv) {
/* already processed this function */
} else {
entry->declared = 1;
- fprintf(output,
+ fprintf(c_output,
"typedef %.*s (*PTR_%.*s)%.*s;\n"
- "static PTR_%.*s REAL_%.*s;\n",
+ "PTR_%.*s REAL_%.*s;\n",
(int)(func_name - statement),
statement,
(int)(func_name_end - func_name),
@@ -757,61 +851,53 @@ int main(int argc, char **argv) {
c = (size_t)(semicolon - preprocessed_headers);
++c;
}
- fprintf(output, "\n\n\n"
- "static void dlsub_init(void);\n"
- "\n"
- "#if __unix__\n"
- "#include <dlfcn.h>\n"
- "#define DLSUB_GET_DLHANDLE(filename) dlopen(filename, RTLD_LAZY)\n"
- "#define DLSUB_GET_SYM dlsym\n"
- "static void __attribute__((constructor)) dlsub_constructor(void) {\n"
- "\tdlsub_init();\n"
- "}\n"
- );
- fprintf(output,
- "#elif _WIN32\n"
- "extern void *__stdcall LoadLibraryA(const char *);\n"
- "extern int (*__stdcall GetProcAddress(void *, const char *))(void);\n"
- "#define DLSUB_GET_DLHANDLE LoadLibraryA\n"
- "#define DLSUB_GET_SYM GetProcAddress\n"
- "unsigned __stdcall DllMain(void *instDLL, unsigned reason, void *_reserved) {\n"
- "\t(void)instDLL; (void)_reserved;\n"
- "\tswitch (reason) {\n"
- "\tcase 1: /* DLL loaded */\n"
- "\t\tdlsub_init();\n"
- "\t\tbreak;\n"
- "\tcase 0: /* DLL unloaded */\n"
- "\t\tbreak;\n"
- "}\n"
- );
- fprintf(output,
- "#else\n"
- "#error \"Unrecognized OS.\"\n"
- "#endif\n"
- );
- fprintf(output, "static void dlsub_init(void) {\n"
- "\tvoid *handle = DLSUB_GET_DLHANDLE(\"%s\");\n",
- input_filename);
{
size_t s;
+ const SymbolHashEntry *entry;
+ const char *symbol;
+
+ fprintf(nasm_output, "default rel\n");
+
for (s = 0; s < all_symbols.n_entries; ++s) {
- const SymbolHashEntry *entry = all_symbols.entries[s];
- const char *symbol;
+ entry = all_symbols.entries[s];
if (!entry) continue;
symbol = entry->symbol;
- if (entry->declared) {
- fprintf(output, "\tREAL_%s = (PTR_%s)DLSUB_GET_SYM(handle, \"%s\");\n", symbol, symbol, symbol);
- } else {
- fprintf(stderr, "Warning: Function '%s' declared in library, not found in any header file. It will not be made available.\n", symbol);
+ fprintf(nasm_output, "extern REAL_%s\n", symbol);
+ if (!entry->declared) {
+ fprintf(c_output, "void (*REAL_%s)(void);\n", symbol);
+ if (!no_warn)
+ fprintf(stderr, "Warning: Function '%s' declared in library, not found in any header file. It will not be usable from C.\n", symbol);
}
}
+
+ fprintf(nasm_output, "section .text\n");
+ fprintf(c_output, "static void dlsub_init(void) {\n"
+ "\tvoid *handle = DLSUB_GET_DLHANDLE(DLSUB_REAL_DL_NAME);\n");
+
+ for (s = 0; s < all_symbols.n_entries; ++s) {
+ entry = all_symbols.entries[s];
+ if (!entry) continue;
+ symbol = entry->symbol;
+ fprintf(c_output, "\tREAL_%s = (%s%s)DLSUB_GET_SYM(handle, \"%s\");\n", symbol,
+ entry->declared ? "PTR_" : "void (*)(void)", entry->declared ? symbol : "", symbol);
+ fprintf(nasm_output, "global %s:function\n", symbol);
+ }
+
+
+ for (s = 0; s < all_symbols.n_entries; ++s) {
+ entry = all_symbols.entries[s];
+ if (!entry) continue;
+ symbol = entry->symbol;
+ fprintf(nasm_output, "%s: mov r11, [REAL_%s wrt ..gotpc]\njmp [r11]\n", symbol, symbol);
+ }
}
- fprintf(output, "}\n");
+ fprintf(c_output, "}\n");
- fclose(output);
+ fclose(c_output);
+ fclose(nasm_output);
}
symbol_hash_table_free(&all_symbols);