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