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