/* dllwrap.c -- wrapper for DLLTOOL and GCC to generate PE style DLLs
- Copyright 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+ Copyright (C) 1998-2019 Free Software Foundation, Inc.
Contributed by Mumit Khan (khan@xraylith.wisc.edu).
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- 02111-1307, USA. */
-
-/* AIX requires this to be the first thing in the file. */
-#ifndef __GNUC__
-# ifdef _AIX
- #pragma alloca
-#endif
-#endif
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+#include "sysdep.h"
#include "bfd.h"
#include "libiberty.h"
-#include "bucomm.h"
#include "getopt.h"
#include "dyn-string.h"
+#include "bucomm.h"
#include <time.h>
-#include <sys/stat.h>
-
-#ifdef ANSI_PROTOTYPES
-#include <stdarg.h>
-#else
-#include <varargs.h>
-#endif
#ifdef HAVE_SYS_WAIT_H
#include <sys/wait.h>
static char *target = TARGET;
+/* -1: use default, 0: no underscoring, 1: underscore. */
+static int is_leading_underscore = -1;
+
typedef enum {
UNKNOWN_TARGET,
CYGWIN_TARGET,
}
target_type;
+typedef enum {
+ UNKNOWN_CPU,
+ X86_CPU,
+ X64_CPU,
+ ARM_CPU
+}
+target_cpu;
+
static target_type which_target = UNKNOWN_TARGET;
+static target_cpu which_cpu = UNKNOWN_CPU;
static int dontdeltemps = 0;
static int dry_run = 0;
-static char *program_name;
+static char *prog_name;
static int verbose = 0;
static char *mybasename (const char *);
static int strhash (const char *);
static void usage (FILE *, int);
-static void display (const char *, va_list);
-static void inform (const char *, ...);
-static void warn (const char *, ...);
+static void display (const char *, va_list) ATTRIBUTE_PRINTF(1,0);
+static void inform (const char *, ...) ATTRIBUTE_PRINTF_1;
+static void warn (const char *, ...) ATTRIBUTE_PRINTF_1;
static char *look_for_prog (const char *, const char *, int);
static char *deduce_name (const char *);
static void delete_temp_files (void);
static void
display (const char * message, va_list args)
{
- if (program_name != NULL)
- fprintf (stderr, "%s: ", program_name);
+ if (prog_name != NULL)
+ fprintf (stderr, "%s: ", prog_name);
vfprintf (stderr, message, args);
fputc ('\n', stderr);
static void
-inform VPARAMS ((const char *message, ...))
+inform (const char *message, ...)
{
- VA_OPEN (args, message);
- VA_FIXEDARG (args, const char *, message);
+ va_list args;
+
+ va_start (args, message);
if (!verbose)
return;
display (message, args);
- VA_CLOSE (args);
+ va_end (args);
}
static void
-warn VPARAMS ((const char *format, ...))
+warn (const char *format, ...)
{
- VA_OPEN (args, format);
- VA_FIXEDARG (args, const char *, format);
+ va_list args;
+
+ va_start (args, format);
display (format, args);
- VA_CLOSE (args);
+ va_end (args);
}
/* Look for the program formed by concatenating PROG_NAME and the
appropriate. */
static char *
-look_for_prog (const char *prog_name, const char *prefix, int end_prefix)
+look_for_prog (const char *progname, const char *prefix, int end_prefix)
{
struct stat s;
char *cmd;
cmd = xmalloc (strlen (prefix)
- + strlen (prog_name)
+ + strlen (progname)
#ifdef HAVE_EXECUTABLE_SUFFIX
+ strlen (EXECUTABLE_SUFFIX)
#endif
+ 10);
strcpy (cmd, prefix);
- sprintf (cmd + end_prefix, "%s", prog_name);
+ sprintf (cmd + end_prefix, "%s", progname);
if (strchr (cmd, '/') != NULL)
{
Returns a dynamically allocated string. */
static char *
-deduce_name (const char *prog_name)
+deduce_name (const char * name)
{
char *cmd;
- char *dash, *slash, *cp;
+ const char *dash;
+ const char *slash;
+ const char *cp;
dash = NULL;
slash = NULL;
- for (cp = program_name; *cp != '\0'; ++cp)
+ for (cp = prog_name; *cp != '\0'; ++cp)
{
if (*cp == '-')
dash = cp;
+
if (
#if defined(__DJGPP__) || defined (__CYGWIN__) || defined(__WIN32__)
*cp == ':' || *cp == '\\' ||
cmd = NULL;
if (dash != NULL)
- {
- /* First, try looking for a prefixed PROG_NAME in the
- PROGRAM_NAME directory, with the same prefix as PROGRAM_NAME. */
- cmd = look_for_prog (prog_name, program_name, dash - program_name + 1);
- }
+ /* First, try looking for a prefixed NAME in the
+ PROG_NAME directory, with the same prefix as PROG_NAME. */
+ cmd = look_for_prog (name, prog_name, dash - prog_name + 1);
if (slash != NULL && cmd == NULL)
- {
- /* Next, try looking for a PROG_NAME in the same directory as
- that of this program. */
- cmd = look_for_prog (prog_name, program_name, slash - program_name + 1);
- }
+ /* Next, try looking for a NAME in the same directory as
+ that of this program. */
+ cmd = look_for_prog (name, prog_name, slash - prog_name + 1);
if (cmd == NULL)
- {
- /* Just return PROG_NAME as is. */
- cmd = xstrdup (prog_name);
- }
+ /* Just return NAME as is. */
+ cmd = xstrdup (name);
return cmd;
}
if (*s == ' ')
i++;
i++;
- argv = alloca (sizeof (char *) * (i + 3));
+ argv = xmalloc (sizeof (char *) * (i + 3));
i = 0;
argv[i++] = what;
s = args;
if (dry_run)
return 0;
- pid = pexecute (argv[0], (char * const *) argv, program_name, temp_base,
+ pid = pexecute (argv[0], (char * const *) argv, prog_name, temp_base,
&errmsg_fmt, &errmsg_arg, PEXECUTE_ONE | PEXECUTE_SEARCH);
+ free (argv);
if (pid == -1)
{
int errno_val = errno;
- fprintf (stderr, "%s: ", program_name);
+ fprintf (stderr, "%s: ", prog_name);
fprintf (stderr, errmsg_fmt, errmsg_arg);
fprintf (stderr, ": %s\n", strerror (errno_val));
return 1;
pid = pwait (pid, &wait_status, 0);
if (pid == -1)
{
- warn ("wait: %s", strerror (errno));
+ warn (_("pwait returns: %s"), strerror (errno));
retcode = 1;
}
else if (WIFSIGNALED (wait_status))
static void
usage (FILE *file, int status)
{
- fprintf (file, _("Usage %s <option(s)> <object-file(s)>\n"), program_name);
+ fprintf (file, _("Usage %s <option(s)> <object-file(s)>\n"), prog_name);
fprintf (file, _(" Generic options:\n"));
+ fprintf (file, _(" @<file> Read options from <file>\n"));
fprintf (file, _(" --quiet, -q Work quietly\n"));
fprintf (file, _(" --verbose, -v Verbose\n"));
fprintf (file, _(" --version Print dllwrap version\n"));
fprintf (file, _(" --implib <outname> Synonym for --output-lib\n"));
- fprintf (file, _(" Options for %s:\n"), program_name);
+ fprintf (file, _(" Options for %s:\n"), prog_name);
fprintf (file, _(" --driver-name <driver> Defaults to \"gcc\"\n"));
fprintf (file, _(" --driver-flags <flags> Override default ld flags\n"));
fprintf (file, _(" --dlltool-name <dlltool> Defaults to \"dlltool\"\n"));
fprintf (file, _(" --add-stdcall-alias Add aliases without @<n>\n"));
fprintf (file, _(" --as <name> Use <name> for assembler\n"));
fprintf (file, _(" --nodelete Keep temp files.\n"));
+ fprintf (file, _(" --no-leading-underscore Entrypoint without underscore\n"));
+ fprintf (file, _(" --leading-underscore Entrypoint with underscore.\n"));
fprintf (file, _(" Rest are passed unmodified to the language driver\n"));
fprintf (file, "\n\n");
+ if (REPORT_BUGS_TO[0] && status == 0)
+ fprintf (file, _("Report bugs to %s\n"), REPORT_BUGS_TO);
exit (status);
}
#define OPTION_IMAGE_BASE (OPTION_ENTRY + 1)
#define OPTION_TARGET (OPTION_IMAGE_BASE + 1)
#define OPTION_MNO_CYGWIN (OPTION_TARGET + 1)
+#define OPTION_NO_LEADING_UNDERSCORE (OPTION_MNO_CYGWIN + 1)
+#define OPTION_LEADING_UNDERSCORE (OPTION_NO_LEADING_UNDERSCORE + 1)
/* DLLTOOL options. */
-#define OPTION_NODELETE (OPTION_MNO_CYGWIN + 1)
+#define OPTION_NODELETE (OPTION_LEADING_UNDERSCORE + 1)
#define OPTION_DLLNAME (OPTION_NODELETE + 1)
#define OPTION_NO_IDATA4 (OPTION_DLLNAME + 1)
#define OPTION_NO_IDATA5 (OPTION_NO_IDATA4 + 1)
{"entry", required_argument, NULL, 'e'},
{"image-base", required_argument, NULL, OPTION_IMAGE_BASE},
{"target", required_argument, NULL, OPTION_TARGET},
+ {"no-leading-underscore", no_argument, NULL, OPTION_NO_LEADING_UNDERSCORE},
+ {"leading-underscore", no_argument, NULL, OPTION_NO_LEADING_UNDERSCORE},
/* dlltool options. */
{"no-delete", no_argument, NULL, 'n'},
char *image_base_str = 0;
- program_name = argv[0];
+ prog_name = argv[0];
#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
setlocale (LC_MESSAGES, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
+ expandargv (&argc, &argv);
+
saved_argv = (char **) xmalloc (argc * sizeof (char*));
dlltool_arg_indices = (int *) xmalloc (argc * sizeof (int));
driver_arg_indices = (int *) xmalloc (argc * sizeof (int));
verbose = 1;
break;
case OPTION_VERSION:
- print_version (program_name);
+ print_version (prog_name);
break;
case 'e':
entry_point = optarg;
case OPTION_MNO_CYGWIN:
target = "i386-mingw32";
break;
+ case OPTION_NO_LEADING_UNDERSCORE:
+ is_leading_underscore = 0;
+ break;
+ case OPTION_LEADING_UNDERSCORE:
+ is_leading_underscore = 1;
+ break;
case OPTION_BASE_FILE:
base_file_name = optarg;
delete_base_file = 0;
}
}
- /* sanity checks. */
+ /* Sanity checks. */
if (! dll_name && ! dll_file_name)
{
warn (_("Must provide at least one of -o or --dllname options"));
if (! def_file_seen)
{
char *fileprefix = choose_temp_base ();
+
def_file_name = (char *) xmalloc (strlen (fileprefix) + 5);
sprintf (def_file_name, "%s.def",
(dontdeltemps) ? mybasename (fileprefix) : fileprefix);
Creating one, but that may not be what you want"));
}
- /* set the target platform. */
+ /* Set the target platform. */
if (strstr (target, "cygwin"))
which_target = CYGWIN_TARGET;
else if (strstr (target, "mingw"))
else
which_target = UNKNOWN_TARGET;
- /* re-create the command lines as a string, taking care to quote stuff. */
+ if (! strncmp (target, "arm", 3))
+ which_cpu = ARM_CPU;
+ else if (!strncmp (target, "x86_64", 6)
+ || !strncmp (target, "athlon64", 8)
+ || !strncmp (target, "amd64", 5))
+ which_cpu = X64_CPU;
+ else if (target[0] == 'i' && (target[1] >= '3' && target[1] <= '6')
+ && target[2] == '8' && target[3] == '6')
+ which_cpu = X86_CPU;
+ else
+ which_cpu = UNKNOWN_CPU;
+
+ if (is_leading_underscore == -1)
+ is_leading_underscore = (which_cpu != X64_CPU && which_cpu != ARM_CPU);
+
+ /* Re-create the command lines as a string, taking care to quote stuff. */
dlltool_cmdline = dyn_string_new (cmdline_len);
if (verbose)
- {
- dyn_string_append_cstr (dlltool_cmdline, " -v");
- }
+ dyn_string_append_cstr (dlltool_cmdline, " -v");
+
dyn_string_append_cstr (dlltool_cmdline, " --dllname ");
dyn_string_append_cstr (dlltool_cmdline, dll_name);
dyn_string_append_cstr (driver_cmdline, " -o ");
dyn_string_append_cstr (driver_cmdline, dll_file_name);
+ if (is_leading_underscore == 0)
+ dyn_string_append_cstr (driver_cmdline, " --no-leading-underscore");
+ else if (is_leading_underscore == 1)
+ dyn_string_append_cstr (driver_cmdline, " --leading-underscore");
+
if (! entry_point || strlen (entry_point) == 0)
{
+ const char *prefix = (is_leading_underscore != 0 ? "_" : "");
+ const char *postfix = "";
+ const char *name_entry;
+
+ if (which_cpu == X86_CPU || which_cpu == UNKNOWN_CPU)
+ postfix = "@12";
+
switch (which_target)
{
case CYGWIN_TARGET:
- entry_point = "__cygwin_dll_entry@12";
+ name_entry = "_cygwin_dll_entry";
break;
case MINGW_TARGET:
- entry_point = "_DllMainCRTStartup@12";
+ name_entry = "DllMainCRTStartup";
break;
default:
- entry_point = "_DllMain@12";
+ name_entry = "DllMain";
break;
}
+ entry_point =
+ (char *) malloc (strlen (name_entry) + strlen (prefix)
+ + strlen (postfix) + 1);
+ sprintf (entry_point, "%s%s%s", prefix, name_entry, postfix);
}
dyn_string_append_cstr (driver_cmdline, " -Wl,-e,");
dyn_string_append_cstr (driver_cmdline, entry_point);
}
}
- /*
- * Step pre-1. If no --def <EXPORT_DEF> is specified, then create it
- * and then pass it on.
- */
+ /* Step pre-1. If no --def <EXPORT_DEF> is specified,
+ then create it and then pass it on. */
if (! def_file_seen)
{
- int i;
dyn_string_t step_pre1;
step_pre1 = dyn_string_new (1024);
fprintf (stderr, _("DRIVER options : %s\n"), driver_cmdline->s);
}
- /*
- * Step 1. Call GCC/LD to create base relocation file. If using GCC, the
- * driver command line will look like the following:
- *
- * % gcc -Wl,--dll --Wl,--base-file,foo.base [rest of command line]
- *
- * If the user does not specify a base name, create temporary one that
- * is deleted at exit.
- *
- */
+ /* Step 1. Call GCC/LD to create base relocation file. If using GCC, the
+ driver command line will look like the following:
+
+ % gcc -Wl,--dll --Wl,--base-file,foo.base [rest of command line]
+
+ If the user does not specify a base name, create temporary one that
+ is deleted at exit. */
if (! base_file_name)
{
dyn_string_delete (step1);
}
+ /* Step 2. generate the exp file by running dlltool.
+ dlltool command line will look like the following:
+ % dlltool -Wl,--dll --Wl,--base-file,foo.base [rest of command line]
- /*
- * Step 2. generate the exp file by running dlltool.
- * dlltool command line will look like the following:
- *
- * % dlltool -Wl,--dll --Wl,--base-file,foo.base [rest of command line]
- *
- * If the user does not specify a base name, create temporary one that
- * is deleted at exit.
- *
- */
+ If the user does not specify a base name, create temporary one that
+ is deleted at exit. */
if (! exp_file_name)
{
char *p = strrchr (dll_name, '.');
- size_t prefix_len = (p) ? p - dll_name : strlen (dll_name);
+ size_t prefix_len = (p) ? (size_t) (p - dll_name) : strlen (dll_name);
+
exp_file_name = (char *) xmalloc (prefix_len + 4 + 1);
strncpy (exp_file_name, dll_name, prefix_len);
exp_file_name[prefix_len] = '\0';
{
int quote;
+
dyn_string_t step2 = dyn_string_new (dlltool_cmdline->length
+ strlen (base_file_name)
+ strlen (exp_file_name)