source: trunk/emx/src/emxomf/emxomfld.c@ 3669

Last change on this file since 3669 was 3667, checked in by bird, 15 years ago

emxomfld/weakld: working on AR and ELF support.

  • Property cvs2svn:cvs-rev set to 1.42
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 80.7 KB
Line 
1/* emxomfld.c -- Provide an ld-like interface to the IBM and M$ linkers
2 Copyright (c) 1992-1998 Eberhard Mattes
3 Copyright (c) 2003 InnoTek Systemberatung GmbH
4 Copyright (c) 2003-2004 Knut St. Osmundsen
5
6This file is part of emxomld.
7
8emxomfld is free software; you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
10the Free Software Foundation; either version 2, or (at your option)
11any later version.
12
13emxomfld is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
19along with emxomfld; see the file COPYING. If not, write to
20the Free Software Foundation, 59 Temple Place - Suite 330,
21Boston, MA 02111-1307, USA. */
22
23
24#include <stdio.h>
25#include <stdlib.h>
26#include <alloca.h>
27#include <errno.h>
28#include <string.h>
29#include <process.h>
30#include <io.h>
31#include <fcntl.h>
32#include <sys/types.h>
33#include <sys/stat.h>
34#include <sys/utime.h>
35#include <sys/moddef.h>
36#include <getopt.h>
37#include <alloca.h>
38#include <sys/omflib.h>
39#include <sys/elf.h>
40#include <ar.h>
41#include "defs.h"
42#include "weakld.h"
43
44#define FALSE 0
45#define TRUE 1
46
47/* A member of a linked list of strings such as file names. */
48typedef struct name_list
49{
50 struct name_list *next;
51 unsigned flags;
52 char *name;
53} name_list;
54
55/* OMF record header. */
56#pragma pack(1)
57typedef struct omf_rec_hdr
58{
59 byte type;
60 word len;
61} omf_rec_hdr;
62#pragma pack()
63
64/* Whether or not linker tracing is enabled. */
65static int opt_t;
66
67/* Whether or not to include .dll in the shared library searching. */
68static int opt_dll_search;
69
70/* The output file name, specified by the -o option. */
71static const char *output_fname = NULL;
72
73/* The map file name (output), set by the -Zmap option. */
74static const char *map_fname = NULL;
75static int map_flag = FALSE;
76
77/* The sym file output flag, set by the -Zsym option. */
78static int sym_flag = FALSE;
79
80/* The module definition file name (input), set if a file matching
81 *.def is given on the command line. */
82static const char *def_fname = NULL;
83
84/* The binary resource file name (input), set if a file matching *.res
85 is given on the command line. */
86static const char *res_fname = NULL;
87
88/* Base address of the excecutable file, specified by the -T
89 option. */
90static const char *base = NULL;
91
92/* List of directories searched for libraries. Each -L option adds a
93 directory to this list. add_libdirs is used to add another entry
94 at the end of the list. */
95static name_list *libdirs = NULL;
96static name_list **add_libdirs = &libdirs;
97
98/* List of object files. Each file given on the command line which
99 does not match *.def, *.lib and *.res is added to this list.
100 add_obj_fnames is used to add another entry at the end of the
101 list. */
102static name_list *obj_fnames = NULL;
103static name_list **add_obj_fnames = &obj_fnames;
104
105/* List of library files. Each file matching *.lib given on the
106 command line is added to this list. The -l option also adds an
107 entry to this list. add_lib_fnames is used to add another entry at
108 the end of the list.
109 The flags member indicates library search method. If set search for
110 static lib, if clear search for shared lib before search for static lib. */
111static name_list *lib_fnames = NULL;
112static name_list **add_lib_fnames = &lib_fnames;
113
114/* List of linker options. Linker options can be specified with the
115 -O option. add_options is used to add another entry at the end of
116 the list. */
117static name_list *options = NULL;
118static name_list **add_options = &options;
119
120/* The command line passed to the linker. */
121static char command_line[260];
122
123/* The current length of the command line. */
124static int line_len;
125
126/* Non-zero if arguments go into the response file instead of
127 command_line. */
128static int response_flag;
129
130/* The name of the response file. */
131static char response_fname[L_tmpnam] = "";
132
133/* The response file. */
134static FILE *response_file = NULL;
135
136/* Force the use of a response file from the next put_arg(). */
137static int force_response_file = FALSE;
138
139/* Weak alias object file. */
140static char weakobj_fname[_MAX_PATH + 1];
141
142/* Weak definition file (modified def_fname). */
143static char weakdef_fname[_MAX_PATH + 1];
144
145/* list of converted libraries and objects which must be removed upon exit. */
146static name_list *conv_list = NULL;
147
148/* Non-zero if debugging information is to be omitted. Set by the -s
149 and -S options. */
150static int strip_symbols = FALSE;
151
152/* Non-zero if emxomfld should create an .exe file and touch the
153 output file. Set by the -Zexe option. */
154static int exe_flag = FALSE;
155
156/* Non-zero when creating a dynamic link library. Set by the -Zdll
157 option. */
158static int dll_flag = FALSE;
159
160/* The stack size, specified by the -Zstack option, in Kbyte. If the
161 -Zstack option is not used, this variable defaults to 1024 to match
162 the defaults of emxbind. */
163static long stack_size = 1024;
164/* Indicates that we've seen -Zstack. */
165static int stack_size_flag = 0;
166
167/* The name of the linker to use. By default, ilink is used. This
168 can be overridden with the EMXOMFLD_LINKER environment variable. */
169static const char *linker_name = "wlink.exe";
170
171/* The type of linker to use. By default we assume it's VAC365 or later
172 version of ilink. This can be overridden with the EMXOMFLD_TYPE env.
173 var. using any of the values WLINK, VAC365, VAC308 and LINK386. */
174static const char *linker_type = "WLINK";
175
176/* The name of the resource compiler to use. By default, rc is used.
177 This can be overridden with the EMXOMFLD_RC environment variable. */
178static const char *rc_name = "rc.exe";
179
180/* The type of resource compiler to use. By default we assume it's
181 IBM resource compiler. This can be overridden with the EMXOMFLD_RC_TYPE
182 env. var. using any of the values RC, WRC. */
183static const char *rc_type = "RC";
184
185/* Non-zero if emxomfld should automatically convert a.out objects and
186 archives to the OMF equivalents during linking. */
187static int autoconvert_flag = 1;
188
189
190/* Prototypes. */
191
192static void usage (void) NORETURN2;
193extern void *xmalloc (size_t n);
194extern void *xrealloc (void *ptr, size_t n);
195extern char *xstrdup (const char *s);
196static void add_name_list (name_list ***add, const char *src, unsigned flags);
197static void conv_path (char *name);
198static void put_arg (const char *src, int path, int quotable);
199static void put_args (const name_list *list, int paths);
200static void make_env (void);
201static void cleanup (void);
202static void arg_init (int rsp);
203static void arg_end (void);
204int main (int argc, char *argv[]);
205
206/* To avoid including os2.h... */
207#ifndef _System
208#define _System
209#endif
210extern int _System DosCopy (char *, char *, int);
211
212/* Allocate N bytes of memory. Quit on failure. This function is
213 used like malloc(), but we don't have to check the return value. */
214
215void *xmalloc (size_t n)
216{
217 void *p;
218
219 p = malloc (n);
220 if (p == NULL && n)
221 {
222 fprintf (stderr, "emxomfld: out of memory\n");
223 exit (2);
224 }
225 return p;
226}
227
228
229/* Change the allocation of PTR to N bytes. Quit on failure. This
230 function is used like realloc(), but we don't have to check the
231 return value. */
232
233void *xrealloc (void *ptr, size_t n)
234{
235 void *p;
236
237 p = realloc (ptr, n);
238 if (p == NULL && n)
239 {
240 fprintf (stderr, "emxomfld: out of memory\n");
241 exit (2);
242 }
243 return p;
244}
245
246
247
248/* Create a duplicate of the string S on the heap. Quit on failure.
249 This function is used like strdup(), but we don't have to check the
250 return value. */
251
252char *xstrdup (const char *s)
253{
254 char *p;
255 int cch = strlen (s) + 1;
256
257 p = xmalloc (cch);
258 memcpy (p, s, cch);
259 return p;
260}
261
262
263/* Add the name SRC to a list. ADD is a pointer to the pointer of the
264 end of the list. We duplicate the string before adding it to the
265 list. */
266
267static void add_name_list (name_list ***add, const char *src, unsigned flags)
268{
269 name_list *node;
270
271 node = xmalloc (sizeof (name_list));
272 node->next = NULL;
273 node->name = xstrdup (src);
274 node->flags = flags;
275 *(*add) = node;
276 (*add) = &node->next;
277}
278
279/* Opens a response file. */
280
281static void open_response_file(void)
282{
283 int fd;
284
285 if (response_file)
286 return;
287
288 /* Complain if we are not allowed to use a response
289 file. */
290
291 if (!response_flag)
292 {
293 fprintf (stderr, "emxomfld: command line too long\n");
294 exit (2);
295 }
296
297 /* Choose a unique file name and create the response
298 file. */
299
300 strcpy (response_fname, "ldXXXXXX");
301 fd = mkstemp (response_fname);
302 if (fd < 0)
303 {
304 perror ("emxomfld");
305 exit (2);
306 }
307 close(fd);
308 response_file = fopen (response_fname, "wt");
309 if (response_file == NULL)
310 {
311 perror ("emxomfld");
312 exit (2);
313 }
314
315 /* Add the name of the response file to the command
316 line. */
317
318 command_line[line_len++] = ' ';
319 command_line[line_len++] = '@';
320 strcpy (command_line+line_len, response_fname);
321 if (!stricmp (linker_type, "WLINK"))
322 strcat (command_line, ".");
323
324 if (force_response_file)
325 force_response_file = FALSE;
326}
327
328/* Replace forward slashes `/' in NAME with backslashes `\'. The linkers
329 requires backslashes in path names. */
330
331static void conv_path (char *name)
332{
333 char *p;
334
335 for (p = name; *p != 0; ++p)
336 if (*p == '/')
337 *p = '\\';
338}
339
340
341/* Add the argument SRC to the command line or to the response file.
342 If PATH is non-zero, SRC is a path name and slashes are to be
343 replaced by backslashes. If the command line gets too long, a
344 response file is created.
345 If quotable is non-zero SRC will be quoted. This is required for
346 supporting files names which includes '+' and spaces. */
347
348static void put_arg (const char *src, int path, int quotable)
349{
350 int len, max_len;
351 char *tmp;
352
353 if (src != NULL)
354 {
355
356 /* Instead of a comma, we write a newline to the response
357 file. */
358
359 if (response_file != NULL && strcmp (src, ",") == 0)
360 {
361 fputc ('\n', response_file);
362 line_len = 0;
363 return;
364 }
365
366 /* Make a local copy of SRC to be able to modify it. Then,
367 translate forward slashes to backslashes if PATH is
368 non-zero. */
369
370 len = strlen (src);
371 tmp = alloca (len + (quotable ? 3 : 1));
372 if (path)
373 {
374 /* needs quoting? */
375 if (quotable)
376 {
377 *tmp = '"';
378 strcpy (tmp+1, src);
379 tmp[++len] = '"';
380 tmp[++len] = '\0';
381 }
382 else
383 strcpy (tmp, src);
384 conv_path (tmp);
385 }
386 else
387 strcpy (tmp, src);
388
389
390 /* Check if we've reached the maximum line length. If the
391 maximum command line length is exceeded, create a response
392 file and write the remaining arguments to that file instead
393 of putting them on the command line. */
394
395 max_len = (response_file == NULL ? 110 : 52);
396 if ( line_len + len + 1 > max_len
397 || (force_response_file && !response_file))
398 {
399
400 /* If SRC is a single comma or a single semicolon, copy it
401 to the output, ignoring the maximum line length. This is
402 to meet the IBM/M$ linker command syntax. The maximum line
403 length allows for enough commas and semicolons added this
404 way. */
405
406 if ((*tmp == ',' || *tmp == ';') && tmp[1] == 0)
407 {
408 if (response_file == NULL)
409 {
410 command_line[line_len+0] = *tmp;
411 command_line[line_len+1] = 0;
412 }
413 else
414 fputc (*tmp, response_file);
415 ++line_len;
416 return;
417 }
418
419 /* If a response file has not yet been opened, open it. */
420
421 if (response_file == NULL)
422 open_response_file();
423 else if (line_len != 0)
424 {
425
426 /* Start a new line in the response file. */
427
428 fputs (" +\n", response_file);
429 }
430 line_len = 0;
431 }
432
433 /* Separate command line arguments by spaces (unless the
434 argument to be added starts with a delimiter. */
435
436 if (line_len != 0 && *src != ',' && *src != ';')
437 {
438 if (response_file == NULL)
439 command_line[line_len++] = ' ';
440 else
441 fputc (' ', response_file);
442 }
443
444 /* Finally write the argument to the command line or to the
445 response file and adjust the current line length. */
446
447 if (response_file == NULL)
448 strcpy (command_line + line_len, tmp);
449 else
450 fputs (tmp, response_file);
451 line_len += len;
452 }
453}
454
455
456/* Put a list of arguments onto the command line or into the response
457 file. If PATHS is non-zero, the arguments are path names and
458 slashes are to be replaced by backslashes. */
459
460static void put_args (const name_list *list, int paths)
461{
462 while (list != NULL)
463 {
464 put_arg (list->name, paths, paths);
465 list = list->next;
466 }
467}
468
469
470/* Build the environment for the IBM/M$ Linkers: define the LIB
471 environment variable. */
472
473static void make_env (void)
474{
475 static char tmp[4096];
476 char *p;
477 int len;
478 const name_list *list;
479
480 /* Create a string for putenv(). */
481
482 strcpy (tmp, "LIB=");
483 len = strlen (tmp);
484
485 /* Add the library directories to LIB, using `;' as separator. */
486
487 for (list = libdirs; list != NULL; list = list->next)
488 {
489 if (list != libdirs && tmp[len-1] != ';')
490 tmp[len++] = ';';
491 strcpy (tmp+len, list->name);
492 conv_path (tmp+len);
493 len += strlen (list->name);
494 }
495
496 /* Append to the end the previous definition of LIB. */
497
498 p = getenv ("LIB");
499 if (p != NULL)
500 {
501 if (tmp[len-1] != ';')
502 tmp[len++] = ';';
503 strcpy (tmp+len, p);
504 }
505
506
507 /* Put the new value of LIB into the environment. */
508
509 putenv (tmp);
510
511 if (opt_t)
512 fprintf(stderr, "*** %s\n", tmp);
513}
514
515/**
516 * Reports archive parsing error.
517 * @returns 0.
518 * @param pszError The parsing error.
519 */
520static int bad_arch(const char *pszError)
521{
522 fprintf(stderr, "emxomfld: failed parsing archive: %s\n", pszError);
523 return 0;
524}
525
526/**
527 * Validates a numeric ar_hdr field.
528 *
529 * These are supposed to be padded with spaces, however, emximp seems to be
530 * using null terminators as well (ar_mode for instance).
531 *
532 * @returns 1 if valid, 0 if invalid.
533 * @param pachField The field.
534 * @param cchField The field length.
535 * @param uBase 10 for decimal, 8 for octal.
536 * @param pszName The field name.
537 */
538static int is_arch_num_field_valid(char const *pachField, size_t cchField, unsigned uBase, const char *pszName)
539{
540 while (cchField > 0)
541 {
542 unsigned ch = *pachField;
543 if (ch - '0' >= uBase)
544 {
545 if (ch == ' ' || !ch)
546 break;
547 return bad_arch(pszName);
548 }
549 cchField--;
550 pachField++;
551 }
552
553 while (cchField > 0)
554 {
555 char ch = *pachField;
556 if (ch != ' ' && ch)
557 return bad_arch(pszName);
558 cchField--;
559 pachField++;
560 }
561
562 return 1;
563}
564
565/**
566 * Checks the name field to see if there is a BSD style variable sized name
567 * field following the header.
568
569 * @returns 0 if none, length if something.
570 * @param pArHdr The archive header.
571 */
572static unsigned arch_hdr_get_ext_name_len(struct ar_hdr *pArHdr)
573{
574 unsigned cchExtName = 0;
575 if (!memcmp(&pArHdr->ar_name[0], AR_EFMT1, sizeof(AR_EFMT1) - 1))
576 {
577 int cch = sizeof(pArHdr->ar_name) - sizeof(AR_EFMT1) - 1;
578 const char *pch = &pArHdr->ar_name[sizeof(AR_EFMT1) - 1];
579 while (cch-- > 0)
580 {
581 unsigned uDig = (unsigned char)*pch++ - '0';
582 if (uDig > 10)
583 break;
584 cchExtName *= 10;
585 cchExtName += uDig;
586 }
587 }
588 return cchExtName;
589}
590
591/**
592 * Converts the size field of the header into something we can use.
593 * @returns ar_size as off_t.
594 * @param pArHdr The archive header.
595 */
596static off_t arch_hdr_get_size(struct ar_hdr *pArHdr)
597{
598 off_t cb = 0;
599 int cch = sizeof(pArHdr->ar_size);
600 const char *pch = &pArHdr->ar_size[0];
601 while (cch-- > 0)
602 {
603 unsigned uDig = (unsigned char)*pch++ - '0';
604 if (uDig > 10)
605 break;
606 cb *= 10;
607 cb += uDig;
608 }
609 return cb;
610}
611
612/**
613 * Matches @a pszName with the name in the archive header.
614 *
615 * @returns 1 if matches, 0 if not.
616 * @param pArHdr The archive header.
617 * @param pszName The name to match it with.
618 */
619static int arch_hdr_match_name(struct ar_hdr *pArHdr, const char *pszName)
620{
621 size_t cch = sizeof(pArHdr->ar_name);
622 const char *pch = &pArHdr->ar_name[0];
623 while (cch > 0)
624 {
625 if (*pszName != *pch)
626 {
627 if (*pszName)
628 return 0;
629 break;
630 }
631 cch--;
632 pszName++;
633 pch++;
634 }
635
636 while (cch-- > 0)
637 {
638 char ch = *pch++;
639 if (ch != ' ' && ch)
640 return 0;
641 }
642
643 return 1;
644}
645
646/**
647 * Checks if the stream @a pFile is an archive only containing ELF and OMF
648 * files.
649 *
650 * @returns 1 if so, 0 if not.
651 * @param pFile The file stream to check. The caller rewinds the stream.
652 */
653static int check_arch_library_with_omf_and_or_elf(FILE *pFile)
654{
655 union
656 {
657 char achMagic[SARMAG];
658 struct ar_hdr ArHdr;
659 Elf32_Ehdr Elfhdr;
660 omf_rec_hdr OmfHdr;
661 /*struct exec AoutHdr;*/
662 } uBuf;
663 off_t offArchive;
664
665 /*
666 * Read+reverify the magic.
667 */
668 if (fread(&uBuf.achMagic[0], SARMAG, 1, pFile) != 1)
669 return 0;
670 if (memcmp(&uBuf.achMagic[0], ARMAG, SARMAG) != 0)
671 return 0;
672
673 /*
674 * Process the archive, file by file.
675 */
676 offArchive = SARMAG;
677 while (!feof(pFile))
678 {
679 off_t cbFile;
680 off_t offNext;
681 size_t cbRead;
682 int cchExtraName;
683
684 /* read + verify the archive header */
685 cbRead = fread(&uBuf.ArHdr, 1, sizeof(uBuf.ArHdr), pFile);
686 if (cbRead != sizeof(uBuf.ArHdr))
687 return cbRead == 0 && feof(pFile) ? 1 : bad_arch("fread");
688 offArchive += sizeof(uBuf.ArHdr);
689
690 if (memcmp(uBuf.ArHdr.ar_fmag, ARFMAG, sizeof(uBuf.ArHdr.ar_fmag)))
691 return bad_arch("ar_fmag");
692 if ( !is_arch_num_field_valid(uBuf.ArHdr.ar_date, sizeof(uBuf.ArHdr.ar_date), 10, "ar_date")
693 || !is_arch_num_field_valid(uBuf.ArHdr.ar_uid, sizeof(uBuf.ArHdr.ar_uid), 10, "ar_uid")
694 || !is_arch_num_field_valid(uBuf.ArHdr.ar_gid, sizeof(uBuf.ArHdr.ar_gid), 10, "ar_gid")
695 || !is_arch_num_field_valid(uBuf.ArHdr.ar_mode, sizeof(uBuf.ArHdr.ar_mode), 8, "ar_mode")
696 || !is_arch_num_field_valid(uBuf.ArHdr.ar_size, sizeof(uBuf.ArHdr.ar_size), 10, "ar_size") )
697 return 0; /* bitched already */
698
699 cbFile = arch_hdr_get_size(&uBuf.ArHdr);
700 offNext = offArchive + cbFile;
701 offNext += offNext & 1; /* make even */
702
703 /* skip the extended name field if present (BSD). */
704 cchExtraName = arch_hdr_get_ext_name_len(&uBuf.ArHdr);
705 /*fprintf(stderr, "%#06x '%.16s' offNext=%#x cb=%#x ext=%d\n", (unsigned)offArchive, &uBuf.ArHdr.ar_name[0], (unsigned)offNext, (unsigned)cbFile, cchExtraName);*/
706 if (cchExtraName)
707 {
708 cbFile -= cchExtraName;
709 offArchive += cchExtraName;
710 if (fseek(pFile, offArchive, SEEK_SET))
711 return bad_arch("fseek-ext-name");
712 }
713
714 /* ignore the archive symbol table. */
715 if ( !arch_hdr_match_name(&uBuf.ArHdr, "__.SYMDEF")
716 && !arch_hdr_match_name(&uBuf.ArHdr, "/")
717 && !arch_hdr_match_name(&uBuf.ArHdr, "ARFILENAMES/")
718 && !arch_hdr_match_name(&uBuf.ArHdr, "//"))
719 {
720 cbRead = sizeof(uBuf);
721 if (cbRead > cbFile)
722 {
723 cbRead = cbFile;
724 memset(&uBuf, 0, sizeof(uBuf));
725 }
726 if (fread(&uBuf, 1, cbRead, pFile) != cbRead)
727 return bad_arch("fread-member-hdr");
728
729 if ( ( uBuf.OmfHdr.len >= sizeof(uBuf.OmfHdr)
730 && cbRead > sizeof(sizeof(uBuf.OmfHdr)) )
731 && ( uBuf.OmfHdr.type == THEADR
732 /*|| uBuf.OmfHdr.type == LIBADR - doubt wlink can handle this */)
733 || IS_ELF(uBuf.Elfhdr) )
734 {
735 /* nothing */
736 /*fprintf(stderr, IS_ELF(uBuf.Elfhdr) ? "ELF\n" : "OMF\n");*/
737 }
738 else
739 {
740 /*fprintf(stderr, "not omf or elf\n");*/
741 return 0;
742 }
743 }
744 /*else
745 fprintf(stderr, "skip archive symbol table\n");*/
746
747 /* advance to the next file */
748 if (fseek(pFile, offNext, SEEK_SET))
749 return bad_arch("fseek-next");
750 offArchive = offNext;
751 }
752
753 return 1;
754}
755
756/**
757 * Checks if the stream phFile is an OMF library.
758 *
759 * @returns 1 if OMF library.
760 * @returns 0 if not OMF library.
761 * @param phFile Filestream to check.
762 */
763static int check_omf_library(FILE *phFile)
764{
765#pragma pack(1)
766 struct
767 {
768 byte rec_type;
769 word rec_len;
770 dword dict_offset;
771 word dict_blocks;
772 byte flags;
773 } libhdr;
774#pragma pack()
775
776 if ( fread(&libhdr, 1, sizeof(libhdr), phFile) == sizeof (libhdr)
777 && !fseek(phFile, 0, SEEK_SET)
778 && libhdr.rec_type == LIBHDR
779 && libhdr.flags <= 1 /* ASSUME only first bit is used... */
780 )
781 {
782 int page_size = libhdr.rec_len + 3;
783 if (page_size >= 16
784 && page_size <= 32768
785 && !(page_size & (page_size - 1)) != 0)
786 return 1;
787 }
788 return 0;
789}
790
791
792/**
793 * Checks if the stream phFile is an OMF object or library.
794 *
795 * @returns 1 if OMF.
796 * @returns 0 if not OMF.
797 * @param phFile Filestream to check.
798 */
799static int check_omf_or_elf(FILE *phFile)
800{
801#pragma pack(1)
802 union
803 {
804 struct
805 {
806 byte rec_type;
807 word rec_len;
808 } omfhdr;
809 byte elfmagic[4];
810 char arch[7];
811 } u;
812#pragma pack()
813 size_t cbRead = fread(&u.omfhdr, 1, sizeof(u), phFile);
814 if (fseek(phFile, 0, SEEK_SET))
815 return 0;
816
817 /* OMF object or library? */
818 if ( cbRead >= sizeof(u.omfhdr)
819 && u.omfhdr.rec_type == THEADR
820 && u.omfhdr.rec_len >= sizeof(u.omfhdr) )
821 return 1;
822 if ( cbRead >= sizeof(u.omfhdr)
823 && u.omfhdr.rec_type == LIBHDR)
824 return check_omf_library(phFile);
825
826 /* ELF object? */
827 if ( u.elfmagic[0] == ELFMAG0
828 && u.elfmagic[1] == ELFMAG1
829 && u.elfmagic[2] == ELFMAG2
830 && u.elfmagic[3] == ELFMAG3)
831 return 1;
832
833 /* AR archive with OMF and/or ELF content? */
834 if ( cbRead >= sizeof("!<arch>") - 1
835 && !memcmp(u.arch, "!<arch>", sizeof(u.arch)))
836 {
837 int rc = check_arch_library_with_omf_and_or_elf(phFile);
838 if (fseek(phFile, 0, SEEK_SET))
839 rc = 0;
840 return rc;
841 }
842
843 /* Not anything we know */
844 return 0;
845}
846
847
848/**
849 * Checks if the stream phFile is an LX DLL.
850 *
851 * @returns 1 if LX DLL.
852 * @returns 0 if not LX DLL.
853 * @param phFile File stream to check.
854 */
855static int check_lx_dll(FILE *phFile)
856{
857 unsigned long ul;
858 char achMagic[2];
859
860 if ( fseek(phFile, 0, SEEK_SET)
861 || fread(&achMagic, 1, 2, phFile) != 2)
862 goto thats_not_it;
863
864 if (!memcmp(achMagic, "MZ", 2))
865 {
866 if ( fseek(phFile, 0x3c, SEEK_SET)
867 || fread(&ul, 1, 4, phFile) != 4 /* offset of the 'new' header */
868 || ul < 0x40
869 || ul >= 0x10000000 /* 512MB stubs sure */
870 || fseek(phFile, ul, SEEK_SET)
871 || fread(&achMagic, 1, 2, phFile) != 2)
872 goto thats_not_it;
873 }
874
875 if ( memcmp(achMagic, "LX", 2)
876 || fseek(phFile, 14, SEEK_CUR)
877 || fread(&ul, 1, 4, phFile) != 4) /*e32_mflags*/
878 goto thats_not_it;
879
880#define E32MODDLL 0x08000L
881#define E32MODPROTDLL 0x18000L
882#define E32MODMASK 0x38000L
883 if ( (ul & E32MODMASK) != E32MODDLL
884 && (ul & E32MODMASK) != E32MODPROTDLL)
885 goto thats_not_it;
886
887 /* it's a LX DLL! */
888 fseek(phFile, 0, SEEK_SET);
889 return 1;
890
891
892thats_not_it:
893 fseek(phFile, 0, SEEK_SET);
894 return 0;
895}
896
897
898/**
899 * Generates an unique temporary file.
900 *
901 * @returns 0 on success.
902 * @returns -1 on failure.
903 * @param pszFile Where to put the filename.
904 * @param pszPrefix Prefix.
905 * @param pszSuffix Suffix.
906 * @param pszLooklike Filename which name is to be incorporated into the temp filename.
907 * @remark The code is nicked from the weak linker.
908 */
909static int make_tempfile(char *pszFile, const char *pszPrefix, const char *pszSuffix, const char *pszLooklike)
910{
911 struct stat s;
912 unsigned c = 0;
913 char szLooklike[32];
914 pid_t pid = getpid();
915 static char s_szTmp[_MAX_PATH + 1];
916
917 /* We need to apply _realrealpath to the tmpdir, so resolve that once and for all. */
918 if (!s_szTmp[0])
919 {
920 const char * pszTmp = getenv("TMP");
921 if (!pszTmp) pszTmp = getenv("TMPDIR");
922 if (!pszTmp) pszTmp = getenv("TEMP");
923 if (!pszTmp) pszTmp = ".";
924 if (!_realrealpath(pszTmp, s_szTmp, sizeof(s_szTmp)))
925 {
926 printf("emxomfld: _realrealpath failed on '%s'!!!\n", pszTmp);
927 exit(1);
928 }
929 }
930
931 if (pszLooklike)
932 {
933 int cch;
934 char *psz = (char*)pszLooklike; /* we're nice fellows. */
935 while ((psz = strpbrk(psz, ":/\\")) != NULL)
936 pszLooklike = ++psz;
937 cch = strlen(pszLooklike);
938 if (cch + 3 > sizeof(szLooklike))
939 cch = sizeof(szLooklike) - 3;
940 szLooklike[0] = '_';
941 memcpy(&szLooklike[1], pszLooklike, cch);
942 szLooklike[cch + 1] = '_';
943 szLooklike[cch + 2] = '\0';
944 pszLooklike = psz = &szLooklike[0];
945 while ((psz = strpbrk(psz, ".@%^&#()")) != NULL)
946 *psz++ = '_';
947 }
948 else
949 pszLooklike = "";
950
951 do
952 {
953 struct timeval tv = {0,0};
954 if (c++ >= 200)
955 return -1;
956 gettimeofday(&tv, NULL);
957 sprintf(pszFile, "%s\\%s%s%x%lx%d%lx%s", s_szTmp, pszPrefix, pszLooklike, pid, tv.tv_sec, c, tv.tv_usec, pszSuffix);
958 } while (!stat(pszFile, &s));
959
960 return 0;
961}
962
963
964/**
965 * Converts the file indicated by phFile & pszFilename to omf closing
966 * phFile and updating pszFilename with the new (temporary filename).
967 *
968 * @returns Pointer to an filestream for the converted file and pszFilename
969 * containing the name of the converted file.
970 * @returns exit the program
971 * @param phFile Filestream of the file to convert. (close this)
972 * @param pszFilename Name of the file to convert on entry.
973 * Name of the converted file on return.
974 */
975static FILE *aout_to_omf(FILE *pf, char *pszFilename, int fLibrary)
976{
977 int rc;
978 char * pszNewFile;
979 name_list *pName;
980
981 fclose(pf); /* don't need this! */
982
983 if (opt_t)
984 fprintf(stderr, "emxomfld: info: converting %s %s to OMF.\n",
985 fLibrary ? "lib" : "obj", pszFilename);
986
987 /*
988 * Make temporary file.
989 */
990 pName = xmalloc(sizeof(name_list));
991 pName->name = pszNewFile = xmalloc(_MAX_PATH);
992 if (make_tempfile(pszNewFile, "ldconv", fLibrary ? ".lib" : ".obj", pszFilename))
993 {
994 free(pszNewFile);
995 return NULL;
996 }
997
998 /*
999 * Do the conversion.
1000 */
1001 rc = spawnlp(P_WAIT, "emxomf.exe", "emxomf.exe", "-o", pszNewFile, pszFilename, NULL);
1002 if (!rc)
1003 {
1004 /* open the file */
1005 pf = fopen(pszNewFile, "rb");
1006 if (pf)
1007 {
1008 /* add to auto delete list for removal on exit(). */
1009 pName->next = conv_list;
1010 conv_list = pName;
1011
1012 strcpy(pszFilename, pszNewFile);
1013
1014 if (opt_t)
1015 fprintf(stderr, "emxomfld: info: convert result '%s'.\n",
1016 pszFilename);
1017 return pf;
1018 }
1019 remove(pszNewFile);
1020 }
1021 free(pszNewFile);
1022 free(pName);
1023
1024 fprintf(stderr, "emxomfld: a.out to omf conversion failed for '%s'.\n",
1025 pszFilename);
1026 exit(1);
1027 return NULL;
1028}
1029
1030
1031/**
1032 * Converts the file indicated by phFile & pszFilename to omf closing
1033 * phFile and updating pszFilename with the new (temporary filename).
1034 *
1035 * @returns Pointer to an filestream for the converted file and pszFilename
1036 * containing the name of the converted file.
1037 * @returns exit the program
1038 * @param phFile Filestream of the file to convert. (close this)
1039 * @param pszFilename Name of the file to convert on entry.
1040 * Name of the converted file on return.
1041 */
1042static FILE *lx_to_omf(FILE *pf, char *pszFilename)
1043{
1044 int rc;
1045 char * pszNewFile;
1046 name_list *pName;
1047
1048 fclose(pf); /* don't need this! */
1049
1050 if (opt_t)
1051 fprintf(stderr, "emxomfld: info: converting %s %s to an OMF import lib.\n",
1052 "lib", pszFilename);
1053
1054 /*
1055 * Make temporary file.
1056 */
1057 pName = xmalloc(sizeof(name_list));
1058 pName->name = pszNewFile = xmalloc(_MAX_PATH);
1059 if (make_tempfile(pszNewFile, "ldconv", ".lib", pszFilename))
1060 {
1061 free(pszNewFile);
1062 return NULL;
1063 }
1064
1065 /*
1066 * Do the conversion.
1067 */
1068 rc = spawnlp(P_WAIT, "emximp.exe", "emximp.exe", "-o", pszNewFile, pszFilename, NULL);
1069 if (!rc)
1070 {
1071 /* open the file */
1072 pf = fopen(pszNewFile, "rb");
1073 if (pf)
1074 {
1075 /* add to auto delete list for removal on exit(). */
1076 pName->next = conv_list;
1077 conv_list = pName;
1078
1079 strcpy(pszFilename, pszNewFile);
1080
1081 if (opt_t)
1082 fprintf(stderr, "emxomfld: info: convert result '%s'.\n",
1083 pszFilename);
1084 return pf;
1085 }
1086 remove(pszNewFile);
1087 }
1088 free(pszNewFile);
1089 free(pName);
1090
1091 fprintf(stderr, "emxomfld: lx dll to omf conversion failed for '%s'.\n",
1092 pszFilename);
1093 exit(2);
1094 return NULL;
1095}
1096
1097
1098/**
1099 * Finds the full path of a OMF object file and opens the file.
1100 *
1101 * This function may perform conversion from a.out to omf if that feature
1102 * is enabled.
1103 *
1104 * We choose to be UNIX compatible her, and not search the LIB env.var.
1105 * for unqualified objects. Nor will we add any suffixes to the name
1106 * if it's witout any extension.
1107 *
1108 * @returns Pointer to a file stream for the object file to use in the link.
1109 * @returns NULL on failure with pszFullname containing a copy of
1110 * pszName (or something like that).
1111 * @param pszFullname Where to store the name of the file to be used
1112 * in the linking (and which stream is returned).
1113 * @param pszName Object name given to on the linker commandline.
1114 */
1115static FILE *find_obj(char *pszFullname, const char *pszName)
1116{
1117 FILE *phFile;
1118 char *psz;
1119
1120 /*
1121 * Make abspath with slashes the desired way and such.
1122 */
1123 if (!_realrealpath(pszName, pszFullname, _MAX_PATH + 1))
1124 {
1125 printf("emxomfld: _abspath failed on '%s'!!!\n", pszName);
1126 exit(1);
1127 }
1128
1129 psz = pszFullname;
1130 while ((psz = strchr(psz, '/')) != NULL)
1131 *psz++ = '\\';
1132
1133 /*
1134 * Try open the file.
1135 */
1136 phFile = fopen(pszFullname, "rb");
1137 if (!phFile)
1138 return NULL;
1139
1140 /*
1141 * If autoconversion check if such is needed.
1142 */
1143 if ( autoconvert_flag
1144 && !check_omf_or_elf(phFile))
1145 phFile = aout_to_omf(phFile, pszFullname, FALSE);
1146
1147 return phFile;
1148}
1149
1150
1151
1152/* Finds the full path of a library file and opens the file.
1153 *
1154 * This function may perform conversion from a.out to omf if that feature
1155 * is enabled.
1156 *
1157 * The function assumes that LIB has been updated with all the search paths
1158 * specified on the commandline.
1159 *
1160 * Library names with no extension are given extensions after the rules
1161 * indicated by the IS_SHARED parameter. If IS_SHARED is set then libraries
1162 * with suffixes indicating shared libraries will be looked for before
1163 * libraries with suffixes indicated static libraries. The list is as
1164 * follows for set IS_SHARED:
1165 * 1. _dll.lib
1166 * 2. .lib
1167 * 3. .dll (optional)
1168 * 4. _s.lib
1169 *
1170 * If IS_SHARED is clear:
1171 * 1. _s.lib
1172 * 2. .lib
1173 *
1174 * Library names with no path is searched for in the semicolon separated list
1175 * of paths the env.var. LIB contains. For each directory in LIB we'll start
1176 * by see if it contains a 'lib' prefixed file, if not found we'll check for
1177 * the unprefixed filename. If we're appending suffixes too, we'll loop thru
1178 * all the possible suffixes for each directory before advancing to the next,
1179 * having the prefixing as the inner most loop.
1180 *
1181 * @returns Pointer to a file stream for the library file to use in the link.
1182 * @returns NULL on failure with pszFullname containing a copy of
1183 * pszName (or something like that).
1184 * @param pszFullname Where to store the name of the file to be used
1185 * in the linking (and which stream is returned).
1186 * @param pszName Library name given to on the linker commandline.
1187 */
1188static FILE *find_lib(char *pszFullname, const char *pszName, int fShared)
1189{
1190 /* Suffix list for shared linking. */
1191 static const char *apszSharedSuff[] = { "_dll.lib", "_dll.a", ".lib", ".a", "_s.lib", "_s.a", NULL };
1192 /* Suffix list for shared linking with .dll. */
1193 static const char *apszSharedDllSuff[] = { "_dll.lib", "_dll.a", ".lib", ".a", ".dll", "_s.lib", "_s.a", NULL };
1194 /* Suffix list for static linking. */
1195 static const char *apszStaticSuff[] = { "_s.lib", "_s.a", ".lib", ".a", NULL };
1196 /* Suffix list for names with extension. */
1197 static const char *apszExtensionSuff[] = { "", NULL };
1198 /* Prefix list for names with path. */
1199 static const char *apszWithPathPref[] = { "", NULL };
1200 /* Prefix list for names with no path. */
1201 static const char *apszWithoutPathPref[]= { "lib", "", NULL };
1202 int fPath; /* set if the library name have a path. */
1203 int fExt; /* set if the library name have an extension. */
1204 const char **papszSuffs; /* Pointer to the suffix list. */
1205 const char **papszPrefs; /* Pointer to the prefix list. */
1206 const char *pszLibPath; /* The path we're searching. */
1207 size_t cchCurPath; /* Size of the current path. */
1208 size_t cchName = strlen(pszName);
1209 const char *psz;
1210
1211 /*
1212 * Check if the file name has a path.
1213 * (If it has, we won't check the LIB directories.)
1214 * Choose the prefix list accordingly.
1215 */
1216 fPath = (strpbrk(pszName, ":/\\") != NULL);
1217 papszPrefs = fPath ? apszWithPathPref : apszWithoutPathPref;
1218
1219 /*
1220 * Check if the file has a real extension.
1221 * Real extension means, .lib, .dll or .a. It also implies something
1222 * before the dot.
1223 * Choose the suffix list accordingly.
1224 */
1225 fExt = ( (cchName > 4 && !stricmp(pszName + cchName - 4, ".lib"))
1226 || (cchName > 4 && !stricmp(pszName + cchName - 4, ".dll"))
1227 || (cchName > 2 && !stricmp(pszName + cchName - 2, ".a")) );
1228
1229 if (!fExt)
1230 {
1231 if (fShared)
1232 papszSuffs = opt_dll_search ? &apszSharedDllSuff[0] : &apszSharedSuff[0];
1233 else
1234 papszSuffs = &apszStaticSuff[0];
1235 }
1236 else
1237 papszSuffs = apszExtensionSuff;
1238
1239 /*
1240 * Loop 1: LIB (with a fake .\ as the first iteration)
1241 * (Looping on pszLibPath, with preinitiated cchCurPath & pszFullname.)
1242 */
1243 cchCurPath = 0;
1244 if (!fPath)
1245 {
1246 cchCurPath = 2;
1247 memcpy(pszFullname, ".\\", 2);
1248 }
1249 pszLibPath = getenv("LIB");
1250 do
1251 {
1252 /*
1253 * Loop2: Suffixes.
1254 */
1255 int iSuff;
1256 for (iSuff = 0; papszSuffs[iSuff]; iSuff++)
1257 {
1258 /*
1259 * Loop3: Prefixes.
1260 */
1261 int iPref;
1262 for (iPref = 0; papszPrefs[iPref]; iPref++)
1263 {
1264 FILE *phFile;
1265 int cch = strlen(papszPrefs[iPref]);
1266
1267 /*
1268 * Construct name.
1269 */
1270 memcpy(&pszFullname[cchCurPath], papszPrefs[iPref], cch);
1271 cch = cchCurPath + cch;
1272 memcpy(&pszFullname[cch], pszName, cchName);
1273 cch += cchName;
1274 strcpy(&pszFullname[cch], papszSuffs[iSuff]);
1275
1276 /*
1277 * Open and if necessary convert it.
1278 */
1279 phFile = fopen(pszFullname, "rb");
1280 if (phFile)
1281 {
1282 char *pszTmp;
1283 if (autoconvert_flag)
1284 {
1285 if (check_lx_dll(phFile))
1286 phFile = lx_to_omf(phFile, pszFullname);
1287 else if (!check_omf_or_elf(phFile))
1288 phFile = aout_to_omf(phFile, pszFullname, TRUE);
1289 }
1290
1291 /* Get the real native path. */
1292 pszTmp = _realrealpath(pszFullname, NULL, 0);
1293 if (pszTmp)
1294 {
1295 strcpy(pszFullname, pszTmp);
1296 free(pszTmp);
1297 }
1298
1299 /* Replace forward slashes with backslashes (link386). */
1300 while ((pszFullname = strchr(pszFullname, '/')) != NULL)
1301 *pszFullname++ = '\\';
1302 return phFile;
1303 }
1304 } /* next prefix */
1305 } /* next suffix */
1306
1307 /*
1308 * If a path was specified or no LIB we're done now.
1309 */
1310 if (fPath || !pszLibPath)
1311 break;
1312
1313 /*
1314 * Next LIB part.
1315 */
1316 for (;;)
1317 {
1318 psz = strchr(pszLibPath, ';');
1319 if (!psz)
1320 psz = strchr(pszLibPath, '\0');
1321 cchCurPath = psz - pszLibPath;
1322 if (cchCurPath)
1323 {
1324 memcpy(pszFullname, pszLibPath, cchCurPath);
1325 pszLibPath = psz + (*psz == ';');
1326 /* Append last slash if it is not there */
1327 if ( pszFullname[cchCurPath - 1] != '/'
1328 && pszFullname[cchCurPath - 1] != '\\')
1329 pszFullname[cchCurPath++] = '\\';
1330 break;
1331 }
1332 if (!*psz)
1333 break;
1334 pszLibPath = psz + 1;
1335 }
1336 } while (cchCurPath);
1337
1338 /* failure */
1339 return NULL;
1340}
1341
1342
1343/* Weak prelinking for Method 2 Weak support. */
1344
1345static void weak_prelink ()
1346{
1347 int rc = 0;
1348 name_list * pOpt;
1349 PWLD pwld;
1350 unsigned fFlags = 0;
1351
1352 /* look for ilinker options. */
1353 if (opt_t)
1354 fFlags |= WLDC_VERBOSE;
1355 if (!stricmp(linker_type, "LINK386"))
1356 fFlags |= WLDC_LINKER_LINK386;
1357 else if (!stricmp(linker_type, "WLINK"))
1358 fFlags |= WLDC_LINKER_WLINK;
1359
1360 for (pOpt = options; pOpt; pOpt = pOpt->next)
1361 if ( !strnicmp(pOpt->name, "/NOE", 4)
1362 || !strnicmp(pOpt->name, "-NOE", 4))
1363 fFlags |= WLDC_NO_EXTENDED_DICTIONARY_SEARCH;
1364 else
1365 if ( !strnicmp(pOpt->name, "/INC", 4)
1366 || !strnicmp(pOpt->name, "-INC", 4))
1367 fFlags = fFlags; /* Ignore for now. */
1368 else
1369 if ( !strnicmp(pOpt->name, "/IG", 3)
1370 || !strnicmp(pOpt->name, "-IG", 3))
1371 fFlags |= WLDC_CASE_INSENSITIVE;
1372 else
1373 if ( !strnicmp(pOpt->name, "/I", 2)
1374 || !strnicmp(pOpt->name, "-I", 2))
1375 fFlags = fFlags; /* Ignore - require opt_t. */
1376 else
1377 if ( !strnicmp(pOpt->name, "/NOIN", 5)
1378 || !strnicmp(pOpt->name, "-NOIN", 5))
1379 fFlags &= ~WLDC_VERBOSE;
1380 else
1381 if ( !strnicmp(pOpt->name, "/NOI", 4)
1382 || !strnicmp(pOpt->name, "/NOI", 4))
1383 fFlags &= ~WLDC_CASE_INSENSITIVE;
1384
1385 /* create the linker and to the linking. */
1386 if (opt_t)
1387 fprintf(stderr, "*** Invoking weak prelinker with flags %x.\n", fFlags);
1388 pwld = WLDCreate (fFlags);
1389 if (pwld)
1390 {
1391 name_list * pcur;
1392 FILE *phfile;
1393 char szname[_MAX_PATH + 1];
1394
1395 /* definition file if any */
1396 if (def_fname && def_fname[0])
1397 {
1398 phfile = fopen (def_fname, "r");
1399 rc = WLDAddDefFile (pwld, phfile, def_fname);
1400 }
1401
1402 /* objects */
1403 for (pcur = obj_fnames; !rc && pcur; pcur = pcur->next)
1404 {
1405 phfile = find_obj (szname, pcur->name);
1406 rc = WLDAddObject (pwld, phfile, szname);
1407 }
1408
1409 /* libraries */
1410 for (pcur = lib_fnames; !rc && pcur; pcur = pcur->next)
1411 {
1412 phfile = find_lib (szname, pcur->name, !pcur->flags);
1413 rc = WLDAddLibrary (pwld, phfile, szname);
1414 free(pcur->name);
1415 pcur->name = xstrdup(szname);
1416 }
1417
1418 /* complete pass 1 */
1419 if (!rc)
1420 {
1421 rc = WLDPass1 (pwld);
1422 /* ignore unresolved externals for now. */
1423 if (rc == 42)
1424 {
1425 rc = 0;
1426 fprintf(stderr, "Ignoring unresolved externals reported from weak prelinker.\n");
1427 }
1428 }
1429
1430 /* generate weak aliases. */
1431 if (!rc)
1432 rc = WLDGenerateWeakAliases (pwld, weakobj_fname, weakdef_fname);
1433 if (!rc && weakobj_fname[0])
1434 {
1435 char *pszTmp = _realrealpath(weakobj_fname, NULL, 0);
1436 if (pszTmp)
1437 {
1438 strcpy(weakobj_fname, pszTmp);
1439 free(pszTmp);
1440 }
1441 add_name_list (&add_obj_fnames, weakobj_fname, 0);
1442 }
1443 if (!rc && weakdef_fname[0])
1444 {
1445 char *pszTmp = _realrealpath(weakdef_fname, NULL, 0);
1446 if (pszTmp)
1447 {
1448 strcpy(weakdef_fname, pszTmp);
1449 free(pszTmp);
1450 }
1451 def_fname = weakdef_fname;
1452 }
1453
1454 /* cleanup the linker */
1455 WLDDestroy (pwld);
1456
1457 /* last words */
1458 if (rc)
1459 {
1460 fprintf (stderr, "emxomfld: weak prelinker failed. (rc=%d)\n", rc);
1461 rc = 8;
1462 }
1463 }
1464 else
1465 {
1466 fprintf (stderr, "emxomfld: failed to create weak prelinker.\n");
1467 rc = 8;
1468 }
1469
1470 /* die on error. */
1471 if (rc)
1472 exit(rc);
1473
1474 /* verbose */
1475 if (opt_t)
1476 fprintf(stderr, "*** Weak prelinker done\n");
1477}
1478
1479
1480/* Start a new set of command line arguments. If RSP is non-zero, we
1481 are allowed to use a response file. */
1482
1483static void arg_init (int rsp)
1484{
1485 if (response_fname[0] != '\0')
1486 {
1487 remove (response_fname);
1488 response_fname[0] = '\0';
1489 }
1490 command_line[0] = '\0';
1491 line_len = 0;
1492 response_flag = rsp;
1493 force_response_file = FALSE;
1494}
1495
1496
1497/* Call this after adding all the command line arguments. If a
1498 response file has been created, add a newline and close it. */
1499
1500static void arg_end (void)
1501{
1502 if (response_file != NULL)
1503 {
1504 fputc ('\n', response_file);
1505 if (fflush (response_file) != 0 || fclose (response_file) != 0)
1506 {
1507 perror ("emxomfld");
1508 exit (2);
1509 }
1510 response_file = NULL;
1511 }
1512}
1513
1514/* Generates a definition file for a dll which doesn't have one. */
1515static void gen_deffile(void)
1516{
1517 char * psz;
1518 name_list *pName;
1519
1520 /*
1521 * Make temporary file.
1522 */
1523 pName = (name_list *)xmalloc(sizeof(*pName));
1524 pName->name = psz = xmalloc(_MAX_PATH);
1525 if (!make_tempfile(psz, "lddef", ".def", NULL))
1526 {
1527 FILE *pFile = fopen(psz, "w");
1528 if (pFile)
1529 {
1530 const char *pszName = _getname(output_fname);
1531 size_t cchName = strlen(pszName);
1532 if (cchName > 4 && !stricmp(pszName + cchName - 4, ".dll"))
1533 cchName -= 4;
1534 fprintf(pFile,
1535 ";; Autogenerated by emxomfld\n"
1536 "LIBRARY %.*s INITINSTANCE TERMINSTANCE\n"
1537 "DATA MULTIPLE\n"
1538 "CODE SHARED\n"
1539 "\n",
1540 cchName, pszName);
1541 fclose(pFile);
1542 def_fname = psz;
1543 if (opt_t)
1544 fprintf(stderr,
1545 "--- Generated def-file %s:\n"
1546 ";; Autogenerated by emxomfld\n"
1547 "LIBRARY %.*s INITINSTANCE TERMINSTANCE\n"
1548 "DATA MULTIPLE NONSHARED\n"
1549 "CODE SINGLE SHARED\n"
1550 "---- End of generated def-file.\n",
1551 psz, cchName, pszName);
1552
1553 /* add to auto delete list for removal on exit(). */
1554 pName->next = conv_list;
1555 conv_list = pName;
1556 return;
1557 }
1558 }
1559 free(psz);
1560 free(pName);
1561}
1562
1563/* converts a def file statement to watcom responsfile lingo. */
1564
1565static int def_2_watcom(struct _md *md, const _md_stmt *stmt, _md_token token, void *arg)
1566{
1567 switch (token)
1568 {
1569 case _MD_BASE:
1570 fprintf (response_file, "OPTION OFFSET=%#lx\n", stmt->base.addr);
1571 break;
1572
1573 case _MD_CODE:
1574 break;
1575
1576 case _MD_DATA:
1577 break;
1578
1579 case _MD_DESCRIPTION:
1580 fprintf (response_file, "OPTION DESCRIPTION '%s'\n", stmt->descr.string);
1581 break;
1582
1583 case _MD_EXETYPE:
1584 break;
1585
1586 case _MD_EXPORTS:
1587 fprintf (response_file, "EXPORT '%s'", stmt->export.entryname);
1588 if (stmt->export.flags & _MDEP_ORDINAL)
1589 fprintf (response_file, ".%d", stmt->export.ordinal);
1590 if (stmt->export.internalname[0])
1591 fprintf (response_file, "='%s'", stmt->export.internalname);
1592 if (stmt->export.flags & _MDEP_RESIDENTNAME)
1593 fprintf (response_file, " RESIDENT");
1594 /** @todo _MDEP_NONAME */
1595 fprintf (response_file, "\n");
1596
1597 /* reference the internal name. */
1598 if (stmt->export.internalname[0])
1599 fprintf (response_file, "REFERENCE '%s'\n", stmt->export.internalname);
1600 break;
1601
1602 case _MD_HEAPSIZE:
1603 fprintf (response_file, "OPTION HEAPSIZE=%#lx\n", stmt->heapsize.size);
1604 break;
1605
1606 case _MD_IMPORTS:
1607 fprintf (response_file, "IMPORT '%s' '%s'", stmt->import.internalname,
1608 stmt->import.modulename);
1609 if (stmt->import.flags & _MDEP_ORDINAL)
1610 fprintf (response_file, ".%d", stmt->import.ordinal);
1611 else if (stmt->import.internalname[0])
1612 fprintf (response_file, ".'%s'", stmt->import.entryname);
1613 fprintf (response_file, "\n");
1614 break;
1615
1616 case _MD_LIBRARY:
1617 if (stmt->library.name[0])
1618 fprintf (response_file, "OPTION MODNAME='%s'\n", stmt->library.name);
1619 break;
1620
1621 case _MD_NAME:
1622 if (stmt->name.name[0])
1623 fprintf (response_file, "OPTION MODNAME='%s'\n", stmt->name.name);
1624 break;
1625
1626 case _MD_OLD:
1627 fprintf (response_file, "OPTION OLDLIBRARY='%s'\n", stmt->old.name);
1628 break;
1629
1630 case _MD_PROTMODE:
1631 fprintf (response_file, "OPTION PROTMODE\n");
1632 break;
1633
1634 case _MD_REALMODE:
1635 fprintf (response_file, "OPTION PROTMODE\n");
1636 break;
1637
1638 case _MD_SEGMENTS:
1639 fprintf (stderr, "emxomfld: ignoring SEGMENTS directive in .def-file\n");
1640 break;
1641
1642 case _MD_STACKSIZE:
1643 fprintf (response_file, "OPTION STACK=%#lx\n", stmt->stacksize.size);
1644 break;
1645
1646 case _MD_STUB:
1647 if (!stmt->stub.none)
1648 {
1649 fprintf (response_file, "OPTION STUB='%s'\n", stmt->stub.name);
1650 *(int*)(arg) = 0; /*need_stub*/
1651 }
1652 else
1653 fprintf (stderr, "emxomfld: warning: \"STUB NONE\" is not supported by wlink. ignoring\n");
1654 break;
1655
1656 case _MD_VIRTUAL:
1657 case _MD_PHYSICAL:
1658 break;
1659
1660 case _MD_parseerror:
1661 fprintf (stderr, "emxomfld: %s (line %ld of %s)",
1662 _md_errmsg (stmt->error.code), _md_get_linenumber (md), def_fname);
1663 exit (2);
1664 break;
1665
1666 default:
1667 abort ();
1668 }
1669 return 0;
1670}
1671
1672/* -t output. We dump the commandline and responsefile. */
1673static void show_spawn(const char *pszwhat)
1674{
1675 if (!opt_t)
1676 return;
1677 fprintf(stderr, "*** Invoking %s\n %s\n", pszwhat, command_line);
1678 if (response_fname[0])
1679 { /* display the responsfile content. */
1680 char sz[4096];
1681 FILE *phfile = fopen(response_fname, "r");
1682 fprintf(stderr, "--- Response file %s:\n", response_fname);
1683 sz[0] = '\0';
1684 while (fgets(sz, sizeof(sz), phfile))
1685 fprintf(stderr, "%s", sz);
1686 fclose(phfile);
1687 if (sz[strlen(sz) - 1] != '\n')
1688 fprintf(stderr, "\n");
1689 fprintf(stderr, "--- End of Response File\n");
1690 }
1691}
1692
1693
1694/* Execute commandline and returns the result.
1695 pszwhat is used for opt_t trace information. */
1696
1697static int emxomfld_spawn(char *pszcmd, const char *pszwhat)
1698{
1699 int argi;
1700 char ** argv;
1701 char * psz;
1702 int rc;
1703
1704 if (opt_t)
1705 show_spawn(pszwhat);
1706
1707 /* construct spawnvp() argument array */
1708 argi = 0;
1709 argv = NULL;
1710 psz = pszcmd;
1711 while (psz && *psz)
1712 {
1713 char *psz2 = psz;
1714
1715 /* skip blanks. */
1716 while (*psz2 == '\t' || *psz2 == ' ')
1717 psz2++;
1718
1719 /* find end of argument taking in account in arg quoting. */
1720 while (*psz2 && *psz2 != '\t' && *psz2 != ' ')
1721 {
1722 if (*psz2 == '"' || *psz2 == '\'')
1723 {
1724 char chQuote = *psz2++;
1725 while (*psz2 && *psz2 != chQuote)
1726 psz2++;
1727 }
1728 psz2++;
1729 }
1730
1731 /* terminate and set psz2 to point to next */
1732 if (*psz2)
1733 *psz2++ = '\0';
1734
1735 /* add argument to argument vector. */
1736 if (!(argi % 32))
1737 argv = xrealloc(argv, sizeof(argv[0]) * (argi + 32 + 1));
1738 argv[argi++] = psz;
1739
1740 /* next */
1741 psz = psz2;
1742 }
1743 argv[argi] = NULL;
1744
1745 /* Spawn process. */
1746 rc = spawnvp(P_WAIT, argv[0], argv);
1747 if (opt_t)
1748 fprintf(stderr, "*** Return from %s is %d\n", pszwhat, rc);
1749
1750 free(argv);
1751 return rc;
1752}
1753
1754
1755/* Cleanup by closing (if open) and deleting (if pressent) the
1756 response file. This function is used with atexit(). */
1757
1758static void cleanup (void)
1759{
1760 if (response_file != NULL)
1761 {
1762 fclose (response_file);
1763 response_file = NULL;
1764 }
1765 if (opt_t <= 1)
1766 {
1767 if (response_fname[0] != '\0')
1768 {
1769 remove (response_fname);
1770 response_fname[0] = '\0';
1771 }
1772 if (weakobj_fname[0] != '\0')
1773 {
1774 remove (weakobj_fname);
1775 weakobj_fname[0] = '\0';
1776 }
1777 if (weakdef_fname[0] != '\0')
1778 {
1779 remove (weakdef_fname);
1780 weakdef_fname[0] = '\0';
1781 }
1782 for (; conv_list; conv_list = conv_list->next)
1783 remove (conv_list->name);
1784 }
1785}
1786
1787/* Tell the user how to run this program. */
1788
1789static void usage (void)
1790{
1791 fputs ("emxomfld " VERSION INNOTEK_VERSION "\n"
1792 "Copyright (c) 1992-1996 by Eberhard Mattes\n"
1793 "Copyright (c) 2003 by InnoTek Systemberatung GmbH\n"
1794 "Copyright (c) 2003-2006 by Knut St. Osmundsen\n"
1795 "\n", stderr);
1796 fputs ("Usage: emxomfld -o <file> [-l <lib>] [-L <libdir>] [-T <base>] [-igtsS]\n"
1797 " [-Zexe] [-Zdll] [-Zsym] [-Zstack <size>] [-Zmap[=<map_file>]]\n"
1798 " [-Z[no-]autoconv] [-Zdll-search] [-O <option>] [-static]\n"
1799 " [-non_shared] [-Bstatic] [-dn] [call_shared] [-Bshared]\n"
1800 " [-dy] <file>...\n"
1801 "\n", stderr);
1802 fputs ("Options:\n"
1803 " -Zno-autoconv / -Zautoconv:\n"
1804 " Turns off/on the automatic conversion of a.out libs and objs.\n"
1805 " default: -Zautoconv\n"
1806 " -Bstatic, -non_shared, -dn, -static:\n"
1807 " Link with static libraries.\n"
1808 " The search order is then changed to: lib<name>_s.lib, <name>_s.lib,\n"
1809 " lib<name>.lib, <name>.lib\n", stderr);
1810 fputs (" -Bshared, -call_shared, -dy:\n"
1811 " Link with shared libraries. This is default.\n"
1812 " The search order is then changed to: lib<name>_dll.lib, <name>_dll.lib,\n"
1813 " lib<name>.lib, <name>.lib, <name>.dll, lib<name>_s.lib, <name>_s.lib.\n"
1814 " -Zdll-search:\n"
1815 " Enables dlls as valid libraries from shared linking. (default disabled)\n",
1816 stderr);
1817 fputs (" -Zsym:"
1818 " Invoke mapsym.cmd on the mapfile to produce a .sym file. Requires -Zmap.\n"
1819 "\n", stderr);
1820 fputs ("Environment variables:\n"
1821 " EMXOMFLD_TYPE:\n"
1822 " The type of linker we're using. Values: WLINK, VAC365, VAC308, LINK386.\n"
1823 " WLINK wlink.exe from Open Watcom v1.5 or later.\n"
1824 " VAC365 ilink.exe from IBM C and C++ Compilers for OS/2 v3.6 or later.\n"
1825 " VAC308 ilink.exe from Visual Age for C++ v3.08.\n"
1826 " LINK386 link386 form OS/2 install or DDK.\n", stderr);
1827 fputs (" EMXOMFLD_LINKER:\n"
1828 " Name of the linker to use and optionally extra parameters. Spaces in the\n"
1829 " linker name or path is not supported. Quotes are not supported either.\n"
1830 "The default values for these two variables are WLINK and wlink.exe.\n", stderr);
1831 fputs (" EMXOMFLD_RC_TYPE:\n"
1832 " The type of resource compiler we're using. Values: RC,WRC.\n"
1833 " RC rc.exe as shipped with OS/2 or found in the Toolkit\n"
1834 " WRC wrc.exe from Open Watcom v1.6 or later.\n", stderr);
1835 fputs (" EMXOMFLD_RC:\n"
1836 " Name of the resource compiler to use and optionally extra parameters.\n"
1837 " Spaces or quotes in the name or path are not supported.\n"
1838 "The default values for these two variables are RC and rc.exe.\n", stderr);
1839 exit (1);
1840}
1841
1842
1843
1844static struct option longopts[] =
1845{
1846#define OPT_LIBS_STATIC 0x1000
1847 {"Bstatic", 0, 0, OPT_LIBS_STATIC},
1848 {"non_shared", 0, 0, OPT_LIBS_STATIC},
1849 {"dn", 0, 0, OPT_LIBS_STATIC},
1850 {"static", 0, 0, OPT_LIBS_STATIC},
1851#define OPT_LIBS_SHARED 0x1001
1852 {"Bshared", 0, 0, OPT_LIBS_SHARED},
1853 {"call_shared", 0, 0, OPT_LIBS_SHARED},
1854 {"dy", 0, 0, OPT_LIBS_SHARED},
1855#define OPT_ZEXE 0x1002
1856 {"Zexe", 0, 0, OPT_ZEXE}, /* Create .exe file, touch `output file' */
1857#define OPT_ZDLL 0x1003
1858 {"Zdll", 0, 0, OPT_ZDLL}, /* Create .dll file, touch `output file' */
1859#define OPT_ZSTACK 0x1004
1860 {"Zstack", 1, 0, OPT_ZSTACK}, /* Set stack size */
1861#define OPT_ZMAP 0x1005
1862 {"Zmap", 2, 0, OPT_ZMAP}, /* Create .map file */
1863 {"Zmap=", 1, 0, OPT_ZMAP},
1864#define OPT_ZAUTOCONV 0x1006
1865 {"Zautoconv",0, 0, OPT_ZAUTOCONV},
1866#define OPT_ZNO_AUTOCONV 0x1007
1867 {"Zno-autoconv",0, 0, OPT_ZNO_AUTOCONV},
1868#define OPT_ZDLL_SEARCH 0x1008
1869 {"Zdll-search",0, 0, OPT_ZDLL_SEARCH},
1870#define OPT_ZSYM 0x1009
1871 {"Zsym",0, 0, OPT_ZSYM},
1872/* {"e", 1, 0, 'e'}, entry point */
1873 {"i", 0, 0, 'i'},
1874 {"o", 1, 0, 'o'},
1875 {"O", 1, 0, 'O'},
1876/* {"u", 1, 0, 'u'}, reference symbol */
1877 {"s", 0, 0, 's'},
1878 {"S", 0, 0, 'S'},
1879 {"t", 0, 0, 't'},
1880 {"T", 1, 0, 'T'},
1881 {"v", 0, 0, 'v'},
1882 {"x", 0, 0, 'x'},
1883 {"X", 0, 0, 'X'},
1884 {NULL, 0, 0, 0}
1885};
1886
1887/* Main function of emxomf. Parse the command line and call the IBM/M$
1888 linker (and optionally RC). */
1889
1890int main (int argc, char *argv[])
1891{
1892 struct stat s;
1893 int c, rc, files;
1894 const char *ext;
1895 char tmp[512], *t;
1896 char execname[512];
1897 name_list *pcur;
1898 int opt_libs_static = 0;
1899 int longind;
1900
1901 /* Get options from response files (@filename) and wildcard (*.o) on the command. */
1902
1903 _response (&argc, &argv);
1904 _wildcard (&argc, &argv);
1905
1906 /* Close and delete the response file on exit. */
1907
1908 atexit (cleanup);
1909
1910 /* Prepare parsing of the command line. */
1911
1912 files = 0;
1913 opterr = FALSE;
1914 /*optmode = GETOPT_KEEP; */
1915 if (argc < 2)
1916 usage ();
1917
1918 /* Parse the command line options and other arguments. */
1919 while ((c = getopt_long_only (argc, argv, "-l:y:L:", longopts, &longind)) != EOF)
1920 {
1921 if (c == 0)
1922 c = longopts[longind].val;
1923 switch (c)
1924 {
1925 case 1: /* Non-option argument */
1926
1927 /* Extract the extension to see what to do with this
1928 argument. */
1929
1930 ext = _getext (optarg);
1931
1932 if (ext == NULL)
1933 {
1934 /* GCC's temporary files don't have an extension. Add a
1935 dot to the end of the name to prevent the linker from
1936 adding `.obj'. */
1937
1938 sprintf (tmp, "%s.", optarg);
1939 add_name_list (&add_obj_fnames, tmp, 0);
1940 }
1941
1942 /* If it's a .def file, use it as module definition file
1943 (input). */
1944
1945 else if (stricmp (ext, ".def") == 0)
1946 {
1947 if (def_fname != NULL)
1948 {
1949 fprintf (stderr,
1950 "emxomfld: multiple module definition files\n");
1951 return 1;
1952 }
1953 def_fname = _realrealpath(optarg, NULL, 0);
1954 if (!def_fname)
1955 def_fname = optarg;
1956 }
1957
1958 /* If it's a .res file, use it as binary resource file
1959 (input). */
1960
1961 else if (stricmp (ext, ".res") == 0)
1962 {
1963 if (res_fname != NULL)
1964 {
1965 fprintf (stderr,
1966 "emxomfld: multiple binary resource files\n");
1967 return 1;
1968 }
1969 res_fname = _realrealpath(optarg, NULL, 0);
1970 if (!res_fname)
1971 res_fname = optarg;
1972 }
1973
1974 /* If it's a .lib file, use it as library file. We also
1975 accept .a files for those who use OMF files disguised as
1976 a.out files (to simplify their make files). */
1977
1978 else if (stricmp (ext, ".lib") == 0 || stricmp (ext, ".a") == 0 || stricmp (ext, ".dll") == 0)
1979 add_name_list (&add_lib_fnames, optarg, opt_libs_static);
1980
1981 /* Otherwise, assume it's an object file. */
1982
1983 else
1984 add_name_list (&add_obj_fnames, optarg, 0);
1985 ++files;
1986 break;
1987
1988 case 't':
1989 case 'i': /* Trace the linking process, sending /INFO to the IBM/M$ linker. */
1990 opt_t++;
1991 break;
1992
1993 case 'l': /* Add library */
1994 add_name_list (&add_lib_fnames, optarg, opt_libs_static);
1995 break;
1996
1997 case 'o': /* Set output file name */
1998 output_fname = optarg;
1999 break;
2000
2001 case 'L': /* Add library directory */
2002 add_name_list (&add_libdirs, optarg, 0);
2003 break;
2004
2005 case 'T': /* Set base address */
2006 base = optarg;
2007 break;
2008
2009 case 's': /* Strip all symbols */
2010 case 'S': /* Strip debugging symbols */
2011 strip_symbols = TRUE;
2012 break;
2013
2014 case 'x': /* Discard all local symbols */
2015 case 'X': /* Discard local symbols starting with L */
2016 break;
2017
2018 case 'v': /* For compatibility */
2019 break;
2020
2021 case 'O': /* Specify Linker option */
2022 add_name_list (&add_options, optarg, 0);
2023 break;
2024
2025 case OPT_ZDLL:
2026 dll_flag = TRUE;
2027 break;
2028
2029 case OPT_ZEXE:
2030 exe_flag = TRUE;
2031 break;
2032
2033 case OPT_ZMAP:
2034 map_flag = TRUE;
2035 if (optarg)
2036 {
2037 if (map_fname != NULL)
2038 {
2039 fprintf (stderr, "emxomfld: multiple map files files\n");
2040 return 1;
2041 }
2042 map_fname = optarg;
2043 }
2044 break;
2045
2046 case OPT_ZSTACK:
2047 if (!optarg)
2048 return 1;
2049 errno = 0;
2050 stack_size = strtol (optarg, &t, 0);
2051 if (errno != 0 || *t != 0 || t == optarg)
2052 return 1;
2053 stack_size_flag = 1;
2054 break;
2055
2056 case OPT_ZAUTOCONV:
2057 autoconvert_flag = 1;
2058 break;
2059 case OPT_ZNO_AUTOCONV:
2060 autoconvert_flag = 0;
2061 break;
2062
2063 case OPT_ZDLL_SEARCH:
2064 opt_dll_search = 1;
2065 break;
2066
2067 case OPT_ZSYM:
2068 sym_flag = TRUE;
2069 break;
2070
2071 case OPT_LIBS_STATIC:
2072 opt_libs_static = 1;
2073 break;
2074 case OPT_LIBS_SHARED:
2075 opt_libs_static = 0;
2076 break;
2077
2078 case '?':
2079 default:
2080 if (optind > 1)
2081 fprintf (stderr, "emxomfld: invalid option (%s)\n", argv[optind - 1]);
2082 else
2083 usage ();
2084 return 1;
2085 }
2086 }
2087 /* Set default value for output file. */
2088
2089 if (output_fname == NULL)
2090 {
2091 fprintf (stderr,
2092 "emxomfld: no output file, creating $$$.exe or $$$.dll\n");
2093 output_fname = "$$$";
2094 }
2095
2096 /* Check if there are any input files. */
2097
2098 if (files == 0)
2099 {
2100 fprintf (stderr, "emxomfld: no input files\n");
2101 return 1;
2102 }
2103
2104 /* Check that -Zmap was specified with -Zsym. */
2105
2106 if (sym_flag && !map_flag)
2107 {
2108 fprintf (stderr, "emxomfld: -Zsym without -Zmap.\n");
2109 return 1;
2110 }
2111
2112 /* Remove the output file if -Zexe is given. */
2113
2114 if (exe_flag)
2115 remove (output_fname);
2116
2117 /* If neither -Zmap nor -Zmap=file is used, pass "nul" to the linker in
2118 the map file field. If -Zmap is used, construct the name of the
2119 .map file. If -Zmap=file is used, use `file' as the name of the
2120 .map file. */
2121
2122 if (!map_flag)
2123 map_fname = "nul";
2124 else if (map_fname == NULL)
2125 {
2126 int cch = strlen (output_fname) + 1;
2127 t = xmalloc (cch + 4);
2128 memcpy (t, output_fname, cch);
2129 _remext (t);
2130 strcat (t, ".map");
2131 map_fname = t;
2132 }
2133
2134 /* Build the environment for the linker. */
2135
2136 make_env ();
2137
2138 /* EMXOMFLD_TYPE contains VAC365, VAC308 or LINK386 if set. If non of these
2139 we assume VAC365.
2140 EMXOMFLD_LINKER contains the linker name and perhaps extra arguments. If
2141 not set we'll use the default linker, ilink. */
2142
2143 t = getenv ("EMXOMFLD_TYPE");
2144 if ( t
2145 && stricmp (t, "WLINK")
2146 && stricmp (t, "VAC365")
2147 && stricmp (t, "VAC308")
2148 && stricmp (t, "LINK386")
2149 )
2150 fprintf (stderr, "emxomfld: warning: '%s' is an invalid value for EMXOMFLD_TYPE.\n", t);
2151 else if (t)
2152 linker_type = t;
2153
2154 t = getenv ("EMXOMFLD_LINKER");
2155 if (t)
2156 linker_name = t;
2157 if (opt_t)
2158 fprintf (stderr, "*** Linker : %s\n"
2159 "*** Linker type: %s\n", linker_name, linker_type);
2160
2161 /* apply object & library hacks */
2162 for (pcur = obj_fnames, rc = 0; !rc && pcur; pcur = pcur->next)
2163 {
2164 char szname[_MAX_PATH + 1];
2165 FILE *phfile = find_obj (szname, pcur->name);
2166 if (!phfile)
2167 continue;
2168 free (pcur->name);
2169 pcur->name = xstrdup(szname);
2170 fclose (phfile);
2171 }
2172
2173 for (pcur = lib_fnames, rc = 0; !rc && pcur; pcur = pcur->next)
2174 {
2175 char szname[_MAX_PATH + 1];
2176 FILE *phfile = find_lib (szname, pcur->name, !pcur->flags);
2177 if (!phfile)
2178 continue;
2179 free (pcur->name);
2180 pcur->name = xstrdup(szname);
2181 fclose (phfile);
2182 }
2183
2184 /* generate .def-file for dlls. */
2185
2186 if (!def_fname && dll_flag)
2187 gen_deffile ();
2188
2189 /* Do the weak prelinking. Important that this is done after make_env(). */
2190
2191 weak_prelink ();
2192
2193 /* Start building the linker command line. We can use a response
2194 file if the command line gets too long. */
2195
2196 arg_init (TRUE);
2197
2198 /* issue commandline */
2199 put_arg (linker_name, TRUE, FALSE);
2200
2201 if (stricmp (linker_type, "WLINK"))
2202 {
2203 /*
2204 For VAC365 and VAC308 the default options are:
2205
2206 /NOFR[EEFORMAT] Use /NOFREEFORMAT to allow a LINK386-compatible
2207 command line syntax, in which different types of file
2208 are grouped and separated by commas.
2209
2210 /DBGPACK If !strip_symbols then we'll add this option, which
2211 will cause type tables to be merged into one global
2212 table and so eliminating a lot of duplicate info.
2213
2214 For VAC365 additional default option is:
2215
2216 /STUB:<emxomfld-path>\os2stub.bin
2217 Causes this MZ stub to be used when linking the
2218 executables instead of the default on for the linker.
2219
2220 For LINK386 the default options are:
2221
2222 /BATCH Run in batch mode (disable prompting, don't
2223 echo response file)
2224
2225 The default options for all linkers are:
2226
2227 /NOLOGO Don't display sign-on banner
2228
2229 /NOEXTDICTIONARY Don't use extended dictionary (redefining
2230 library symbols is quite common)
2231
2232 /NOIGNORECASE Make symbols case-sensitive
2233
2234 /PACKCODE Group neighboring code segments (this is the
2235 default unless the SEGMENTS module definition
2236 statement is used for a segment of class
2237 'CODE'). Not grouping neighboring code
2238 segments would break sets
2239
2240 For non DLLs targets:
2241
2242 /BASE:0x10000 Base the executable an so removing extra fixups.
2243
2244 */
2245
2246 /* the next part depends on the linker type. */
2247 if (!stricmp (linker_type, "LINK386"))
2248 put_arg ("/bat", FALSE, FALSE);
2249 else /* vac3xx: */
2250 {
2251 put_arg ("/nofree", FALSE, FALSE);
2252 if (!strip_symbols)
2253 put_arg ("/db", FALSE, FALSE);
2254 if (map_flag)
2255 put_arg ("/map", FALSE, FALSE);
2256 }
2257 put_arg ("/nol", FALSE, FALSE);
2258 put_arg ("/noe", FALSE, FALSE);
2259 put_arg ("/noi", FALSE, FALSE);
2260 put_arg ("/packc", FALSE, FALSE);
2261
2262
2263 /* VAC365: check if we have os2stub.bin.
2264 We must to this after the above stuff else /nol might end up in the
2265 response file and we'll get the component output. */
2266
2267 if (!stricmp (linker_type, "VAC365"))
2268 {
2269 /* gklayout show that the linker isn't capable of determining a
2270 decent value for this parameter. 32MB makes gklayout link. */
2271 put_arg ("/ocache:0x02000000", FALSE, FALSE);
2272
2273 _execname (&execname[0], sizeof(execname));
2274 strcpy (_getname (&execname[0]), "os2stub.bin");
2275 if (!stat (execname, &s))
2276 {
2277 sprintf (tmp, "/STUB:%s", &execname[0]);
2278 put_arg (tmp, FALSE, FALSE);
2279 }
2280 }
2281
2282 /* Add the /INFORMATION option if the -i or -t option was given. This is
2283 for debugging. */
2284
2285 if (opt_t)
2286 put_arg ("/i", FALSE, FALSE);
2287
2288 /* Add the /DEBUG option if the -s option was not given. Without
2289 this, the linker throws away debugging information. */
2290
2291 if (!strip_symbols)
2292 put_arg ("/de", FALSE, FALSE);
2293
2294 /* Add the /BASE:n option to set the base address. This specifies
2295 the preferred load address of object 1. The base address being
2296 used is 0x10000 unless a DLL is generated or the -T option was
2297 given. -Tno can be used to suppress the /BASE:n option. */
2298
2299 if (base == NULL && !dll_flag)
2300 {
2301 struct _md *md;
2302
2303 if (def_fname != NULL)
2304 {
2305 int token;
2306 md = _md_open (def_fname);
2307 if (md == NULL)
2308 {
2309 fprintf (stderr, "emxomfld: cannot open `%s'\n", def_fname);
2310 exit (2);
2311 }
2312 token = _md_next_token (md);
2313 if (token == _MD_LIBRARY || token == _MD_PHYSICAL || token == _MD_VIRTUAL)
2314 dll_flag = TRUE;
2315 _md_close (md);
2316 }
2317 }
2318 if (base == NULL && !dll_flag)
2319 base = "0x10000";
2320 if (base != NULL && stricmp (base, "no") != 0)
2321 {
2322 sprintf (tmp, "/bas:%s", base);
2323 put_arg (tmp, FALSE, FALSE);
2324 }
2325
2326 /* Add the /STACK:n option if the -Zstack option was given. */
2327
2328 if (!dll_flag)
2329 {
2330 sprintf (tmp, "/st:0x%lx", stack_size * 1024);
2331 put_arg (tmp, FALSE, FALSE);
2332 }
2333
2334 /* Add the linker options specified with -O. */
2335
2336 put_args (options, FALSE);
2337
2338 /* Put the object file names onto the command line. */
2339
2340 force_response_file = TRUE; /* link386 workaround. */
2341 put_args (obj_fnames, TRUE);
2342 put_arg (",", FALSE, FALSE);
2343
2344 /* Put the output file name onto the command line. */
2345
2346 put_arg (output_fname, TRUE, TRUE);
2347 put_arg (",", FALSE, FALSE);
2348
2349 /* Put the map file name onto the command line. */
2350
2351 put_arg (map_fname, TRUE, TRUE);
2352 put_arg (",", FALSE, FALSE);
2353
2354 /* Put the library file names onto the command line. */
2355
2356 put_args (lib_fnames, TRUE);
2357 put_arg (",", FALSE, FALSE);
2358
2359 /* Put the name of the module definition file onto the command line. */
2360
2361 put_arg (def_fname, TRUE, TRUE);
2362 put_arg (";", FALSE, FALSE);
2363
2364 /* Call Linker and abort on failure. */
2365 }
2366 else /* wlink */
2367 {
2368 unsigned uPMType = 0;
2369 int need_stub = 1;
2370
2371 open_response_file ();
2372
2373 /* convert common ilink/link386 command line arguments. */
2374
2375 for (pcur = options; pcur; pcur = pcur->next)
2376 {
2377 size_t cchOpt;
2378 const char *pszVal;
2379 size_t cchVal;
2380
2381 if (pcur->name [0] != '-' && pcur->name [0] != '/')
2382 continue;
2383 if (strchr (&pcur->name[1], '='))
2384 continue;
2385 pszVal = strchr (&pcur->name[1], ':');
2386 cchOpt = pszVal ? pszVal - &pcur->name[1] : strlen (&pcur->name[1]);
2387 if (pszVal && pszVal[1])
2388 cchVal = strlen (++pszVal);
2389 else
2390 pszVal = NULL, cchVal = 0;
2391#define MAX(a,b) ((a) <= (b) ? (a) : (b))
2392 if (!strnicmp (&pcur->name[1], "PMtype", cchOpt)
2393 && cchVal)
2394 {
2395 if (!strnicmp (pszVal, "PM", cchVal))
2396 uPMType = _MD_WINDOWAPI;
2397 else if (!strnicmp (pszVal, "VIO", cchVal))
2398 uPMType = _MD_WINDOWCOMPAT;
2399 else if (!strnicmp (pszVal, "NOVIO", MAX (cchVal, 3)))
2400 uPMType = _MD_NOTWINDOWCOMPAT;
2401 else
2402 continue;
2403 }
2404 else if (!strnicmp (&pcur->name[1], "PDD", MAX (cchOpt, 3)))
2405 uPMType = _MD_PHYSICAL;
2406 else if (!strnicmp (&pcur->name[1], "VDD", MAX (cchOpt, 3)))
2407 uPMType = _MD_VIRTUAL;
2408 else if (!strnicmp (&pcur->name[1], "STACK", MAX (cchOpt, 2))
2409 && cchVal && !stack_size_flag)
2410 {
2411 errno = 0;
2412 stack_size = strtol (pszVal, &t, 0);
2413 if (errno || *t)
2414 {
2415 fprintf (stderr, "emxomfld: Number conversion failed: '%s'\n", pcur->name);
2416 return 1;
2417 }
2418 stack_size = (stack_size + 0xfff) / 1024;
2419 }
2420 /* ignore these */
2421 else if (!strnicmp (&pcur->name[1], "PACKCODE", MAX (cchOpt, 5))
2422 || !strnicmp (&pcur->name[1], "NOPACKCODE", MAX (cchOpt, 3))
2423 || !strnicmp (&pcur->name[1], "PACKDATA", MAX (cchOpt, 5))
2424 || !strnicmp (&pcur->name[1], "NOPACKDATA", MAX (cchOpt, 7))
2425 || !strnicmp (&pcur->name[1], "EXEPACK", MAX (cchOpt, 1))
2426 || !strnicmp (&pcur->name[1], "NOEXEPACK", MAX (cchOpt, 5))
2427 || !strnicmp (&pcur->name[1], "DBGPACK", MAX (cchOpt, 2))
2428 || !strnicmp (&pcur->name[1], "NODBGPACK", MAX (cchOpt, 4))
2429 )
2430 fprintf (stderr, "emxomfld: warning: ignoring ilink option '%s'\n", pcur->name);
2431 else
2432 continue;
2433 pcur->name = NULL;
2434#undef MAX
2435 }
2436
2437 /* figure out what format options we're gonna use */
2438
2439 if (!def_fname && !dll_flag)
2440 {
2441 switch (uPMType)
2442 {
2443 case 0:
2444 case _MD_WINDOWCOMPAT:
2445 default:
2446 fprintf (response_file, "FORMAT OS2 LX PMCompatible\n");
2447 break;
2448 case _MD_WINDOWAPI:
2449 fprintf (response_file, "FORMAT OS2 LX PM\n");
2450 break;
2451 case _MD_NOTWINDOWCOMPAT:
2452 fprintf (response_file, "FORMAT OS2 LX FULLscreen\n");
2453 break;
2454 case _MD_PHYSICAL:
2455 dll_flag = TRUE;
2456 fprintf (response_file, "FORMAT OS2 LX PHYSdevice\n");
2457 break;
2458 case _MD_VIRTUAL:
2459 dll_flag = TRUE;
2460 fprintf (response_file, "FORMAT OS2 LX VIRTdevice\n");
2461 break;
2462 }
2463 }
2464 else if (!def_fname && dll_flag)
2465 fprintf (response_file, "FORMAT OS2 LX DLL INITINSTANCE TERMINSTANCE\n");
2466 else
2467 {
2468 int token;
2469 struct _md *pMd = _md_open (def_fname);
2470 if (!pMd)
2471 {
2472 fprintf (stderr, "emxomfld: cannot open `%s'\n", def_fname);
2473 exit (2);
2474 }
2475 token = _md_next_token (pMd);
2476 if (token == _MD_PHYSICAL)
2477 {
2478 dll_flag = TRUE;
2479 fprintf (response_file, "FORMAT OS2 LX PHYSdevice\n");
2480 }
2481 else if (token == _MD_VIRTUAL)
2482 {
2483 dll_flag = TRUE;
2484 fprintf (response_file, "FORMAT OS2 LX VIRTdevice\n");
2485 }
2486 else if (token == _MD_LIBRARY || dll_flag)
2487 {
2488 int fInitInstance = 1;
2489 int fTermInstance = 1;
2490 for (;;)
2491 {
2492 switch (_md_next_token (pMd))
2493 {
2494 case _MD_INITINSTANCE: fInitInstance = 1; continue;
2495 case _MD_INITGLOBAL: fInitInstance = 0; continue;
2496 case _MD_TERMINSTANCE: fTermInstance = 1; continue;
2497 case _MD_TERMGLOBAL: fTermInstance = 0; continue;
2498 case _MD_quote: continue;
2499 case _MD_word: continue;
2500 default: break;
2501 }
2502 break;
2503 }
2504 dll_flag = TRUE;
2505 fprintf (response_file, "FORMAT OS2 LX DLL %s %s\n",
2506 fInitInstance ? "INITINSTANCE" : "INITGLOBAL",
2507 fTermInstance ? "TERMINSTANCE" : "TERMGLOBAL");
2508 }
2509 else
2510 {
2511 if (token == _MD_NAME)
2512 {
2513 /* (ignores uPMType and uses the .def-file) */
2514 token = _md_next_token (pMd);
2515 if (token == _MD_quote || token == _MD_word)
2516 token = _md_next_token (pMd);
2517 }
2518 else
2519 token = uPMType;
2520 switch (token)
2521 {
2522 case _MD_WINDOWAPI:
2523 fprintf (response_file, "FORMAT OS2 LX PM\n");
2524 break;
2525 default:
2526 case _MD_WINDOWCOMPAT:
2527 fprintf (response_file, "FORMAT OS2 LX PMCompatible\n");
2528 break;
2529 case _MD_NOTWINDOWCOMPAT:
2530 fprintf (response_file, "FORMAT OS2 LX FullScreen\n");
2531 break;
2532 }
2533 }
2534 _md_close (pMd);
2535 }
2536
2537 /* output files */
2538
2539 fprintf (response_file, "NAME '%s'\n", output_fname);
2540
2541 if (map_flag && map_fname)
2542 fprintf (response_file, "OPTION MAP='%s'\n", map_fname);
2543 else if (map_flag)
2544 fprintf (response_file, "OPTION MAP\n");
2545
2546 /* standard stuff */
2547
2548 if (!strip_symbols)
2549 fprintf (response_file, "DEBUG HLL\n");
2550 fprintf (response_file, "OPTION QUIET\n");
2551 fprintf (response_file, "OPTION OSNAME='OS/2 EMX'\n");
2552 fprintf (response_file, "OPTION CASEEXACT\n");
2553 if (!dll_flag)
2554 fprintf (response_file, "OPTION STACK=%#lx\n", stack_size * 1024);
2555 if (!dll_flag && !base)
2556 base = "0x10000";
2557 if (base)
2558 fprintf (response_file, "OPTION OFFSET=%s\n", base);
2559
2560 /* Add the /INFORMATION option if the -i or -t option was given. This is
2561 for debugging. */
2562
2563// if (opt_t)
2564// put_arg ("/i", FALSE, FALSE);
2565
2566 /* Add the linker options specified with -O. */
2567
2568 for (pcur = options; pcur; pcur = pcur->next)
2569 if (pcur->name)
2570 fprintf (response_file, "%s\n", pcur->name);
2571
2572 /* Put the object file names onto the command line. */
2573
2574 for (pcur = obj_fnames; pcur; pcur = pcur->next)
2575 fprintf (response_file, "FILE '%s'\n", pcur->name);
2576
2577 /* Put the library file names onto the command line. */
2578
2579 for (pcur = lib_fnames; pcur; pcur = pcur->next)
2580 fprintf (response_file, "LIBRARY '%s'\n", pcur->name);
2581
2582 /* Translate the essentials of the module definition file into wlink lingo. */
2583
2584 if (def_fname)
2585 {
2586 struct _md *pMd = _md_open (def_fname);
2587 if (!pMd)
2588 {
2589 fprintf (stderr, "emxomfld: cannot open `%s'\n", def_fname);
2590 exit (2);
2591 }
2592 _md_next_token (pMd);
2593 _md_parse (pMd, def_2_watcom, &need_stub);
2594 _md_close (pMd);
2595 }
2596
2597 /* the stub */
2598
2599 if (need_stub)
2600 {
2601 _execname(&execname[0], sizeof(execname));
2602 strcpy (_getname (&execname[0]), "os2stub.bin");
2603 if (!stat (execname, &s))
2604 fprintf (response_file, "OPTION STUB='%s'\n", execname);
2605 }
2606
2607 }
2608
2609 /* End the arguments and run the linker. */
2610
2611 arg_end ();
2612
2613 rc = emxomfld_spawn (command_line, "Linker");
2614 if (rc == 4 && !strnicmp(linker_type, "VAC3", 4)) /* Ignore iLink warnings. */
2615 rc = 0;
2616 if (rc < 0)
2617 {
2618 perror (linker_name);
2619 exit (2);
2620 }
2621
2622 /* Run RC if Linker completed successfully and a binary resource
2623 file was given on the command line. */
2624
2625 if (rc == 0 && res_fname != NULL)
2626 {
2627 /* EMXOMFLD_RC_TYPE contains RC or WRC if set. If non of these
2628 we assume RC.
2629 EMXOMFLD_RC contains the compiler name and perhaps extra
2630 arguments. If not set we'll use the default compiler, rc.exe. */
2631
2632 t = getenv ("EMXOMFLD_RC_TYPE");
2633 if ( t
2634 && stricmp (t, "RC")
2635 && stricmp (t, "WRC"))
2636 fprintf (stderr, "emxomfld: warning: '%s' is an invalid value for EMXOMFLD_RC_TYPE.\n", t);
2637 else if (t)
2638 rc_type = t;
2639
2640 t = getenv ("EMXOMFLD_RC");
2641 if (t)
2642 rc_name = t;
2643 if (opt_t)
2644 fprintf (stderr, "*** Resource compiler : %s\n"
2645 "*** Resource compiler type: %s\n", rc_name, rc_type);
2646
2647 if (!stricmp (rc_type, "RC"))
2648 {
2649 arg_init (TRUE);
2650 put_arg (rc_name, TRUE, FALSE);
2651 put_arg ("-n", FALSE, FALSE);
2652 put_arg (res_fname, TRUE, FALSE);
2653 put_arg (output_fname, TRUE, FALSE);
2654 arg_end ();
2655 rc = emxomfld_spawn (command_line, "Resource Linker");
2656 if (rc < 0)
2657 {
2658 perror ("emxomfld: rc");
2659 exit (2);
2660 }
2661 }
2662 else
2663 {
2664 /* wrc doesn't understand response files and put_arg handles max 110 chars */
2665 rc = spawnlp (P_WAIT, rc_name, rc_name, "-q", res_fname, output_fname, NULL);
2666 if (rc < 0)
2667 {
2668 perror ("emxomfld: wrc");
2669 exit (2);
2670 }
2671 }
2672 }
2673
2674 /* If both Linker and RC completed successfully and the -Zexe option
2675 was given, touch the output file (without .exe) to keep `make'
2676 happy. */
2677
2678 if (rc == 0 && exe_flag)
2679 {
2680 /* find target and source filenames. */
2681 t = xstrdup (output_fname);
2682 _remext (t);
2683 _execname (&execname[0], sizeof(execname));
2684 strcpy (_getname(&execname[0]), "ldstub.bin");
2685
2686 /* Copy stub into file */
2687 if (opt_t)
2688 fprintf (stderr, "*** copy %s to %s (-Zexe)", execname, t);
2689 DosCopy (&execname[0], t, 4);
2690
2691 /* Now touch it */
2692 if (utime (t, NULL))
2693 {
2694 perror ("emxomfld");
2695 exit (2);
2696 }
2697 free (t);
2698 }
2699
2700 /* Run mapsym if requested and linking succeeded. */
2701 if (rc == 0 && sym_flag)
2702 {
2703 char* cwd = getcwd (NULL, 0);
2704 char map_fname_fullpath[_MAX_PATH];
2705 char drive[_MAX_PATH];
2706 char dir[_MAX_DIR];
2707
2708 /* get absolute path of map file and change CWD to map file directory. */
2709 _fullpath (map_fname_fullpath, map_fname, sizeof (map_fname_fullpath));
2710 _splitpath (map_fname_fullpath, drive, dir, NULL, NULL);
2711 strcat (drive, dir);
2712 if (chdir (drive))
2713 {
2714 perror ("chdir failed");
2715 exit (2);
2716 }
2717
2718 /* Invoke mapsym.cmd writing the .sym file to current directory. */
2719 arg_init (TRUE);
2720 if (getenv ("COMSPEC"))
2721 put_arg (getenv ("COMSPEC"), TRUE, FALSE);
2722 else
2723 put_arg ("cmd.exe", TRUE, FALSE);
2724 put_arg ("/c", FALSE, FALSE);
2725 put_arg ("mapsym.cmd", TRUE, FALSE);
2726 if (!stricmp (linker_type, "WLINK"))
2727 put_arg ("watcom", TRUE, FALSE);
2728 else if (!stricmp (linker_type, "LINK386"))
2729 put_arg ("link386", TRUE, FALSE);
2730 else
2731 put_arg ("vac3xx", TRUE, FALSE);
2732 put_arg (map_fname_fullpath, TRUE, FALSE);
2733 arg_end ();
2734 rc = emxomfld_spawn (command_line, "Mapsym");
2735 if (rc < 0)
2736 {
2737 perror ("emxomfld: mapsym");
2738 exit (2);
2739 }
2740
2741 /* Restore the working directory */
2742 if (chdir (cwd))
2743 {
2744 perror ("chdir failed");
2745 exit (2);
2746 }
2747 }
2748
2749 /* Return the return code of Linker or RC. */
2750
2751 return rc;
2752}
2753
Note: See TracBrowser for help on using the repository browser.