From 279caa9a5964133d1f94c07907d1424e8391ab5e Mon Sep 17 00:00:00 2001 From: Robert Pengelly Date: Fri, 22 May 2026 05:49:51 +0100 Subject: [PATCH] Added support for creating an implib from a list of comma seperated files --- Makefile.unix | 2 +- Makefile.w32 | 2 +- Makefile.wat | 2 +- lib.c | 16 ++- lib.h | 3 +- ll.c | 303 ++++++++++++++++++++++++++++++++++++++++++++++++++ ll.h | 13 +++ pe.c | 237 ++++++++++++++++++++++++++++++++++----- 8 files changed, 541 insertions(+), 37 deletions(-) create mode 100644 ll.c create mode 100644 ll.h diff --git a/Makefile.unix b/Makefile.unix index 7778788..5c70774 100644 --- a/Makefile.unix +++ b/Makefile.unix @@ -7,7 +7,7 @@ VPATH := $(SRCDIR) CC := gcc CFLAGS := -D_FILE_OFFSET_BITS=64 -O2 -Wall -Werror -Wextra -ansi -pedantic -std=c90 -CSRC := aout.c coff.c dx.c elf.c elks.c hashtab.c ld.c lib.c link.c macho.c map.c mz.c omf.c pe.c report.c section.c symbol.c vector.c write7x.c +CSRC := aout.c coff.c dx.c elf.c elks.c hashtab.c ld.c lib.c link.c ll.c macho.c map.c mz.c omf.c pe.c report.c section.c symbol.c vector.c write7x.c ifeq ($(OS), Windows_NT) all: slink.exe diff --git a/Makefile.w32 b/Makefile.w32 index 5cccc57..9c3381c 100644 --- a/Makefile.w32 +++ b/Makefile.w32 @@ -7,7 +7,7 @@ VPATH := $(SRCDIR) CC := gcc CFLAGS := -D_FILE_OFFSET_BITS=64 -O2 -Wall -Werror -Wextra -CSRC := aout.c coff.c dx.c elf.c elks.c hashtab.c ld.c lib.c link.c macho.c map.c mz.c omf.c pe.c report.c section.c symbol.c vector.c write7x.c +CSRC := aout.c coff.c dx.c elf.c elks.c hashtab.c ld.c lib.c link.c ll.c macho.c map.c mz.c omf.c pe.c report.c section.c symbol.c vector.c write7x.c all: slink.exe diff --git a/Makefile.wat b/Makefile.wat index 0a87a54..375bea5 100644 --- a/Makefile.wat +++ b/Makefile.wat @@ -4,7 +4,7 @@ SRCDIR ?= $(CURDIR) VPATH := $(SRCDIR) -SRC := aout.c coff.c dx.c elf.c elks.c hashtab.c ld.c lib.c link.c macho.c map.c mz.c omf.c pe.c report.c section.c symbol.c vector.c write7x.c +SRC := aout.c coff.c dx.c elf.c elks.c hashtab.c ld.c lib.c link.c ll.c macho.c map.c mz.c omf.c pe.c report.c section.c symbol.c vector.c write7x.c all: slink.exe diff --git a/lib.c b/lib.c index 4d26833..aabed80 100644 --- a/lib.c +++ b/lib.c @@ -33,7 +33,7 @@ static struct options_with_use emulation_table[] = { { 0, 0, 0 }, { 0, 0, 0 }, { &pe_print_help, &pe_check_option, &pe_use_option }, - { &macho_print_help, &macho_check_option, &macho_use_option }, + { &macho_print_help, &macho_check_option, &macho_use_option } }; @@ -544,6 +544,16 @@ void integer_to_array (uint64_t value, unsigned char *dest, int size, int big_en } +char *skip_whitespace (char *p) { + + while (isspace ((int) *p)) { + p++; + } + + return p; + +} + char *xstrdup (const char *__p) { char *p = xmalloc (strlen (__p) + 1); @@ -637,8 +647,8 @@ void dynarray_add (void *ptab, long *nb_ptr, void *data) { void parse_args (int argc, char **argv, int optind) { - struct options_with_use *options_with_use; - struct ld_option *popt; + struct options_with_use *options_with_use = { 0 }; + struct ld_option *popt = { 0 }; const char *optarg, *r; diff --git a/lib.h b/lib.h index f741eb1..c32f6d0 100644 --- a/lib.h +++ b/lib.h @@ -25,8 +25,9 @@ uint64_t array_to_integer (unsigned char *arr, int size, int big_endian); void integer_to_array (uint64_t value, unsigned char *dest, int size, int big_endian); int xstrcasecmp (const char *__s1, const char *__s2); - int strstart (const char *val, const char **str); + +char *skip_whitespace (char *p); void dynarray_add (void *ptab, long *nb_ptr, void *data); char *xstrdup (const char *__p); diff --git a/ll.c b/ll.c new file mode 100644 index 0000000..c59fab3 --- /dev/null +++ b/ll.c @@ -0,0 +1,303 @@ +/****************************************************************************** + * @file ll.c + *****************************************************************************/ +#include +#include +#include +#include + +#include "ll.h" +#include "report.h" + +struct load_line_data { + + char *line, *real_line; + + unsigned long capacity, read_size; + unsigned long end_of_prev_real_line; + + unsigned long *new_line_number_p; + +}; + +#define CAPACITY_INCREMENT 256 +extern void get_filename_and_line_number (const char **__filename_p, unsigned long *__line_number_p); + +extern void *xmalloc (unsigned long __size); +extern void *xrealloc (void *__ptr, unsigned long __size); + +int load_line (char **line_p, char **line_end_p, char **real_line_p, unsigned long *real_line_len_p, unsigned long *newlines_p, FILE *ifp, void **load_line_internal_data_p) { + + struct load_line_data *ll_data = *load_line_internal_data_p; + unsigned long pos_in_line = 0, pos_in_real_line = 0, newlines = 0; + + int in_escape = 0, in_double_quote = 0, in_single_quote = 0; + int in_line_comment = 0, skipping_spaces = 0; + + if (ll_data->end_of_prev_real_line) { + + memmove (ll_data->real_line, ll_data->real_line + ll_data->end_of_prev_real_line, ll_data->read_size - ll_data->end_of_prev_real_line); + ll_data->read_size -= ll_data->end_of_prev_real_line; + + } + + while (1) { + + if (pos_in_line >= ll_data->capacity || pos_in_real_line >= ll_data->capacity) { + + ll_data->capacity += CAPACITY_INCREMENT; + + ll_data->line = xrealloc (ll_data->line, ll_data->capacity + 2); + ll_data->real_line = xrealloc (ll_data->real_line, ll_data->capacity + 1); + + } + + if (pos_in_real_line >= ll_data->read_size) { + + ll_data->read_size = fread (ll_data->real_line + pos_in_real_line, 1, ll_data->capacity - pos_in_real_line, ifp) + pos_in_real_line; + + if (ferror (ifp)) { + return 4; + } + + ll_data->real_line[ll_data->read_size] = '\0'; + + } + + copying: + + if (in_line_comment) { + + while (pos_in_real_line < ll_data->read_size) { + + if (ll_data->real_line[pos_in_real_line] == '\n') { + + in_line_comment = 0; + break; + + } + + pos_in_real_line++; + + } + + } + + if (skipping_spaces) { + + while (pos_in_real_line < ll_data->read_size) { + + if (ll_data->real_line[pos_in_real_line] != ' ' && ll_data->real_line[pos_in_real_line] != '\t') { + + skipping_spaces = 0; + break; + + } + + pos_in_real_line++; + + } + + } + + while (pos_in_real_line < ll_data->read_size && pos_in_line < ll_data->capacity) { + + ll_data->line[pos_in_line] = ll_data->real_line[pos_in_real_line++]; + + if (in_double_quote || in_single_quote) { + + if (in_escape) { + in_escape = 0; + } else if (in_double_quote && ll_data->line[pos_in_line] == '"') { + in_double_quote = 0; + } else if (in_single_quote && ll_data->line[pos_in_line] == '\'') { + in_single_quote = 0; + } else if (ll_data->line[pos_in_line] == '\\') { + in_escape = 1; + } + + if (ll_data->line[pos_in_line] == '\n') { + + int pos = pos_in_line; + + if (pos > 0 && ll_data->line[pos - 1] == '\r') { + ll_data->line[--pos] = '\n'; + } + + if (pos > 0) { + + if (ll_data->line[pos - 1] != '\\') { + + ll_data->line[pos + 1] = '\0'; + ll_data->end_of_prev_real_line = pos_in_real_line; + + *line_p = ll_data->line; + *line_end_p = ll_data->line + pos; + + *real_line_p = ll_data->real_line; + *real_line_len_p = pos_in_real_line; + + *newlines_p = newlines; + return 0; + + } else { + + pos_in_line = pos - 1; + + newlines++; + goto copying; + + } + + } + + } + + } else { + + if (ll_data->line[pos_in_line] == ' ' || ll_data->line[pos_in_line] == '\t') { + + /*ll_data->line[pos_in_line++] = ' ';*/ + + /*skipping_spaces = 1; + goto copying;*/ + + if (ll_data->line[pos_in_line] == '\t') { + + int cnt = 4 - (pos_in_line % 4); + int i = 0; + + ll_data->capacity += CAPACITY_INCREMENT; + + ll_data->line = xrealloc (ll_data->line, ll_data->capacity + 2); + ll_data->real_line = xrealloc (ll_data->real_line, ll_data->capacity + 1); + + for (; i < cnt; i++) { + ll_data->line[pos_in_line++] = ' '; + } + + continue; + + } + + } else if (ll_data->line[pos_in_line] == '\n') { + + if (pos_in_line > 0 && ll_data->line[pos_in_line - 1] == '\r') { + ll_data->line[--pos_in_line] = '\n'; + } + + ll_data->line[pos_in_line + 1] = '\0'; + ll_data->end_of_prev_real_line = pos_in_real_line; + + *line_p = ll_data->line; + *line_end_p = ll_data->line + pos_in_line; + + *real_line_p = ll_data->real_line; + *real_line_len_p = pos_in_real_line; + + *newlines_p = newlines; + return 0; + + } else if (ll_data->line[pos_in_line] == '\\') { + + /*ll_data->line[pos_in_line] = ' ';*/ + pos_in_line--; + + while (pos_in_real_line < ll_data->read_size) { + + if (ll_data->real_line[pos_in_real_line] == '\r' || ll_data->real_line[pos_in_real_line] == '\n') { + + if (ll_data->real_line[pos_in_real_line] == '\r') { + pos_in_real_line++; + } + + if (ll_data->real_line[pos_in_real_line] == '\n') { + pos_in_real_line++; + } + + break; + + } + + pos_in_real_line++; + + } + + newlines++; + continue; + + } else if (ll_data->line[pos_in_line] == '"') { + in_double_quote = 1; + } else if (ll_data->line[pos_in_line] == '\'') { + in_single_quote = 1; + } else if (ll_data->line[pos_in_line] == '#') { + + in_line_comment = 1; + goto copying; + + } + + } + + pos_in_line++; + + } + + if (feof (ifp)) { + + if (ll_data->read_size == 0) { + return 1; + } + + ll_data->line[pos_in_line] = '\n'; + ll_data->line[pos_in_line + 1] = '\0'; + + ll_data->end_of_prev_real_line = 0; + ll_data->read_size = 0; + + *line_p = ll_data->line; + *line_end_p = ll_data->line + pos_in_line; + + *real_line_p = ll_data->real_line; + *real_line_len_p = pos_in_real_line; + + *newlines_p = newlines; + return 0; + + } + + } + +} + +void load_line_destroy_internal_data (void *load_line_internal_data) { + + struct load_line_data *ll_data; + + if (load_line_internal_data) { + + ll_data = load_line_internal_data; + + free (ll_data->line); + free (ll_data->real_line); + free (ll_data); + + } + +} + +void *load_line_create_internal_data (unsigned long *new_line_number_p) { + + struct load_line_data *ll_data = xmalloc (sizeof (*ll_data));; + + ll_data->capacity = 0; + ll_data->line = NULL; + ll_data->real_line = NULL; + + ll_data->read_size = 0; + ll_data->end_of_prev_real_line = 0; + + ll_data->new_line_number_p = new_line_number_p; + return ll_data; + +} diff --git a/ll.h b/ll.h new file mode 100644 index 0000000..b6754ef --- /dev/null +++ b/ll.h @@ -0,0 +1,13 @@ +/****************************************************************************** + * @file ll.h + *****************************************************************************/ +#ifndef _LL_H +#define _LL_H + +#include +int load_line (char **line_p, char **line_end_p, char **real_line_p, unsigned long *real_line_len_p, unsigned long *newlines_p, FILE *ifp, void **load_line_internal_data_p); + +void load_line_destroy_internal_data (void *load_line_internal_data); +void *load_line_create_internal_data (unsigned long *new_line_number_p); + +#endif /* _LL_H */ diff --git a/pe.c b/pe.c index ecf5748..7e2f0a4 100644 --- a/pe.c +++ b/pe.c @@ -13,19 +13,23 @@ #include "ar.h" #include "ld.h" #include "lib.h" +#include "ll.h" #include "pe.h" #include "report.h" #include "section.h" #include "write7x.h" static char *output_implib_filename = 0; -static int kill_at = 0; +static int kill_at = 0, leading_underscore = 1; static unsigned short subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI; static unsigned long section_alignment = DEFAULT_SECTION_ALIGNMENT; static unsigned long file_alignment = DEFAULT_FILE_ALIGNMENT; +static const char **def_list = 0; +long nb_def_list = 0; + struct exclude_symbol { char *name; @@ -36,19 +40,21 @@ struct exclude_symbol { static struct exclude_symbol *exclude_symbols = 0; #define LD_OPTION_IGNORED 0 -#define LD_OPTION_FILE_ALIGNMENT 1 -#define LD_OPTION_KILL_AT 2 -#define LD_OPTION_OUT_IMPLIB 3 -#define LD_OPTION_SECTION_ALIGNMENT 4 -#define LD_OPTION_SHARED 5 -#define LD_OPTION_STACK 6 -#define LD_OPTION_SUBSYSTEM 7 +#define LD_OPTION_DEF_LIST 1 +#define LD_OPTION_FILE_ALIGNMENT 2 +#define LD_OPTION_KILL_AT 3 +#define LD_OPTION_OUT_IMPLIB 4 +#define LD_OPTION_SECTION_ALIGNMENT 5 +#define LD_OPTION_SHARED 6 +#define LD_OPTION_STACK 7 +#define LD_OPTION_SUBSYSTEM 8 static struct ld_option opts[] = { { "--file-alignment", LD_OPTION_TYPE_LONG, LD_OPTION_FILE_ALIGNMENT, LD_OPTION_HAS_ARG }, { "--section-alignment", LD_OPTION_TYPE_LONG, LD_OPTION_SECTION_ALIGNMENT, LD_OPTION_HAS_ARG }, + { "--def-list", LD_OPTION_TYPE_LONG, LD_OPTION_DEF_LIST, LD_OPTION_HAS_ARG }, { "--subsystem", LD_OPTION_TYPE_LONG, LD_OPTION_SUBSYSTEM, LD_OPTION_HAS_ARG }, { "--shared", LD_OPTION_TYPE_LONG, LD_OPTION_SHARED, LD_OPTION_NO_ARG }, @@ -134,6 +140,39 @@ void pe_use_option (const char *cmd_arg, int idx, const char *optarg) { } + case LD_OPTION_DEF_LIST: { + + const char *fn = optarg, *arg, *p; + + for (;;) { + + fn = skip_whitespace ((char *) fn); + + if ((p = strchr (fn, ','))) { + + arg = p; + + while (isspace ((int) *arg)) { + arg--; + } + + dynarray_add (&def_list, &nb_def_list, xstrndup (fn, arg - fn)); + fn = p + 1; + + continue; + + } + + dynarray_add (&def_list, &nb_def_list, xstrdup (fn)); + break; + + } + + leading_underscore = 0; + break; + + } + case LD_OPTION_FILE_ALIGNMENT: { long conversion; @@ -271,6 +310,104 @@ struct name_list { static struct name_list *export_name_list = 0; static struct name_list **last_export_name_list_p = &export_name_list; +static void export_symbol_callback (struct symbol *symbol) { + + struct name_list *name_list; + + if (symbol_is_undefined (symbol)) { + return; + } + + name_list = xmalloc (sizeof (*name_list)); + + if (leading_underscore && symbol->name[0] == '_') { + name_list->name = xstrdup (symbol->name + 1); + } else { + name_list->name = xstrdup (symbol->name); + } + + name_list->info = (symbol->part->section->flags & SECTION_FLAG_CODE) ? 0 : 1; + name_list->next = NULL; + + *last_export_name_list_p = name_list; + last_export_name_list_p = &name_list->next; + +} + +static char is_end_of_line[256] = { + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 /* '\0' and '\n' */ +}; + +static void parse_def (const char *ifile) { + + char *line, *line_end, *real_line, *caret; + unsigned long real_line_len; + + unsigned long new_line_number = 1; + unsigned long newlines; + + int has_exports = 0; + void *load_line_internal_data = NULL; + + struct symbol *symbol; + FILE *fp; + + if (!(fp = fopen (ifile, "r"))) { + + report_at (program_name, 0, REPORT_FATAL_ERROR, "Failed to open '%s' for reading", ifile); + return; + + } + + load_line_internal_data = load_line_create_internal_data (&new_line_number); + + while (!load_line (&line, &line_end, &real_line, &real_line_len, &newlines, fp, &load_line_internal_data)) { + + caret = (line = skip_whitespace (line)); + + if (line < line_end) { + + if (!isalnum ((int) *line) && *line != '_') { + + report_at (ifile, 0, REPORT_ERROR, "expected ident"); + continue; + + } + + while (!is_end_of_line[(int) *line]) { + line++; + } + + *line = '\0'; + + if (!has_exports) { + + if (strcmp (caret, "EXPORTS")) { + + report_at (ifile, 0, REPORT_ERROR, "invalid command"); + continue; + + } + + has_exports = 1; + continue; + + } + + *line = '\0'; + + if ((symbol = symbol_find (caret))) { + export_symbol_callback (symbol); + } + + } + + } + + load_line_destroy_internal_data (load_line_internal_data); + +} + void pe_interpret_dot_drectve_section (/*const char *filename, unsigned char *data, unsigned long data_size, */unsigned char *pos, unsigned long size) { char *temp_buf = xmalloc (size + 1), *p; @@ -816,7 +953,12 @@ struct symbol_info *create_symbol_list (struct export_name *export_name, unsigne symbol_info = xmalloc (sizeof (*symbol_info)); symbol_info->name = xmalloc (7 + strlen (export_name[i].name) + 1); - sprintf (symbol_info->name, "__imp__%s", export_name[i].name); + + if (leading_underscore) { + sprintf (symbol_info->name, "__imp__%s", export_name[i].name); + } else { + sprintf (symbol_info->name, "__imp_%s", export_name[i].name); + } symbol_info->name_length = strlen (symbol_info->name); symbol_info->offset_index = j; @@ -965,7 +1107,7 @@ struct data_entry { static void write_implib (struct export_name *export_names, unsigned long num_names, unsigned long ordinal_base) { - struct symbol_info *info_list, *info, *next_info; + struct symbol_info *info_list, *info; unsigned long *offsets, offset_count, symbol_count, length, i; unsigned long module_name_length; @@ -1407,12 +1549,23 @@ static void write_implib (struct export_name *export_names, unsigned long num_na offsets[4 + i] = offset2; - offset2 += write_file_header (outfile, header_name, bHeaderName, sizeof (import_hdr) + 1 + strlen (export_names[i].name) + 1 + module_name_length + 1, 0); + if (leading_underscore) { + offset2 += write_file_header (outfile, header_name, bHeaderName, sizeof (import_hdr) + 1 + strlen (export_names[i].name) + 1 + module_name_length + 1, 0); + } else { + offset2 += write_file_header (outfile, header_name, bHeaderName, sizeof (import_hdr) + strlen (export_names[i].name) + 1 + module_name_length + 1, 0); + } + memset (&import_hdr, 0, sizeof (import_hdr)); integer_to_array (0xFFFF, import_hdr.Magic2, 2, 0); integer_to_array (IMAGE_FILE_MACHINE_I386, import_hdr.Machine, 2, 0); - integer_to_array (1 + strlen (export_names[i].name) + 1 + module_name_length + 1, import_hdr.SizeOfData, 4, 0); + + if (leading_underscore) { + integer_to_array (1 + strlen (export_names[i].name) + 1 + module_name_length + 1, import_hdr.SizeOfData, 4, 0); + } else { + integer_to_array (strlen (export_names[i].name) + 1 + module_name_length + 1, import_hdr.SizeOfData, 4, 0); + } + integer_to_array (ordinal_base + i, import_hdr.OrdinalHint, 2, 0); switch (export_names[i].export_type) { @@ -1439,8 +1592,17 @@ static void write_implib (struct export_name *export_names, unsigned long num_na integer_to_array (type, import_hdr.Type, 2, 0); offset2 += write_data (outfile, &import_hdr, sizeof (import_hdr)); - name = xmalloc (1 + strlen (export_names[i].name) + 1); - sprintf (name, "_%s", export_names[i].name); + if (leading_underscore) { + + name = xmalloc (1 + strlen (export_names[i].name) + 1); + sprintf (name, "_%s", export_names[i].name); + + } else { + + name = xmalloc (strlen (export_names[i].name) + 1); + sprintf (name, "%s", export_names[i].name); + + } offset2 += write_data (outfile, name, strlen (name) + 1); offset2 += write_data (outfile, module_name, module_name_length + 1); @@ -1472,18 +1634,6 @@ static void write_implib (struct export_name *export_names, unsigned long num_na } fclose (outfile); - - for (info = info_list; info; info = next_info) { - - next_info = info->next; - - free (info->name); - free (info); - - } - - free (header_name); - free (module_name); } @@ -1607,8 +1757,17 @@ static void generate_edata (void) { for (i = 0; i < num_names; i++) { - symbol->name = xmalloc (1 + strlen (export_names[i].name) + 1); - sprintf (symbol->name, "_%s", export_names[i].name); + if (leading_underscore) { + + symbol->name = xmalloc (1 + strlen (export_names[i].name) + 1); + sprintf (symbol->name, "_%s", export_names[i].name); + + } else { + + symbol->name = xmalloc (strlen (export_names[i].name) + 1); + sprintf (symbol->name, "%s", export_names[i].name); + + } symbol->value = 0; symbol->part = 0; @@ -1729,6 +1888,16 @@ void pe_before_link (void) { report_at (program_name, 0, REPORT_WARNING, "base address must be a multiple of 64 KiB (0x10000) according to the specification"); } + if (nb_def_list > 0) { + + long i; + + for (i = 0; i < nb_def_list; i++) { + parse_def (def_list[i]); + } + + } + exclude_symbols_free (); if (export_name_list) { @@ -2062,7 +2231,9 @@ void pe_print_help (void) { fprintf (stderr, " --subsystem Set required OS subsystem.\n"); fprintf (stderr, "\n"); - fprintf (stderr, " -shared, -Bshareable Create a shared library\n"); + fprintf (stderr, " --def-list LIST Create implib from a comma seperated\n"); + fprintf (stderr, " list of files.\n"); + fprintf (stderr, " -shared, -Bshareable Create a shared library.\n"); } @@ -2229,11 +2400,17 @@ static void import_generate_import (const char *import_name, short ordinal_hint, } symbol->name = xmalloc (6 + strlen (import_name) + 1); - sprintf (symbol->name, "__imp_%s", import_name); + + if (leading_underscore) { + sprintf (symbol->name, "__imp_%s", import_name); + } else { + sprintf (symbol->name, "__imp%s", import_name); + } symbol->value = 0; symbol->part = dot_idata5_part; symbol->section_number = 2; + symbol_record_external_symbol (symbol); } -- 2.34.1