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