xref: /netbsd-src/external/gpl3/binutils.old/dist/binutils/dllwrap.c (revision a24efa7dea9f1f56c3bdb15a927d3516792ace1c)
1 /* dllwrap.c -- wrapper for DLLTOOL and GCC to generate PE style DLLs
2    Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2009,
3    2011, 2012 Free Software Foundation, Inc.
4    Contributed by Mumit Khan (khan@xraylith.wisc.edu).
5 
6    This file is part of GNU Binutils.
7 
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12 
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17 
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
21    02110-1301, USA.  */
22 
23 #include "sysdep.h"
24 #include "bfd.h"
25 #include "libiberty.h"
26 #include "getopt.h"
27 #include "dyn-string.h"
28 #include "bucomm.h"
29 
30 #include <time.h>
31 
32 #ifdef HAVE_SYS_WAIT_H
33 #include <sys/wait.h>
34 #else /* ! HAVE_SYS_WAIT_H */
35 #if ! defined (_WIN32) || defined (__CYGWIN32__)
36 #ifndef WIFEXITED
37 #define WIFEXITED(w)	(((w)&0377) == 0)
38 #endif
39 #ifndef WIFSIGNALED
40 #define WIFSIGNALED(w)	(((w)&0377) != 0177 && ((w)&~0377) == 0)
41 #endif
42 #ifndef WTERMSIG
43 #define WTERMSIG(w)	((w) & 0177)
44 #endif
45 #ifndef WEXITSTATUS
46 #define WEXITSTATUS(w)	(((w) >> 8) & 0377)
47 #endif
48 #else /* defined (_WIN32) && ! defined (__CYGWIN32__) */
49 #ifndef WIFEXITED
50 #define WIFEXITED(w)	(((w) & 0xff) == 0)
51 #endif
52 #ifndef WIFSIGNALED
53 #define WIFSIGNALED(w)	(((w) & 0xff) != 0 && ((w) & 0xff) != 0x7f)
54 #endif
55 #ifndef WTERMSIG
56 #define WTERMSIG(w)	((w) & 0x7f)
57 #endif
58 #ifndef WEXITSTATUS
59 #define WEXITSTATUS(w)	(((w) & 0xff00) >> 8)
60 #endif
61 #endif /* defined (_WIN32) && ! defined (__CYGWIN32__) */
62 #endif /* ! HAVE_SYS_WAIT_H */
63 
64 static char *driver_name = NULL;
65 static char *cygwin_driver_flags =
66   "-Wl,--dll -nostartfiles";
67 static char *mingw32_driver_flags = "-mdll";
68 static char *generic_driver_flags = "-Wl,--dll";
69 
70 static char *entry_point;
71 
72 static char *dlltool_name = NULL;
73 
74 static char *target = TARGET;
75 
76 /* -1: use default, 0: no underscoring, 1: underscore.  */
77 static int is_leading_underscore = -1;
78 
79 typedef enum {
80   UNKNOWN_TARGET,
81   CYGWIN_TARGET,
82   MINGW_TARGET
83 }
84 target_type;
85 
86 typedef enum {
87   UNKNOWN_CPU,
88   X86_CPU,
89   X64_CPU,
90   ARM_CPU
91 }
92 target_cpu;
93 
94 static target_type which_target = UNKNOWN_TARGET;
95 static target_cpu which_cpu = UNKNOWN_CPU;
96 
97 static int dontdeltemps = 0;
98 static int dry_run = 0;
99 
100 static char *prog_name;
101 
102 static int verbose = 0;
103 
104 static char *dll_file_name;
105 static char *dll_name;
106 static char *base_file_name;
107 static char *exp_file_name;
108 static char *def_file_name;
109 static int delete_base_file = 1;
110 static int delete_exp_file = 1;
111 static int delete_def_file = 1;
112 
113 static int run (const char *, char *);
114 static char *mybasename (const char *);
115 static int strhash (const char *);
116 static void usage (FILE *, int);
117 static void display (const char *, va_list) ATTRIBUTE_PRINTF(1,0);
118 static void inform (const char *, ...) ATTRIBUTE_PRINTF_1;
119 static void warn (const char *, ...) ATTRIBUTE_PRINTF_1;
120 static char *look_for_prog (const char *, const char *, int);
121 static char *deduce_name (const char *);
122 static void delete_temp_files (void);
123 static void cleanup_and_exit (int);
124 
125 /**********************************************************************/
126 
127 /* Please keep the following 4 routines in sync with dlltool.c:
128      display ()
129      inform ()
130      look_for_prog ()
131      deduce_name ()
132    It's not worth the hassle to break these out since dllwrap will
133    (hopefully) soon be retired in favor of `ld --shared.  */
134 
135 static void
136 display (const char * message, va_list args)
137 {
138   if (prog_name != NULL)
139     fprintf (stderr, "%s: ", prog_name);
140 
141   vfprintf (stderr, message, args);
142   fputc ('\n', stderr);
143 }
144 
145 
146 static void
147 inform VPARAMS ((const char *message, ...))
148 {
149   VA_OPEN (args, message);
150   VA_FIXEDARG (args, const char *, message);
151 
152   if (!verbose)
153     return;
154 
155   display (message, args);
156 
157   VA_CLOSE (args);
158 }
159 
160 static void
161 warn VPARAMS ((const char *format, ...))
162 {
163   VA_OPEN (args, format);
164   VA_FIXEDARG (args, const char *, format);
165 
166   display (format, args);
167 
168   VA_CLOSE (args);
169 }
170 
171 /* Look for the program formed by concatenating PROG_NAME and the
172    string running from PREFIX to END_PREFIX.  If the concatenated
173    string contains a '/', try appending EXECUTABLE_SUFFIX if it is
174    appropriate.  */
175 
176 static char *
177 look_for_prog (const char *progname, const char *prefix, int end_prefix)
178 {
179   struct stat s;
180   char *cmd;
181 
182   cmd = xmalloc (strlen (prefix)
183 		 + strlen (progname)
184 #ifdef HAVE_EXECUTABLE_SUFFIX
185 		 + strlen (EXECUTABLE_SUFFIX)
186 #endif
187 		 + 10);
188   strcpy (cmd, prefix);
189 
190   sprintf (cmd + end_prefix, "%s", progname);
191 
192   if (strchr (cmd, '/') != NULL)
193     {
194       int found;
195 
196       found = (stat (cmd, &s) == 0
197 #ifdef HAVE_EXECUTABLE_SUFFIX
198 	       || stat (strcat (cmd, EXECUTABLE_SUFFIX), &s) == 0
199 #endif
200 	       );
201 
202       if (! found)
203 	{
204 	  /* xgettext:c-format */
205 	  inform (_("Tried file: %s"), cmd);
206 	  free (cmd);
207 	  return NULL;
208 	}
209     }
210 
211   /* xgettext:c-format */
212   inform (_("Using file: %s"), cmd);
213 
214   return cmd;
215 }
216 
217 /* Deduce the name of the program we are want to invoke.
218    PROG_NAME is the basic name of the program we want to run,
219    eg "as" or "ld".  The catch is that we might want actually
220    run "i386-pe-as" or "ppc-pe-ld".
221 
222    If argv[0] contains the full path, then try to find the program
223    in the same place, with and then without a target-like prefix.
224 
225    Given, argv[0] = /usr/local/bin/i586-cygwin32-dlltool,
226    deduce_name("as") uses the following search order:
227 
228      /usr/local/bin/i586-cygwin32-as
229      /usr/local/bin/as
230      as
231 
232    If there's an EXECUTABLE_SUFFIX, it'll use that as well; for each
233    name, it'll try without and then with EXECUTABLE_SUFFIX.
234 
235    Given, argv[0] = i586-cygwin32-dlltool, it will not even try "as"
236    as the fallback, but rather return i586-cygwin32-as.
237 
238    Oh, and given, argv[0] = dlltool, it'll return "as".
239 
240    Returns a dynamically allocated string.  */
241 
242 static char *
243 deduce_name (const char * name)
244 {
245   char *cmd;
246   const char *dash;
247   const char *slash;
248   const char *cp;
249 
250   dash = NULL;
251   slash = NULL;
252   for (cp = prog_name; *cp != '\0'; ++cp)
253     {
254       if (*cp == '-')
255 	dash = cp;
256 
257       if (
258 #if defined(__DJGPP__) || defined (__CYGWIN__) || defined(__WIN32__)
259 	  *cp == ':' || *cp == '\\' ||
260 #endif
261 	  *cp == '/')
262 	{
263 	  slash = cp;
264 	  dash = NULL;
265 	}
266     }
267 
268   cmd = NULL;
269 
270   if (dash != NULL)
271     /* First, try looking for a prefixed NAME in the
272        PROG_NAME directory, with the same prefix as PROG_NAME.  */
273     cmd = look_for_prog (name, prog_name, dash - prog_name + 1);
274 
275   if (slash != NULL && cmd == NULL)
276     /* Next, try looking for a NAME in the same directory as
277        that of this program.  */
278     cmd = look_for_prog (name, prog_name, slash - prog_name + 1);
279 
280   if (cmd == NULL)
281     /* Just return NAME as is.  */
282     cmd = xstrdup (name);
283 
284   return cmd;
285 }
286 
287 static void
288 delete_temp_files (void)
289 {
290   if (delete_base_file && base_file_name)
291     {
292       if (verbose)
293 	{
294 	  if (dontdeltemps)
295 	    warn (_("Keeping temporary base file %s"), base_file_name);
296 	  else
297 	    warn (_("Deleting temporary base file %s"), base_file_name);
298 	}
299       if (! dontdeltemps)
300 	{
301 	  unlink (base_file_name);
302 	  free (base_file_name);
303 	}
304     }
305 
306   if (delete_exp_file && exp_file_name)
307     {
308       if (verbose)
309 	{
310 	  if (dontdeltemps)
311 	    warn (_("Keeping temporary exp file %s"), exp_file_name);
312 	  else
313 	    warn (_("Deleting temporary exp file %s"), exp_file_name);
314 	}
315       if (! dontdeltemps)
316 	{
317 	  unlink (exp_file_name);
318 	  free (exp_file_name);
319 	}
320     }
321   if (delete_def_file && def_file_name)
322     {
323       if (verbose)
324 	{
325 	  if (dontdeltemps)
326 	    warn (_("Keeping temporary def file %s"), def_file_name);
327 	  else
328 	    warn (_("Deleting temporary def file %s"), def_file_name);
329 	}
330       if (! dontdeltemps)
331 	{
332 	  unlink (def_file_name);
333 	  free (def_file_name);
334 	}
335     }
336 }
337 
338 static void
339 cleanup_and_exit (int status)
340 {
341   delete_temp_files ();
342   exit (status);
343 }
344 
345 static int
346 run (const char *what, char *args)
347 {
348   char *s;
349   int pid, wait_status, retcode;
350   int i;
351   const char **argv;
352   char *errmsg_fmt, *errmsg_arg;
353   char *temp_base = choose_temp_base ();
354   int in_quote;
355   char sep;
356 
357   if (verbose || dry_run)
358     fprintf (stderr, "%s %s\n", what, args);
359 
360   /* Count the args */
361   i = 0;
362   for (s = args; *s; s++)
363     if (*s == ' ')
364       i++;
365   i++;
366   argv = alloca (sizeof (char *) * (i + 3));
367   i = 0;
368   argv[i++] = what;
369   s = args;
370   while (1)
371     {
372       while (*s == ' ' && *s != 0)
373 	s++;
374       if (*s == 0)
375 	break;
376       in_quote = (*s == '\'' || *s == '"');
377       sep = (in_quote) ? *s++ : ' ';
378       argv[i++] = s;
379       while (*s != sep && *s != 0)
380 	s++;
381       if (*s == 0)
382 	break;
383       *s++ = 0;
384       if (in_quote)
385 	s++;
386     }
387   argv[i++] = NULL;
388 
389   if (dry_run)
390     return 0;
391 
392   pid = pexecute (argv[0], (char * const *) argv, prog_name, temp_base,
393 		  &errmsg_fmt, &errmsg_arg, PEXECUTE_ONE | PEXECUTE_SEARCH);
394 
395   if (pid == -1)
396     {
397       int errno_val = errno;
398 
399       fprintf (stderr, "%s: ", prog_name);
400       fprintf (stderr, errmsg_fmt, errmsg_arg);
401       fprintf (stderr, ": %s\n", strerror (errno_val));
402       return 1;
403     }
404 
405   retcode = 0;
406   pid = pwait (pid, &wait_status, 0);
407   if (pid == -1)
408     {
409       warn (_("pwait returns: %s"), strerror (errno));
410       retcode = 1;
411     }
412   else if (WIFSIGNALED (wait_status))
413     {
414       warn (_("subprocess got fatal signal %d"), WTERMSIG (wait_status));
415       retcode = 1;
416     }
417   else if (WIFEXITED (wait_status))
418     {
419       if (WEXITSTATUS (wait_status) != 0)
420 	{
421 	  warn (_("%s exited with status %d"), what, WEXITSTATUS (wait_status));
422 	  retcode = 1;
423 	}
424     }
425   else
426     retcode = 1;
427 
428   return retcode;
429 }
430 
431 static char *
432 mybasename (const char *name)
433 {
434   const char *base = name;
435 
436   while (*name)
437     {
438       if (*name == '/' || *name == '\\')
439 	{
440 	  base = name + 1;
441 	}
442       ++name;
443     }
444   return (char *) base;
445 }
446 
447 static int
448 strhash (const char *str)
449 {
450   const unsigned char *s;
451   unsigned long hash;
452   unsigned int c;
453   unsigned int len;
454 
455   hash = 0;
456   len = 0;
457   s = (const unsigned char *) str;
458   while ((c = *s++) != '\0')
459     {
460       hash += c + (c << 17);
461       hash ^= hash >> 2;
462       ++len;
463     }
464   hash += len + (len << 17);
465   hash ^= hash >> 2;
466 
467   return hash;
468 }
469 
470 /**********************************************************************/
471 
472 static void
473 usage (FILE *file, int status)
474 {
475   fprintf (file, _("Usage %s <option(s)> <object-file(s)>\n"), prog_name);
476   fprintf (file, _("  Generic options:\n"));
477   fprintf (file, _("   @<file>                Read options from <file>\n"));
478   fprintf (file, _("   --quiet, -q            Work quietly\n"));
479   fprintf (file, _("   --verbose, -v          Verbose\n"));
480   fprintf (file, _("   --version              Print dllwrap version\n"));
481   fprintf (file, _("   --implib <outname>     Synonym for --output-lib\n"));
482   fprintf (file, _("  Options for %s:\n"), prog_name);
483   fprintf (file, _("   --driver-name <driver> Defaults to \"gcc\"\n"));
484   fprintf (file, _("   --driver-flags <flags> Override default ld flags\n"));
485   fprintf (file, _("   --dlltool-name <dlltool> Defaults to \"dlltool\"\n"));
486   fprintf (file, _("   --entry <entry>        Specify alternate DLL entry point\n"));
487   fprintf (file, _("   --image-base <base>    Specify image base address\n"));
488   fprintf (file, _("   --target <machine>     i386-cygwin32 or i386-mingw32\n"));
489   fprintf (file, _("   --dry-run              Show what needs to be run\n"));
490   fprintf (file, _("   --mno-cygwin           Create Mingw DLL\n"));
491   fprintf (file, _("  Options passed to DLLTOOL:\n"));
492   fprintf (file, _("   --machine <machine>\n"));
493   fprintf (file, _("   --output-exp <outname> Generate export file.\n"));
494   fprintf (file, _("   --output-lib <outname> Generate input library.\n"));
495   fprintf (file, _("   --add-indirect         Add dll indirects to export file.\n"));
496   fprintf (file, _("   --dllname <name>       Name of input dll to put into output lib.\n"));
497   fprintf (file, _("   --def <deffile>        Name input .def file\n"));
498   fprintf (file, _("   --output-def <deffile> Name output .def file\n"));
499   fprintf (file, _("   --export-all-symbols     Export all symbols to .def\n"));
500   fprintf (file, _("   --no-export-all-symbols  Only export .drectve symbols\n"));
501   fprintf (file, _("   --exclude-symbols <list> Exclude <list> from .def\n"));
502   fprintf (file, _("   --no-default-excludes    Zap default exclude symbols\n"));
503   fprintf (file, _("   --base-file <basefile> Read linker generated base file\n"));
504   fprintf (file, _("   --no-idata4           Don't generate idata$4 section\n"));
505   fprintf (file, _("   --no-idata5           Don't generate idata$5 section\n"));
506   fprintf (file, _("   -U                     Add underscores to .lib\n"));
507   fprintf (file, _("   -k                     Kill @<n> from exported names\n"));
508   fprintf (file, _("   --add-stdcall-alias    Add aliases without @<n>\n"));
509   fprintf (file, _("   --as <name>            Use <name> for assembler\n"));
510   fprintf (file, _("   --nodelete             Keep temp files.\n"));
511   fprintf (file, _("   --no-leading-underscore  Entrypoint without underscore\n"));
512   fprintf (file, _("   --leading-underscore     Entrypoint with underscore.\n"));
513   fprintf (file, _("  Rest are passed unmodified to the language driver\n"));
514   fprintf (file, "\n\n");
515   if (REPORT_BUGS_TO[0] && status == 0)
516     fprintf (file, _("Report bugs to %s\n"), REPORT_BUGS_TO);
517   exit (status);
518 }
519 
520 #define OPTION_START		149
521 
522 /* GENERIC options.  */
523 #define OPTION_QUIET		(OPTION_START + 1)
524 #define OPTION_VERBOSE		(OPTION_QUIET + 1)
525 #define OPTION_VERSION		(OPTION_VERBOSE + 1)
526 
527 /* DLLWRAP options.  */
528 #define OPTION_DRY_RUN		(OPTION_VERSION + 1)
529 #define OPTION_DRIVER_NAME	(OPTION_DRY_RUN + 1)
530 #define OPTION_DRIVER_FLAGS	(OPTION_DRIVER_NAME + 1)
531 #define OPTION_DLLTOOL_NAME	(OPTION_DRIVER_FLAGS + 1)
532 #define OPTION_ENTRY		(OPTION_DLLTOOL_NAME + 1)
533 #define OPTION_IMAGE_BASE	(OPTION_ENTRY + 1)
534 #define OPTION_TARGET		(OPTION_IMAGE_BASE + 1)
535 #define OPTION_MNO_CYGWIN	(OPTION_TARGET + 1)
536 #define OPTION_NO_LEADING_UNDERSCORE (OPTION_MNO_CYGWIN + 1)
537 #define OPTION_LEADING_UNDERSCORE (OPTION_NO_LEADING_UNDERSCORE + 1)
538 
539 /* DLLTOOL options.  */
540 #define OPTION_NODELETE		(OPTION_LEADING_UNDERSCORE + 1)
541 #define OPTION_DLLNAME		(OPTION_NODELETE + 1)
542 #define OPTION_NO_IDATA4	(OPTION_DLLNAME + 1)
543 #define OPTION_NO_IDATA5	(OPTION_NO_IDATA4 + 1)
544 #define OPTION_OUTPUT_EXP	(OPTION_NO_IDATA5 + 1)
545 #define OPTION_OUTPUT_DEF	(OPTION_OUTPUT_EXP + 1)
546 #define OPTION_EXPORT_ALL_SYMS	(OPTION_OUTPUT_DEF + 1)
547 #define OPTION_NO_EXPORT_ALL_SYMS (OPTION_EXPORT_ALL_SYMS + 1)
548 #define OPTION_EXCLUDE_SYMS	(OPTION_NO_EXPORT_ALL_SYMS + 1)
549 #define OPTION_NO_DEFAULT_EXCLUDES (OPTION_EXCLUDE_SYMS + 1)
550 #define OPTION_OUTPUT_LIB	(OPTION_NO_DEFAULT_EXCLUDES + 1)
551 #define OPTION_DEF		(OPTION_OUTPUT_LIB + 1)
552 #define OPTION_ADD_UNDERSCORE	(OPTION_DEF + 1)
553 #define OPTION_KILLAT		(OPTION_ADD_UNDERSCORE + 1)
554 #define OPTION_HELP		(OPTION_KILLAT + 1)
555 #define OPTION_MACHINE		(OPTION_HELP + 1)
556 #define OPTION_ADD_INDIRECT	(OPTION_MACHINE + 1)
557 #define OPTION_BASE_FILE	(OPTION_ADD_INDIRECT + 1)
558 #define OPTION_AS		(OPTION_BASE_FILE + 1)
559 
560 static const struct option long_options[] =
561 {
562   /* generic options.  */
563   {"quiet", no_argument, NULL, 'q'},
564   {"verbose", no_argument, NULL, 'v'},
565   {"version", no_argument, NULL, OPTION_VERSION},
566   {"implib", required_argument, NULL, OPTION_OUTPUT_LIB},
567 
568   /* dllwrap options.  */
569   {"dry-run", no_argument, NULL, OPTION_DRY_RUN},
570   {"driver-name", required_argument, NULL, OPTION_DRIVER_NAME},
571   {"driver-flags", required_argument, NULL, OPTION_DRIVER_FLAGS},
572   {"dlltool-name", required_argument, NULL, OPTION_DLLTOOL_NAME},
573   {"entry", required_argument, NULL, 'e'},
574   {"image-base", required_argument, NULL, OPTION_IMAGE_BASE},
575   {"target", required_argument, NULL, OPTION_TARGET},
576   {"no-leading-underscore", no_argument, NULL, OPTION_NO_LEADING_UNDERSCORE},
577   {"leading-underscore", no_argument, NULL, OPTION_NO_LEADING_UNDERSCORE},
578 
579   /* dlltool options.  */
580   {"no-delete", no_argument, NULL, 'n'},
581   {"dllname", required_argument, NULL, OPTION_DLLNAME},
582   {"no-idata4", no_argument, NULL, OPTION_NO_IDATA4},
583   {"no-idata5", no_argument, NULL, OPTION_NO_IDATA5},
584   {"output-exp", required_argument, NULL, OPTION_OUTPUT_EXP},
585   {"output-def", required_argument, NULL, OPTION_OUTPUT_DEF},
586   {"export-all-symbols", no_argument, NULL, OPTION_EXPORT_ALL_SYMS},
587   {"no-export-all-symbols", no_argument, NULL, OPTION_NO_EXPORT_ALL_SYMS},
588   {"exclude-symbols", required_argument, NULL, OPTION_EXCLUDE_SYMS},
589   {"no-default-excludes", no_argument, NULL, OPTION_NO_DEFAULT_EXCLUDES},
590   {"output-lib", required_argument, NULL, OPTION_OUTPUT_LIB},
591   {"def", required_argument, NULL, OPTION_DEF},
592   {"add-underscore", no_argument, NULL, 'U'},
593   {"killat", no_argument, NULL, 'k'},
594   {"add-stdcall-alias", no_argument, NULL, 'A'},
595   {"help", no_argument, NULL, 'h'},
596   {"machine", required_argument, NULL, OPTION_MACHINE},
597   {"add-indirect", no_argument, NULL, OPTION_ADD_INDIRECT},
598   {"base-file", required_argument, NULL, OPTION_BASE_FILE},
599   {"as", required_argument, NULL, OPTION_AS},
600   {0, 0, 0, 0}
601 };
602 
603 int main (int, char **);
604 
605 int
606 main (int argc, char **argv)
607 {
608   int c;
609   int i;
610 
611   char **saved_argv = 0;
612   int cmdline_len = 0;
613 
614   int export_all = 0;
615 
616   int *dlltool_arg_indices;
617   int *driver_arg_indices;
618 
619   char *driver_flags = 0;
620   char *output_lib_file_name = 0;
621 
622   dyn_string_t dlltool_cmdline;
623   dyn_string_t driver_cmdline;
624 
625   int def_file_seen = 0;
626 
627   char *image_base_str = 0;
628 
629   prog_name = argv[0];
630 
631 #if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
632   setlocale (LC_MESSAGES, "");
633 #endif
634 #if defined (HAVE_SETLOCALE)
635   setlocale (LC_CTYPE, "");
636 #endif
637   bindtextdomain (PACKAGE, LOCALEDIR);
638   textdomain (PACKAGE);
639 
640   expandargv (&argc, &argv);
641 
642   saved_argv = (char **) xmalloc (argc * sizeof (char*));
643   dlltool_arg_indices = (int *) xmalloc (argc * sizeof (int));
644   driver_arg_indices = (int *) xmalloc (argc * sizeof (int));
645   for (i = 0; i < argc; ++i)
646     {
647       size_t len = strlen (argv[i]);
648       char *arg = (char *) xmalloc (len + 1);
649       strcpy (arg, argv[i]);
650       cmdline_len += len;
651       saved_argv[i] = arg;
652       dlltool_arg_indices[i] = 0;
653       driver_arg_indices[i] = 1;
654     }
655   cmdline_len++;
656 
657   /* We recognize dllwrap and dlltool options, and everything else is
658      passed onto the language driver (eg., to GCC). We collect options
659      to dlltool and driver in dlltool_args and driver_args.  */
660 
661   opterr = 0;
662   while ((c = getopt_long_only (argc, argv, "nkAqve:Uho:l:L:I:",
663 				long_options, (int *) 0)) != EOF)
664     {
665       int dlltool_arg;
666       int driver_arg;
667       int single_word_option_value_pair;
668 
669       dlltool_arg = 0;
670       driver_arg = 1;
671       single_word_option_value_pair = 0;
672 
673       if (c != '?')
674 	{
675 	  /* We recognize this option, so it has to be either dllwrap or
676 	     dlltool option. Do not pass to driver unless it's one of the
677 	     generic options that are passed to all the tools (such as -v)
678 	     which are dealt with later.  */
679 	  driver_arg = 0;
680 	}
681 
682       /* deal with generic and dllwrap options first.  */
683       switch (c)
684 	{
685 	case 'h':
686 	  usage (stdout, 0);
687 	  break;
688 	case 'q':
689 	  verbose = 0;
690 	  break;
691 	case 'v':
692 	  verbose = 1;
693 	  break;
694 	case OPTION_VERSION:
695 	  print_version (prog_name);
696 	  break;
697 	case 'e':
698 	  entry_point = optarg;
699 	  break;
700 	case OPTION_IMAGE_BASE:
701 	  image_base_str = optarg;
702 	  break;
703 	case OPTION_DEF:
704 	  def_file_name = optarg;
705 	  def_file_seen = 1;
706 	  delete_def_file = 0;
707 	  break;
708 	case 'n':
709 	  dontdeltemps = 1;
710 	  dlltool_arg = 1;
711 	  break;
712 	case 'o':
713 	  dll_file_name = optarg;
714 	  break;
715 	case 'I':
716 	case 'l':
717 	case 'L':
718 	  driver_arg = 1;
719 	  break;
720 	case OPTION_DLLNAME:
721 	  dll_name = optarg;
722 	  break;
723 	case OPTION_DRY_RUN:
724 	  dry_run = 1;
725 	  break;
726 	case OPTION_DRIVER_NAME:
727 	  driver_name = optarg;
728 	  break;
729 	case OPTION_DRIVER_FLAGS:
730 	  driver_flags = optarg;
731 	  break;
732 	case OPTION_DLLTOOL_NAME:
733 	  dlltool_name = optarg;
734 	  break;
735 	case OPTION_TARGET:
736 	  target = optarg;
737 	  break;
738 	case OPTION_MNO_CYGWIN:
739 	  target = "i386-mingw32";
740 	  break;
741 	case OPTION_NO_LEADING_UNDERSCORE:
742 	  is_leading_underscore = 0;
743 	  break;
744 	case OPTION_LEADING_UNDERSCORE:
745 	  is_leading_underscore = 1;
746 	  break;
747 	case OPTION_BASE_FILE:
748 	  base_file_name = optarg;
749 	  delete_base_file = 0;
750 	  break;
751 	case OPTION_OUTPUT_EXP:
752 	  exp_file_name = optarg;
753 	  delete_exp_file = 0;
754 	  break;
755 	case OPTION_EXPORT_ALL_SYMS:
756 	  export_all = 1;
757 	  break;
758 	case OPTION_OUTPUT_LIB:
759 	  output_lib_file_name = optarg;
760 	  break;
761 	case '?':
762 	  break;
763 	default:
764 	  dlltool_arg = 1;
765 	  break;
766 	}
767 
768       /* Handle passing through --option=value case.  */
769       if (optarg
770 	  && saved_argv[optind-1][0] == '-'
771 	  && saved_argv[optind-1][1] == '-'
772 	  && strchr (saved_argv[optind-1], '='))
773 	single_word_option_value_pair = 1;
774 
775       if (dlltool_arg)
776 	{
777 	  dlltool_arg_indices[optind-1] = 1;
778 	  if (optarg && ! single_word_option_value_pair)
779 	    {
780 	      dlltool_arg_indices[optind-2] = 1;
781 	    }
782 	}
783 
784       if (! driver_arg)
785 	{
786 	  driver_arg_indices[optind-1] = 0;
787 	  if (optarg && ! single_word_option_value_pair)
788 	    {
789 	      driver_arg_indices[optind-2] = 0;
790 	    }
791 	}
792     }
793 
794   /* Sanity checks.  */
795   if (! dll_name && ! dll_file_name)
796     {
797       warn (_("Must provide at least one of -o or --dllname options"));
798       exit (1);
799     }
800   else if (! dll_name)
801     {
802       dll_name = xstrdup (mybasename (dll_file_name));
803     }
804   else if (! dll_file_name)
805     {
806       dll_file_name = xstrdup (dll_name);
807     }
808 
809   /* Deduce driver-name and dlltool-name from our own.  */
810   if (driver_name == NULL)
811     driver_name = deduce_name ("gcc");
812 
813   if (dlltool_name == NULL)
814     dlltool_name = deduce_name ("dlltool");
815 
816   if (! def_file_seen)
817     {
818       char *fileprefix = choose_temp_base ();
819 
820       def_file_name = (char *) xmalloc (strlen (fileprefix) + 5);
821       sprintf (def_file_name, "%s.def",
822 	       (dontdeltemps) ? mybasename (fileprefix) : fileprefix);
823       delete_def_file = 1;
824       free (fileprefix);
825       delete_def_file = 1;
826       warn (_("no export definition file provided.\n\
827 Creating one, but that may not be what you want"));
828     }
829 
830   /* Set the target platform.  */
831   if (strstr (target, "cygwin"))
832     which_target = CYGWIN_TARGET;
833   else if (strstr (target, "mingw"))
834     which_target = MINGW_TARGET;
835   else
836     which_target = UNKNOWN_TARGET;
837 
838   if (! strncmp (target, "arm", 3))
839     which_cpu = ARM_CPU;
840   else if (!strncmp (target, "x86_64", 6)
841 	   || !strncmp (target, "athlon64", 8)
842 	   || !strncmp (target, "amd64", 5))
843     which_cpu = X64_CPU;
844   else if (target[0] == 'i' && (target[1] >= '3' && target[1] <= '6')
845 	   && target[2] == '8' && target[3] == '6')
846     which_cpu = X86_CPU;
847   else
848     which_cpu = UNKNOWN_CPU;
849 
850   if (is_leading_underscore == -1)
851     is_leading_underscore = (which_cpu != X64_CPU && which_cpu != ARM_CPU);
852 
853   /* Re-create the command lines as a string, taking care to quote stuff.  */
854   dlltool_cmdline = dyn_string_new (cmdline_len);
855   if (verbose)
856     dyn_string_append_cstr (dlltool_cmdline, " -v");
857 
858   dyn_string_append_cstr (dlltool_cmdline, " --dllname ");
859   dyn_string_append_cstr (dlltool_cmdline, dll_name);
860 
861   for (i = 1; i < argc; ++i)
862     {
863       if (dlltool_arg_indices[i])
864 	{
865 	  char *arg = saved_argv[i];
866 	  int quote = (strchr (arg, ' ') || strchr (arg, '\t'));
867 	  dyn_string_append_cstr (dlltool_cmdline,
868 	                     (quote) ? " \"" : " ");
869 	  dyn_string_append_cstr (dlltool_cmdline, arg);
870 	  dyn_string_append_cstr (dlltool_cmdline,
871 	                     (quote) ? "\"" : "");
872 	}
873     }
874 
875   driver_cmdline = dyn_string_new (cmdline_len);
876   if (! driver_flags || strlen (driver_flags) == 0)
877     {
878       switch (which_target)
879 	{
880 	case CYGWIN_TARGET:
881 	  driver_flags = cygwin_driver_flags;
882 	  break;
883 
884 	case MINGW_TARGET:
885 	  driver_flags = mingw32_driver_flags;
886 	  break;
887 
888 	default:
889 	  driver_flags = generic_driver_flags;
890 	  break;
891 	}
892     }
893   dyn_string_append_cstr (driver_cmdline, driver_flags);
894   dyn_string_append_cstr (driver_cmdline, " -o ");
895   dyn_string_append_cstr (driver_cmdline, dll_file_name);
896 
897   if (is_leading_underscore == 0)
898     dyn_string_append_cstr (driver_cmdline, " --no-leading-underscore");
899   else if (is_leading_underscore == 1)
900     dyn_string_append_cstr (driver_cmdline, " --leading-underscore");
901 
902   if (! entry_point || strlen (entry_point) == 0)
903     {
904       const char *prefix = (is_leading_underscore != 0 ? "_" : "");
905       const char *postfix = "";
906       const char *name_entry;
907 
908       if (which_cpu == X86_CPU || which_cpu == UNKNOWN_CPU)
909 	postfix = "@12";
910 
911       switch (which_target)
912 	{
913 	case CYGWIN_TARGET:
914 	  name_entry = "_cygwin_dll_entry";
915 	  break;
916 
917 	case MINGW_TARGET:
918 	  name_entry = "DllMainCRTStartup";
919 	  break;
920 
921 	default:
922 	  name_entry = "DllMain";
923 	  break;
924 	}
925       entry_point =
926 	(char *) malloc (strlen (name_entry) + strlen (prefix)
927 			 + strlen (postfix) + 1);
928       sprintf (entry_point, "%s%s%s", prefix, name_entry, postfix);
929     }
930   dyn_string_append_cstr (driver_cmdline, " -Wl,-e,");
931   dyn_string_append_cstr (driver_cmdline, entry_point);
932   dyn_string_append_cstr (dlltool_cmdline, " --exclude-symbol=");
933   dyn_string_append_cstr (dlltool_cmdline,
934                     (entry_point[0] == '_') ? entry_point+1 : entry_point);
935 
936   if (! image_base_str || strlen (image_base_str) == 0)
937     {
938       char *tmpbuf = (char *) xmalloc (sizeof ("0x12345678") + 1);
939       unsigned long hash = strhash (dll_file_name);
940       sprintf (tmpbuf, "0x%.8lX", 0x60000000|((hash<<16)&0xFFC0000));
941       image_base_str = tmpbuf;
942     }
943 
944   dyn_string_append_cstr (driver_cmdline, " -Wl,--image-base,");
945   dyn_string_append_cstr (driver_cmdline, image_base_str);
946 
947   if (verbose)
948     {
949       dyn_string_append_cstr (driver_cmdline, " -v");
950     }
951 
952   for (i = 1; i < argc; ++i)
953     {
954       if (driver_arg_indices[i])
955 	{
956 	  char *arg = saved_argv[i];
957 	  int quote = (strchr (arg, ' ') || strchr (arg, '\t'));
958 	  dyn_string_append_cstr (driver_cmdline,
959 	                     (quote) ? " \"" : " ");
960 	  dyn_string_append_cstr (driver_cmdline, arg);
961 	  dyn_string_append_cstr (driver_cmdline,
962 	                     (quote) ? "\"" : "");
963 	}
964     }
965 
966   /* Step pre-1. If no --def <EXPORT_DEF> is specified,
967      then create it and then pass it on.  */
968 
969   if (! def_file_seen)
970     {
971       dyn_string_t step_pre1;
972 
973       step_pre1 = dyn_string_new (1024);
974 
975       dyn_string_append_cstr (step_pre1, dlltool_cmdline->s);
976       if (export_all)
977 	{
978 	  dyn_string_append_cstr (step_pre1, " --export-all --exclude-symbol=");
979 	  dyn_string_append_cstr (step_pre1,
980 	  "_cygwin_dll_entry@12,DllMainCRTStartup@12,DllMain@12,DllEntryPoint@12");
981 	}
982       dyn_string_append_cstr (step_pre1, " --output-def ");
983       dyn_string_append_cstr (step_pre1, def_file_name);
984 
985       for (i = 1; i < argc; ++i)
986 	{
987 	  if (driver_arg_indices[i])
988 	    {
989 	      char *arg = saved_argv[i];
990 	      size_t len = strlen (arg);
991 	      if (len >= 2 && arg[len-2] == '.'
992 	          && (arg[len-1] == 'o' || arg[len-1] == 'a'))
993 		{
994 		  int quote = (strchr (arg, ' ') || strchr (arg, '\t'));
995 		  dyn_string_append_cstr (step_pre1,
996 				     (quote) ? " \"" : " ");
997 		  dyn_string_append_cstr (step_pre1, arg);
998 		  dyn_string_append_cstr (step_pre1,
999 				     (quote) ? "\"" : "");
1000 		}
1001 	    }
1002 	}
1003 
1004       if (run (dlltool_name, step_pre1->s))
1005 	cleanup_and_exit (1);
1006 
1007       dyn_string_delete (step_pre1);
1008     }
1009 
1010   dyn_string_append_cstr (dlltool_cmdline, " --def ");
1011   dyn_string_append_cstr (dlltool_cmdline, def_file_name);
1012 
1013   if (verbose)
1014     {
1015       fprintf (stderr, _("DLLTOOL name    : %s\n"), dlltool_name);
1016       fprintf (stderr, _("DLLTOOL options : %s\n"), dlltool_cmdline->s);
1017       fprintf (stderr, _("DRIVER name     : %s\n"), driver_name);
1018       fprintf (stderr, _("DRIVER options  : %s\n"), driver_cmdline->s);
1019     }
1020 
1021   /* Step 1. Call GCC/LD to create base relocation file. If using GCC, the
1022      driver command line will look like the following:
1023 
1024         % gcc -Wl,--dll --Wl,--base-file,foo.base [rest of command line]
1025 
1026      If the user does not specify a base name, create temporary one that
1027      is deleted at exit.  */
1028 
1029   if (! base_file_name)
1030     {
1031       char *fileprefix = choose_temp_base ();
1032       base_file_name = (char *) xmalloc (strlen (fileprefix) + 6);
1033       sprintf (base_file_name, "%s.base",
1034 	       (dontdeltemps) ? mybasename (fileprefix) : fileprefix);
1035       delete_base_file = 1;
1036       free (fileprefix);
1037     }
1038 
1039   {
1040     int quote;
1041 
1042     dyn_string_t step1 = dyn_string_new (driver_cmdline->length
1043 					 + strlen (base_file_name)
1044 					 + 20);
1045     dyn_string_append_cstr (step1, "-Wl,--base-file,");
1046     quote = (strchr (base_file_name, ' ')
1047 	     || strchr (base_file_name, '\t'));
1048     dyn_string_append_cstr (step1,
1049 	               (quote) ? "\"" : "");
1050     dyn_string_append_cstr (step1, base_file_name);
1051     dyn_string_append_cstr (step1,
1052 	               (quote) ? "\"" : "");
1053     if (driver_cmdline->length)
1054       {
1055 	dyn_string_append_cstr (step1, " ");
1056 	dyn_string_append_cstr (step1, driver_cmdline->s);
1057       }
1058 
1059     if (run (driver_name, step1->s))
1060       cleanup_and_exit (1);
1061 
1062     dyn_string_delete (step1);
1063   }
1064 
1065   /* Step 2. generate the exp file by running dlltool.
1066      dlltool command line will look like the following:
1067 
1068         % dlltool -Wl,--dll --Wl,--base-file,foo.base [rest of command line]
1069 
1070      If the user does not specify a base name, create temporary one that
1071      is deleted at exit.  */
1072 
1073   if (! exp_file_name)
1074     {
1075       char *p = strrchr (dll_name, '.');
1076       size_t prefix_len = (p) ? (size_t) (p - dll_name) : strlen (dll_name);
1077 
1078       exp_file_name = (char *) xmalloc (prefix_len + 4 + 1);
1079       strncpy (exp_file_name, dll_name, prefix_len);
1080       exp_file_name[prefix_len] = '\0';
1081       strcat (exp_file_name, ".exp");
1082       delete_exp_file = 1;
1083     }
1084 
1085   {
1086     int quote;
1087 
1088     dyn_string_t step2 = dyn_string_new (dlltool_cmdline->length
1089 					 + strlen (base_file_name)
1090 					 + strlen (exp_file_name)
1091 				         + 20);
1092 
1093     dyn_string_append_cstr (step2, "--base-file ");
1094     quote = (strchr (base_file_name, ' ')
1095 	     || strchr (base_file_name, '\t'));
1096     dyn_string_append_cstr (step2,
1097 	               (quote) ? "\"" : "");
1098     dyn_string_append_cstr (step2, base_file_name);
1099     dyn_string_append_cstr (step2,
1100 	               (quote) ? "\" " : " ");
1101 
1102     dyn_string_append_cstr (step2, "--output-exp ");
1103     quote = (strchr (exp_file_name, ' ')
1104 	     || strchr (exp_file_name, '\t'));
1105     dyn_string_append_cstr (step2,
1106 	               (quote) ? "\"" : "");
1107     dyn_string_append_cstr (step2, exp_file_name);
1108     dyn_string_append_cstr (step2,
1109 	               (quote) ? "\"" : "");
1110 
1111     if (dlltool_cmdline->length)
1112       {
1113 	dyn_string_append_cstr (step2, " ");
1114 	dyn_string_append_cstr (step2, dlltool_cmdline->s);
1115       }
1116 
1117     if (run (dlltool_name, step2->s))
1118       cleanup_and_exit (1);
1119 
1120     dyn_string_delete (step2);
1121   }
1122 
1123   /*
1124    * Step 3. Call GCC/LD to again, adding the exp file this time.
1125    * driver command line will look like the following:
1126    *
1127    *    % gcc -Wl,--dll --Wl,--base-file,foo.base foo.exp [rest ...]
1128    */
1129 
1130   {
1131     int quote;
1132 
1133     dyn_string_t step3 = dyn_string_new (driver_cmdline->length
1134 					 + strlen (exp_file_name)
1135 					 + strlen (base_file_name)
1136 				         + 20);
1137     dyn_string_append_cstr (step3, "-Wl,--base-file,");
1138     quote = (strchr (base_file_name, ' ')
1139 	     || strchr (base_file_name, '\t'));
1140     dyn_string_append_cstr (step3,
1141 	               (quote) ? "\"" : "");
1142     dyn_string_append_cstr (step3, base_file_name);
1143     dyn_string_append_cstr (step3,
1144 	               (quote) ? "\" " : " ");
1145 
1146     quote = (strchr (exp_file_name, ' ')
1147 	     || strchr (exp_file_name, '\t'));
1148     dyn_string_append_cstr (step3,
1149 	               (quote) ? "\"" : "");
1150     dyn_string_append_cstr (step3, exp_file_name);
1151     dyn_string_append_cstr (step3,
1152 	               (quote) ? "\"" : "");
1153 
1154     if (driver_cmdline->length)
1155       {
1156 	dyn_string_append_cstr (step3, " ");
1157 	dyn_string_append_cstr (step3, driver_cmdline->s);
1158       }
1159 
1160     if (run (driver_name, step3->s))
1161       cleanup_and_exit (1);
1162 
1163     dyn_string_delete (step3);
1164   }
1165 
1166 
1167   /*
1168    * Step 4. Run DLLTOOL again using the same command line.
1169    */
1170 
1171   {
1172     int quote;
1173     dyn_string_t step4 = dyn_string_new (dlltool_cmdline->length
1174 					 + strlen (base_file_name)
1175 					 + strlen (exp_file_name)
1176 				         + 20);
1177 
1178     dyn_string_append_cstr (step4, "--base-file ");
1179     quote = (strchr (base_file_name, ' ')
1180 	     || strchr (base_file_name, '\t'));
1181     dyn_string_append_cstr (step4,
1182 	               (quote) ? "\"" : "");
1183     dyn_string_append_cstr (step4, base_file_name);
1184     dyn_string_append_cstr (step4,
1185 	               (quote) ? "\" " : " ");
1186 
1187     dyn_string_append_cstr (step4, "--output-exp ");
1188     quote = (strchr (exp_file_name, ' ')
1189 	     || strchr (exp_file_name, '\t'));
1190     dyn_string_append_cstr (step4,
1191 	               (quote) ? "\"" : "");
1192     dyn_string_append_cstr (step4, exp_file_name);
1193     dyn_string_append_cstr (step4,
1194 	               (quote) ? "\"" : "");
1195 
1196     if (dlltool_cmdline->length)
1197       {
1198 	dyn_string_append_cstr (step4, " ");
1199 	dyn_string_append_cstr (step4, dlltool_cmdline->s);
1200       }
1201 
1202     if (output_lib_file_name)
1203       {
1204 	dyn_string_append_cstr (step4, " --output-lib ");
1205 	dyn_string_append_cstr (step4, output_lib_file_name);
1206       }
1207 
1208     if (run (dlltool_name, step4->s))
1209       cleanup_and_exit (1);
1210 
1211     dyn_string_delete (step4);
1212   }
1213 
1214 
1215   /*
1216    * Step 5. Link it all together and be done with it.
1217    * driver command line will look like the following:
1218    *
1219    *    % gcc -Wl,--dll foo.exp [rest ...]
1220    *
1221    */
1222 
1223   {
1224     int quote;
1225 
1226     dyn_string_t step5 = dyn_string_new (driver_cmdline->length
1227 					 + strlen (exp_file_name)
1228 				         + 20);
1229     quote = (strchr (exp_file_name, ' ')
1230 	     || strchr (exp_file_name, '\t'));
1231     dyn_string_append_cstr (step5,
1232 	               (quote) ? "\"" : "");
1233     dyn_string_append_cstr (step5, exp_file_name);
1234     dyn_string_append_cstr (step5,
1235 	               (quote) ? "\"" : "");
1236 
1237     if (driver_cmdline->length)
1238       {
1239 	dyn_string_append_cstr (step5, " ");
1240 	dyn_string_append_cstr (step5, driver_cmdline->s);
1241       }
1242 
1243     if (run (driver_name, step5->s))
1244       cleanup_and_exit (1);
1245 
1246     dyn_string_delete (step5);
1247   }
1248 
1249   cleanup_and_exit (0);
1250 
1251   return 0;
1252 }
1253