source: trunk/emx/src/emxbind/emxbind.c@ 2673

Last change on this file since 2673 was 2673, checked in by bird, 19 years ago
  • *:

o Synced over changed from 0.6.1 bugfixing.

  • emxbind:

o #38: Fixed truncation bug writing to the LX nametable. (Yuri)
o #38: Imports and exports are limited to 255 not 127 chars. (Yuri)
o #28: Use DLL name from the .def file when present.

  • emxomf:

o #70: Demangle symbol names in debug info. (thanks to Yuri)

  • emxomfld:

o #55: delete the response file when reinit the args.
o #46: specify .map file extension to the linker.
o #34: Removed all the silliness trying to deal with truncated symbols.
o Don't display usage() on failure, just the error message.
o #20: use mkstemp + close instead of mktemp for the response file.

  • ld:

o #20: use make_temp_file instead of mktemp. This involved including

libiberty.h which required some adjustments of duplicate code to work.

o #27: Applied fix from Yuri.

  • libmoddef:

o Allow '.' and '@' in LIBRARY/NAME names.

  • Property cvs2svn:cvs-rev set to 1.10
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 14.2 KB
Line 
1/* emxbind.c -- Create an .exe executable from an a.out executable
2 Copyright (c) 1991-1997 Eberhard Mattes
3
4This file is part of emxbind.
5
6emxbind is free software; you can redistribute it and/or modify it
7under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11emxbind is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with emxbind; see the file COPYING. If not, write to
18the Free Software Foundation, 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, USA. */
20
21
22#define EXTERN
23
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <getopt.h>
28#include <sys/moddef.h>
29#include "defs.h"
30#include "emxbind.h"
31
32
33/* The name of the module definition file (set by the -d option) or
34 NULL (if there is no module definition file). If it's the empty
35 string, the input file name with .def extension will be used. */
36
37static char *opt_d = NULL;
38
39/* The banner line of emxbind. */
40
41static char *title = "emxbind " VERSION " -- "
42 "Copyright (c) 1991-1997 by Eberhard Mattes";
43
44/* File names of various files. inp_fname holds the name of the
45 input executable, stub_fname the name of the DOS stub file and
46 def_fname the name of the module definition file (-d option). */
47
48static char inp_fname[FNAME_SIZE];
49static char stub_fname[FNAME_SIZE];
50static char def_fname[FNAME_SIZE];
51
52/* These global variables have the same values as the argc and argv
53 parameters, respectively, of main(). */
54
55static int gargc;
56static char **gargv;
57
58
59/* Give the user a short reminder about how to call this program. */
60
61static void usage (void)
62{
63 puts (title);
64 puts ("\nUsage:");
65 puts (" emxbind [-b] [<options>] <stub>[.exe] <input> [<output>[.exe]]");
66 puts (" emxbind [-b] [<options>] [-o <output>[.exe]] <input>");
67 puts (" emxbind -e [<options>] <input>[.exe]");
68 puts (" emxbind -s [<options>] <input>[.exe]");
69 puts ("\nCommands:");
70 puts (" -b bind .exe (default)");
71 puts (" -e set OS/2 .exe flags: -f, -p or -w");
72 puts (" -s strip symbols");
73 puts ("\nOptions:");
74 puts (" -f application type: full screen (-b and -e)");
75 puts (" -p application type: Presentation Manager (-b and -e)");
76 puts (" -w application type: windowed (-b and -e)");
77 puts (" -q be quiet");
78 puts (" -v be verbose");
79 puts (" -s strip symbols (-b only)");
80 puts (" -c[<core>] add data from core dump file (-b only)");
81 puts (" -d[<def>] read module definition file (-b only)");
82 puts (" -h<size> set heap size for OS/2 (-b only)");
83 puts (" -k<size> set stack size for OS/2 (-b only)");
84 puts (" -m<map> write .map file (-b only)");
85 puts (" -r<res> add resources (-b only)");
86 exit (1);
87}
88
89
90/* A module statement is ignored: display a warning message if the
91 verbosity level is high enough. */
92
93static void def_ignored (const char *name)
94{
95 if (verbosity >= 2)
96 printf ("emxbind: %s statement not supported (warning)\n", name);
97}
98
99
100/* Callback function for reading the module definition file. Display
101 a warning for ignored statements if the verbosity level is high
102 enough. Save data from the other statements. */
103
104static int md_callback (struct _md *md, const _md_stmt *stmt, _md_token token,
105 void *arg)
106{
107 struct export exp;
108
109 switch (token)
110 {
111 case _MD_BASE:
112 def_ignored ("BASE");
113 break;
114
115 case _MD_CODE:
116 def_ignored ("CODE");
117 break;
118
119 case _MD_DATA:
120 def_ignored ("DATA");
121 break;
122
123 case _MD_DESCRIPTION:
124
125 /* Save the description string for putting it into the
126 non-resident name table. */
127
128 description = xstrdup (stmt->descr.string);
129 break;
130
131 case _MD_EXETYPE:
132 def_ignored ("EXETYPE");
133 break;
134
135 case _MD_EXPORTS:
136
137 /* Add an export entry. */
138
139 exp.ord = stmt->export.ordinal;
140 exp.resident = (!exp.ord || (stmt->export.flags & _MDEP_RESIDENTNAME)) ? TRUE : FALSE;
141 exp.entryname = xstrdup (stmt->export.entryname);
142 exp.flags = stmt->export.flags;
143 if (stmt->export.internalname[0] != 0)
144 exp.internalname = xstrdup (stmt->export.internalname);
145 else
146 exp.internalname = xstrdup (stmt->export.entryname);
147 exp.offset = 0;
148 exp.object = 0;
149 add_export (&exp);
150 break;
151
152 case _MD_HEAPSIZE:
153 def_ignored ("HEAPSIZE");
154 break;
155
156 case _MD_IMPORTS:
157 def_ignored ("IMPORTS");
158 break;
159
160 case _MD_LIBRARY:
161
162 /* Create a DLL. Override the module name if specified. Save the
163 initialization and termination policies after choosing default
164 values for unspecified values. */
165
166 dll_flag = TRUE;
167
168 if (stmt->library.name[0] != 0)
169 module_name = xstrdup (stmt->library.name);
170
171 switch (stmt->library.init)
172 {
173 case _MDIT_GLOBAL:
174 init_global = TRUE;
175 break;
176 case _MDIT_INSTANCE:
177 init_global = FALSE;
178 break;
179 default:
180 break;
181 }
182 switch (stmt->library.term)
183 {
184 case _MDIT_GLOBAL:
185 term_global = TRUE;
186 break;
187 case _MDIT_INSTANCE:
188 term_global = FALSE;
189 break;
190 default:
191 break;
192 }
193 if (stmt->library.init != _MDIT_DEFAULT
194 && stmt->library.term == _MDIT_DEFAULT)
195 term_global = init_global;
196 if (stmt->library.term != _MDIT_DEFAULT
197 && stmt->library.init == _MDIT_DEFAULT)
198 init_global = term_global;
199 break;
200
201 case _MD_NAME:
202
203 /* Create a program. Save the module name and the application
204 type. */
205
206 if (stmt->name.name[0] != 0)
207 module_name = xstrdup (stmt->name.name);
208 app_type = stmt->name.pmtype;
209 break;
210
211 case _MD_OLD:
212 def_ignored ("OLD");
213 break;
214
215 case _MD_PROTMODE:
216 def_ignored ("PROTMODE");
217 break;
218
219 case _MD_REALMODE:
220 def_ignored ("REALMODE");
221 break;
222
223 case _MD_SEGMENTS:
224 def_ignored ("SEGMENTS");
225 break;
226
227 case _MD_STACKSIZE:
228
229 /* Check and save the stack size. */
230
231 if (stmt->stacksize.size < 20*1024
232 || stmt->stacksize.size > 512*1024*1024)
233 error ("Invalid stack size in module definition file");
234 stack_size = (stmt->stacksize.size + 0xfff) & ~0xfff;
235 break;
236
237 case _MD_STUB:
238
239 /* Save the name of the stub. */
240
241 if (!stmt->stub.none)
242 _strncpy (stub_fname, stmt->stub.name, sizeof (stub_fname));
243 break;
244
245 case _MD_VIRTUAL:
246 case _MD_PHYSICAL:
247 error ("VIRTUAL DEVICE and PHYSICAL DEVICE statements not supported");
248
249 case _MD_parseerror:
250
251 /* Handle a syntax error. */
252
253 error ("%s (line %ld of %s)", _md_errmsg (stmt->error.code),
254 _md_get_linenumber (md), def_fname);
255 break;
256
257 default:
258 abort ();
259 }
260 return 0;
261}
262
263
264/* Read the module definition file. */
265
266static void read_def_file (void)
267{
268 struct _md *md;
269
270 md = _md_open (def_fname);
271 if (md == NULL)
272 error ("cannot open `%s'", def_fname);
273 _md_next_token (md);
274 _md_parse (md, md_callback, NULL);
275 _md_close (md);
276}
277
278
279/* Fetch a file name from the command line. If there are no more
280 arguments or if the current argument looks like an option, don't
281 use an argument and use the default file name DEF instead. If DEF
282 is NULL, a file name must be provided. If EXT is non-NULL, it is
283 used as default extension. This function will update optind if it
284 uses an argument. */
285
286static void file_name (char *dst, const char *ext, const char *def)
287{
288 if (optind < gargc && gargv[optind][0] != '-')
289 {
290 if (strlen (gargv[optind]) > FNAME_SIZE - 5)
291 error ("file name too long");
292 strcpy (dst, gargv[optind]);
293 ++optind;
294 }
295 else if (def == NULL)
296 error ("file name missing");
297 else
298 strcpy (dst, def);
299 if (ext)
300 {
301 char *curext = _getext2 (dst);
302 if (curext && *curext == '.')
303 curext++;
304 if (strcmp (curext, ext))
305 {
306 if (strlen (dst) > FNAME_SIZE - 5)
307 error ("file name too long");
308 strcat (dst, ".");
309 strcat (dst, ext);
310 }
311 }
312}
313
314
315/* Parse the command line. */
316
317static void get_args (void)
318{
319 int c;
320 char *q;
321 const char *opt_o = NULL;
322
323 /* At least one argument, the command option, must be supplied. */
324
325 if (gargc <= 1)
326 usage ();
327
328 /* Don't let getopt() report errors, use `-' to introduce options. */
329
330 opterr = FALSE;
331//optswchar = "-";
332
333 /* No command option has been seen yet. */
334
335 mode = 0;
336
337 /* Examine the initial (emxbind) options, one by one. */
338
339 while ((c = getopt (gargc, gargv,
340 "bc::d::efh:k:m:o:pqr:svw")) != -1)
341 {
342 switch (c)
343 {
344 case 's':
345 /* -s after -b selects 'strip on bind' mode.
346 -s without -b selects the 'strip in a executable' mode */
347 if (mode == 'b')
348 {
349 opt_s = TRUE;
350 break;
351 }
352 case 'b':
353 case 'e':
354 if (mode != 0)
355 error ("multiple commands specified");
356 mode = c;
357 break;
358 case 'c':
359 if (opt_c != NULL)
360 error ("multiple core files");
361 opt_c = (optarg != NULL ? optarg : "");
362 break;
363 case 'd':
364 if (opt_d != NULL)
365 error ("multiple module definition files");
366 opt_d = (optarg != NULL ? optarg : "");
367 break;
368 case 'f':
369 opt_f = TRUE;
370 break;
371 case 'h':
372 errno = 0;
373 heap_size = strtol (optarg, &q, 0);
374 if (errno != 0 || heap_size < 0 || heap_size > 512 || *q != 0)
375 error ("invalid heap size");
376 heap_size *= 1024*1024;
377 break;
378 case 'k':
379 errno = 0;
380 stack_size = strtol (optarg, &q, 0);
381 if (errno != 0 || *q != 0 ||
382 (stack_size < 20 || stack_size > 512*1024))
383 error ("invalid stack size");
384 stack_size *= 1024;
385 stack_size = (stack_size + 0xfff) & ~0xfff;
386 break;
387 case 'm':
388 if (opt_m != NULL)
389 error ("multiple map files");
390 opt_m = optarg;
391 break;
392 case 'o':
393 if (opt_o != NULL)
394 error ("multiple output files");
395 opt_o = optarg;
396 break;
397 case 'p':
398 opt_p = TRUE;
399 break;
400 case 'q':
401 verbosity = 0;
402 break;
403 case 'r':
404 opt_r = optarg;
405 break;
406 case 'v':
407 verbosity = 2;
408 break;
409 case 'w':
410 opt_w = TRUE;
411 break;
412 default:
413 error ("invalid option");
414 }
415 }
416
417 /* The default command option is -b. */
418
419 if (mode == 0)
420 mode = 'b';
421
422 /* Complain if an illegal combination of options is used. */
423
424 if (opt_o != NULL && mode != 'b')
425 error ("-o option can be used only with -b command");
426 if (opt_c != NULL && mode != 'b')
427 error ("-c option can be used only with -b command");
428 if ((opt_f || opt_p || opt_w) && mode != 'b' && mode != 'e')
429 error ("-f, -p and -w options can be used only with -b and -e commands");
430 if (opt_f + opt_p + opt_w > TRUE)
431 error ("more than one of -f, -p and -w options given");
432 if (mode == 'e' && !(opt_p || opt_f || opt_w))
433 error ("-e command requires -f, -p or -w option");
434 if (opt_d != NULL && mode != 'b')
435 error ("-d option can be used only with -b command");
436
437 /* If the -c option is used without argument, "core" will be used as
438 core dump file. */
439
440 if (opt_c != NULL && *opt_c == 0)
441 opt_c = "core";
442
443 /* Set the default path to the DOS stub */
444 _execname (stub_fname, sizeof (stub_fname));
445 strcpy (_getname (stub_fname), "os2stub.bin");
446
447 /* If the -E option is not given and the name is not given by the
448 EMXBIND_DLL environment variable, "emx.dll" will be used. */
449
450 /* Parse the rest of the command line, depending on the command
451 option. */
452
453 switch (mode)
454 {
455 case 'b':
456 if (gargc - optind <= 1 || gargv[optind+1][0] == '-')
457 ;
458 else if (opt_o != NULL)
459 error ("Too many file names specified");
460 else
461 file_name (stub_fname, "exe", NULL);
462 file_name (inp_fname, NULL, NULL);
463 if (opt_d != NULL)
464 {
465 if (opt_d[0] == 0)
466 {
467 _strncpy (def_fname, inp_fname, sizeof (def_fname) - 4);
468 _remext (def_fname);
469 }
470 else
471 _strncpy (def_fname, opt_d, sizeof (def_fname) - 4);
472 _defext (def_fname, "def");
473 read_def_file ();
474 }
475 file_name (out_fname, (dll_flag ? "dll" : "exe"),
476 (opt_o != NULL ? opt_o : inp_fname));
477 if (stricmp (inp_fname, out_fname) == 0)
478 error ("The input and output files have the same name");
479 break;
480
481 case 'e':
482 case 's':
483 file_name (inp_fname, "exe", NULL);
484 break;
485 }
486
487 /* Complain if there are any unprocessed arguments left. */
488
489 if (optind < gargc)
490 error ("too many arguments");
491}
492
493
494static void cleanup (void)
495{
496 my_remove (&out_file);
497}
498
499
500/* Open the files, depending on the command option. The module
501 definition file (-d option) is not handled here. */
502
503static void open_files (void)
504{
505 atexit (cleanup);
506 switch (mode)
507 {
508 case 'b':
509 my_open (&inp_file, inp_fname, open_read);
510 my_open (&stub_file, stub_fname, open_read);
511 if (opt_c != NULL)
512 my_open (&core_file, opt_c, open_read);
513 if (opt_r != NULL)
514 my_open (&res_file, opt_r, open_read);
515 my_open (&out_file, out_fname, create_write);
516 break;
517 case 'e':
518 case 's':
519 my_open (&inp_file, inp_fname, open_read_write);
520 break;
521 }
522}
523
524
525/* Close all the open files. */
526
527static void close_files (void)
528{
529 my_close (&out_file);
530 my_close (&inp_file);
531 my_close (&stub_file);
532 my_close (&core_file);
533 my_close (&res_file);
534}
535
536
537/* This is the main function. Parse the command line and perform the
538 action requested by the user. */
539
540int main (int argc, char *argv[])
541{
542 /* Setup global variables for referencing the command line arguments. */
543
544 gargc = argc; gargv = argv;
545
546 /* Parse the command line. */
547
548 get_args ();
549
550 /* Display the banner line unless suppressed. */
551
552 if (verbosity > 0) puts (title);
553
554 /* If emxl.exe was located automatically by emxbind, display the
555 path name of emxl.exe. */
556
557 if (verbosity >= 2)
558 printf ("Loader program for DOS: %s\n", stub_fname);
559
560 /* Open the files. */
561
562 open_files ();
563
564 /* Further processing depends on the command. */
565
566 cmd (mode);
567
568 /* Close the files. */
569
570 close_files ();
571 return 0;
572}
Note: See TracBrowser for help on using the repository browser.