source: trunk/emx/src/emxomf/emxomf.c@ 2446

Last change on this file since 2446 was 2431, checked in by bird, 20 years ago

Fixed problems with symbol truncation.
Kudos to Yuri for tracking down the places which required attention.

  • Property cvs2svn:cvs-rev set to 1.43
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 129.1 KB
Line 
1/* emxomf.c -- Convert GNU-style a.out object files (with emx extensions)
2 to OS/2-style OMF (Object Module Formats) object files
3 Copyright (c) 1992-1998 Eberhard Mattes
4
5This file is part of emxomf.
6
7emxomf is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2, or (at your option)
10any later version.
11
12emxomf is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with emxomf; see the file COPYING. If not, write to
19the Free Software Foundation, 59 Temple Place - Suite 330,
20Boston, MA 02111-1307, USA. */
21
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <stdarg.h>
26#include <string.h>
27#include <alloca.h>
28#include <ctype.h>
29#include <getopt.h>
30#include <alloca.h>
31#include <sys/param.h>
32#include <sys/emxload.h>
33#include <sys/types.h>
34#include <sys/stat.h>
35#include <sys/time.h>
36#include <ar.h>
37#include <assert.h>
38
39/* Insert private header files. */
40
41#include "defs.h" /* Common definitions */
42#include "emxomf.h" /* Global definitions for emxomf */
43#include "stabshll.h" /* Convert debug information */
44#include "grow.h" /* Growing objects */
45
46/* This header must come after defs.h */
47
48#include <sys/omflib.h> /* Handling OMF libraries */
49
50/* Flag bits for FLAGS field of the struct symbol structure. */
51
52#define SF_FAR16 0x01 /* 16:16 pointer */
53
54/* Length of the weak marker. */
55
56#define SYMBOL_WEAK_LENGTH (3 + 11 + 6)
57
58/* Length of the OMF symbol hash */
59
60#define SYMBOL_HASH_LENGTH (2 + 6)
61
62/* Max OMF symbol length */
63
64#define SYMBOL_MAX_LENGTH (255 - SYMBOL_HASH_LENGTH - SYMBOL_WEAK_LENGTH)
65/* This structure holds additional data for symbols. */
66
67struct symbol
68{
69 int index; /* EXTDEF index */
70 int flags; /* SF_FAR16 */
71 int hll_type; /* HLL type index. */
72};
73
74/* This program keeps OMF symbols (names) in a list of lname
75 structures. */
76
77struct lname
78{
79 struct lname *next; /* Pointer to next element */
80 char *name; /* Name of the symbol */
81 int index; /* OMF index of the symbol */
82};
83
84/* Names of files to be deleted on program termination are stored in a
85 list of delete structures. */
86
87struct delete
88{
89 struct delete *next; /* Pointer to next element */
90 char *name; /* Name of the file to be deleted */
91};
92
93/* This structure holds the information about one class (set) of a.out
94 set elements. Set elements are used for constructors and
95 destructors. These structures are chained in a list. See
96 write_set_data() for details. */
97
98struct set
99{
100 struct set *next; /* Pointer to next class of set elements */
101 char *name; /* Name of the set (the a.out symbol) */
102 int seg_name[3]; /* Name indices of the three segments */
103 int seg_index[3]; /* Segment indices of the three segments */
104 int def; /* Non-zero if head element encountered */
105 int count; /* Number of non-head non-tail elements */
106 dword *data; /* Values of set elements (COUNT elements) */
107 byte *seg; /* Segments of set elements (COUNT elements) */
108};
109
110/* Default library requests (see -i option) are stored in a list of
111 libreq structures. */
112
113struct libreq
114{
115 char *name; /* Name of the default library */
116 struct libreq *next; /* Pointer to next element */
117};
118
119/* This structure describes an OMF-style line number. */
120
121struct line
122{
123 dword addr; /* Start address of the line */
124 int line; /* Line number */
125 int file_index; /* File index */
126};
127
128/* fetch_modstr() caches the string it has retrieved from other
129 modules of the same library. The cache consists of a a linked list
130 of `struct modstr' structures. */
131
132struct modstr
133{
134 struct modstr *next; /* Pointer to next node */
135 char *symbol; /* Symbol attached to the string */
136 char *str; /* The value of the string */
137};
138
139
140/* The number of symbols in the a.out file. */
141int sym_count = 0;
142
143/* The sym_ptr variable points to an array of a.out symbols. There
144 are sym_count table entries. Note that this table is complemented
145 by the sym_more table. */
146const struct nlist *sym_ptr = NULL;
147
148/* The str_ptr variable points to the a.out string table. The
149 elements of sym_ptr contain offsets into this table. The table
150 starts with a 32-bit number. The rest of the table consists of
151 null-terminated strings. */
152const byte *str_ptr = NULL;
153
154/* The text_ptr variable points to the first byte of the text
155 segment. text_size bytes are available at text_ptr. */
156byte *text_ptr = NULL;
157long text_size = 0;
158
159/* The data_ptr variable points to the first byte of the data
160 segment. data_size bytes are available at data_ptr. */
161
162static byte *data_ptr;
163static long data_size;
164
165/* These varibles point to the text and data relocation tables. */
166
167static const struct relocation_info *text_rel;
168static const struct relocation_info *data_rel;
169
170/* Public variables for communication with stabshll.c. */
171
172struct buffer tt = BUFFER_INIT;
173struct buffer sst = BUFFER_INIT;
174struct buffer sst_reloc = BUFFER_INIT;
175struct grow sst_boundary_grow = GROW_INIT;
176struct grow tt_boundary_grow = GROW_INIT;
177int *sst_boundary = NULL;
178int *tt_boundary = NULL;
179/** The HLL version of the HLL debuginfo we're generating.
180 * Default level is 4.
181 *
182 * VisualAge 3.65 iLink support HLL v6
183 * VisualAge 3.08 iLink support HLL v4
184 * Link386 support HLL v3 (?)
185 */
186int hll_version = 4;
187
188/* Private variables. */
189
190/* The name of the current input file. */
191static const char *inp_fname;
192
193/* The name of the current output file. */
194static const char *out_fname = NULL;
195
196/* Use this file name for reporting errors. This is either the name
197 of the input file or a library name plus module name:
198 library(module). */
199static const char *error_fname;
200
201/* The output directory. This is set by the -O option. */
202static const char *output_dir = "";
203
204/* The current input file. */
205static FILE *inp_file;
206
207/* The current output file. */
208static FILE *out_file = NULL;
209
210/* While writing a LIB response file, this variable contains the
211 stream pointer. Otherwise, this variable is NULL. */
212static FILE *response_file = NULL;
213
214/* When creating an OMF library (.lib file), this variable contains
215 the descriptor used by the omflib library. Otherwise, this
216 variable is NULL. */
217static struct omflib *out_lib = NULL;
218
219/* This buffer receives error messages from the omflib library. */
220static char lib_errmsg[512];
221
222/* emxomf reads a complete a.out module into memory. inp_buf points
223 to the buffer holding the current a.out module. This pointer is
224 aliased by sym_ptr etc. */
225static byte *inp_buf;
226
227/* OMF records are constructed in this buffer. The first three bytes
228 are used for the record type and record length. One byte at the
229 end is used for the checksum. */
230static byte out_buf[1+2+MAX_REC_SIZE+1];
231
232/* Index into out_buf (to be more precise: it's a pointer into
233 out_data, which is an alias to out_buf+3) for the next byte of the
234 OMF record. */
235static int out_idx;
236
237/* The list of OMF names. lnames is the head of the list, lname_add
238 is used to add another name to the end of the list. */
239static struct lname *lnames;
240static struct lname **lname_add;
241
242/* The list of sets. sets is the head of the list, set_add is used to
243 add another set to the end of the list. */
244static struct set *sets;
245static struct set **set_add;
246
247/* If this variable is TRUE, an a.out archive is split into several
248 OMF .obj files (-x option). If this variable is FALSE, an a.out
249 archive is converted into an OMF library file. */
250static int opt_x = FALSE;
251
252/* Remove underscores from all symbol names */
253static int opt_rmunder = FALSE;
254
255/* This is the page size for OMF libraries. It is set by the -p
256 option. */
257static int page_size = 0;
258
259/* The index of the next OMF name, used by find_lname(). Name indices
260 are established by LNAMES records written by write_lnames(). */
261static int lname_index;
262
263/* The index of the next segment, used by seg_def() for creating
264 SEGDEF records. */
265static int segdef_index;
266
267/* The index of the next group, used for creating GRPDEF records. */
268static int group_index;
269
270/* The index of the next symbol, used for creating EXTDEF and COMDEF
271 records. */
272static int sym_index;
273
274/* The index of the "WEAK$ZERO" symbol or 0. */
275static int weak_zero_index;
276
277/* OMF name indices: segments, classes, groups, etc. */
278static int ovl_name; /* Overlay name, "" */
279static int text_seg_name; /* Text segment, "TEXT32" */
280static int data_seg_name; /* Data segment, "DATA32" */
281static int udat_seg_name; /* Explicit data segment, see -D */
282static int stack_seg_name; /* Stack segment, "STACK" */
283static int bss_seg_name; /* Uninitialized data segment, "BSS32" */
284static int symbols_seg_name; /* Symbols segment, "$$SYMBOLS" */
285static int types_seg_name; /* Types segment */
286static int code_class_name; /* Code class, "CODE" */
287static int data_class_name; /* Data class, "DATA" */
288static int stack_class_name; /* Stack class, "STACK" */
289static int bss_class_name; /* Uninitialized data class, "BSS" */
290static int debsym_class_name; /* Symbols class, "DEBSYM" */
291static int debtyp_class_name; /* Types class, "DEBTYP" */
292static int flat_group_name; /* FLAT group, "FLAT" */
293static int dgroup_group_name; /* DGROUP group, "DGROUP" or "DATAGROUP" */
294
295/* Segment indices for the TEXT32, DATA32, STACK, BSS32, $$SYMBOLS,
296 $$TYPES and explicit data segments. */
297static int text_index; /* Text segment, TEXT32 */
298static int data_index; /* Data segment, DATA32 */
299static int udat_index; /* Data segment set by -D or same as above */
300static int stack_index; /* Stack segment, STACK */
301static int bss_index; /* Uninitialized data segment, BSS32 */
302static int symbols_index; /* Symbols segment, $$SYMBOLS */
303static int types_index; /* Types segment, $$TYPES */
304
305/* Group indices for the FLAT and DGROUP groups. */
306static int flat_index; /* FLAT group */
307static int dgroup_index; /* DGROUP group */
308
309/* Next FIXUPP thread index to be used for the frame and target
310 thread, respectively. */
311static int frame_thread_index; /* Frame thread */
312static int target_thread_index; /* Target thread */
313
314/* We define target threads for referencing the TEXT32, DATA32 (or the
315 one set by -D) and BSS32 segments and the FLAT group in FIXUPP
316 records. A thread has not been defined if the variable is -1.
317 Otherwise, the value is the thread number. */
318static int text_thread; /* TEXT32 segment */
319static int data_thread; /* Data segment (DATA32 or -D) */
320static int bss_thread; /* BSS32 segment */
321static int flat_thread; /* FLAT group */
322
323/* This variable holds the module name. See get_mod_name(). */
324static char mod_name[256];
325
326/* This variable holds the base(=current) directory. See get_mod_name(). */
327static char base_dir[256];
328
329/* This variable holds the timestamped weak marker for the current module. */
330static char weak_marker[SYMBOL_WEAK_LENGTH + 1];
331
332/* This growing array holds the file name table for generating line
333 number information. */
334static char **file_list;
335static struct grow file_grow;
336
337/* This variable points to the a.out header of the input module. */
338static const struct exec *a_out_h;
339
340/* This table contains additional information for the a.out symbols.
341 Each entry of the sym_ptr table is complemented by an entry of this
342 table. */
343static struct symbol *sym_more;
344
345/* The length of the a.out string table, in bytes. This value
346 includes the 32-bit number at the start of the string table. */
347static long str_size;
348
349/* omflib_write_module() stored the page number of the module to this
350 variable. */
351static word mod_page;
352
353/* This variable is TRUE until we have written the first line to the
354 LIB response file. It is used to suppress the line continuation
355 character `&'. */
356static int response_first = TRUE;
357
358/* This is the list of files to be deleted on program termination.
359 See delete_files(). */
360static struct delete *files_to_delete = NULL;
361
362/* The module type (-l and -m options). It is MT_MODULE unless the -l
363 or -m option is used. */
364static enum {MT_MODULE, MT_MAIN, MT_LIB} mod_type = MT_MODULE;
365
366/* The start (entry point) symbol (-m option). This is NULL unless
367 the -m option (or -l with argument) is used. */
368static char *entry_name = NULL;
369
370/* The name of the identifier manipulation DLL. If this variable is
371 NULL, no IDMDLL record is written. */
372static char *idmdll_name = "INNIDM";
373
374/* the name of the debug packing DLL. This variable is not used when
375 debug info is stripped. If NULL we'll select the default for the
376 linker type (EMXOMFLD_TYPE). */
377static char *dbgpack_name = NULL;
378
379/* If this variable is TRUE (-b option), we always use the 32-bit
380 variant of the OMF records. If this variable is FALSE, we use the
381 16-bit variant whenever possible. This non-documented feature is
382 used for debugging. */
383static int force_big = FALSE;
384
385/* The name of the LIB response file (-r and -R options). This value
386 is NULL unless the -r or -R option is used. */
387static char *response_fname = NULL;
388
389/* When creating a LIB response file, emit commands for replacing
390 modules if this variable is TRUE (-R option). Otherwise, emit
391 commands for adding modules (-r option). */
392static int response_replace;
393
394/* Delete input files after successful conversion if this variable is
395 TRUE (-d option). */
396static int delete_input_files = FALSE;
397
398/* Strip debug information if this variable is TRUE (-s option).
399 Otherwise, convert DBX debugging information to HLL debugging
400 information. */
401static int strip_symbols = FALSE;
402
403/* Print unknown symbol table entries if this variable is TRUE (-u
404 option). */
405static int unknown_stabs = FALSE;
406
407/* Supress certain warnings if this variable is TRUE (-q option). */
408static int quiet = FALSE;
409
410/* The libreq_head variable contains a pointer to the head of the list
411 of default libraries. The -i option is used to add a default
412 library request. The libreq_add pointer is used for appending new
413 elements to the tail of the list. */
414static struct libreq *libreq_head = NULL;
415static struct libreq **libreq_add = &libreq_head;
416
417/* fetch_mod_str() caches the string it has retrieved from other
418 modules of the same library. modstr_cache points to the head of
419 the linked list of `struct modstr' structures. */
420
421static struct modstr *modstr_cache = NULL;
422
423/* Simulate the data array of an OMF record. The data is stored along
424 with the record type (1 byte) and record length (2 bytes) in a
425 single buffer. */
426#define out_data (out_buf+1+2)
427
428/* The data segment name, set by the -D option. If this value is
429 non-NULL, put variables into the named data segment, which isn't a
430 member of DGROUP. */
431
432static char *udat_seg_string = NULL;
433
434/* Prototypes for private functions. */
435
436static void doesn_fit (void) NORETURN2;
437static void usage (void) NORETURN2;
438static int ar_read_header (struct ar_hdr *dst, long pos);
439static long ar_member_size (const struct ar_hdr *p);
440
441
442/* Display an error message on stderr, delete the output file and
443 quit. This function is invoked like printf(): FMT is a
444 printf-style format string, all other arguments are formatted
445 according to FMT. The message should not end with a newline. The
446 exit code is 2. */
447
448void error (const char *fmt, ...)
449{
450 va_list arg_ptr;
451
452 va_start (arg_ptr, fmt);
453 fprintf (stderr, "emxomf: ");
454 vfprintf (stderr, fmt, arg_ptr);
455 va_end (arg_ptr);
456 fputc ('\n', stderr);
457
458 /* If there is an output file, close and delete it. */
459
460 if (out_file != NULL)
461 {
462 fclose (out_file);
463 remove (out_fname);
464 }
465 exit (2);
466}
467
468
469/* Display a warning message on stderr (and do not quit). This
470 function is invoked like printf(): FMT is a printf-style format
471 string, all other arguments are formatted according to FMT. */
472
473void warning (const char *fmt, ...)
474{
475 va_list arg_ptr;
476
477 va_start (arg_ptr, fmt);
478 fprintf (stderr, "emxomf warning: ");
479 vfprintf (stderr, fmt, arg_ptr);
480 va_end (arg_ptr);
481 fputc ('\n', stderr);
482}
483
484
485/* Allocate N bytes of memory. Quit on failure. This function is
486 used like malloc(), but we don't have to check the return value. */
487
488void *xmalloc (size_t n)
489{
490 void *p;
491
492 p = malloc (n);
493 if (p == NULL && n)
494 error ("Out of memory");
495 return p;
496}
497
498
499/* Change the allocation of PTR to N bytes. Quit on failure. This
500 function is used like realloc(), but we don't have to check the
501 return value. */
502
503void *xrealloc (void *ptr, size_t n)
504{
505 void *p;
506
507 p = realloc (ptr, n);
508 if (p == NULL && n)
509 error ("Out of memory");
510 return p;
511}
512
513
514/* Create a duplicate of the string S on the heap. Quit on failure.
515 This function is used like strdup(), but we don't have to check the
516 return value. */
517
518char *xstrdup (const char *s)
519{
520 char *p;
521
522 p = xmalloc (strlen (s) + 1);
523 strcpy (p, s);
524 return p;
525}
526
527
528/* Check if we should remove the leading underscore from a symbol name */
529static inline int strip_underscore (const char *name)
530{
531 if (!opt_rmunder)
532 return 0;
533
534 return (*name == '_');
535}
536
537
538/* Find an a.out symbol. The underscore character `_' is prepended to
539 NAME. On success, a pointer to the symbol table entry (in the
540 array pointed to by sym_ptr) is returned. If the symbol is not
541 found, NULL is returned.
542 NOT_ENTRY is an entry index which is not to be found.
543 FEXT is an indicator on whether or not we can find external symbols or
544 not. */
545const struct nlist *find_symbol_ex (const char *name, int not_entry, int fext)
546{
547 int i, j, n, len, t;
548 const byte *s;
549
550 i = 4; len = strlen (name);
551
552 /* Search the string table for a matching string. */
553 while (i < str_size)
554 {
555 int sym_ofs = i;
556 s = (const byte *)name;
557 if (strip_underscore ((const char *)(str_ptr + i)))
558 ++i;
559 if (memcmp (name, str_ptr+i, len+1) == 0)
560 {
561 /* Search the symbol table for an appropriate entry
562 referencing the string. */
563 n = sym_count;
564 for (j = 0; j < n; ++j)
565 if (sym_ptr[j].n_un.n_strx == sym_ofs && j != not_entry)
566 {
567 t = sym_ptr[j].n_type & ~N_EXT;
568 if ( t == N_TEXT || t == N_DATA || t == N_BSS
569 || (fext && sym_ptr[j].n_type == N_EXT)
570 || (sym_ptr[j].n_type >= N_WEAKA && sym_ptr[j].n_type <= N_WEAKB)
571 || (t == 0 && sym_ptr[j].n_value != 0))
572 return sym_ptr+j;
573 }
574 }
575 i += strlen ((const char *)(str_ptr + i)) + 1;
576 }
577 return NULL; /* Symbol not found */
578}
579
580/* Find an a.out symbol. The underscore character `_' is prepended to
581 NAME. On success, a pointer to the symbol table entry (in the
582 array pointed to by sym_ptr) is returned. If the symbol is not
583 found, NULL is returned. */
584const struct nlist *find_symbol (const char *name)
585{
586 return find_symbol_ex (name, -1, 0);
587}
588
589
590/* Set the hll_type of a symbols. */
591void set_hll_type (int index, int hll_type)
592{
593 if (index > sym_count || index < 0)
594 error ("Internal error! Invalid index (%d) passed to set_hll_type().", index);
595 sym_more[index].hll_type = hll_type;
596}
597
598
599/* Initialize variables for starting a new OMF output file. */
600
601static void init_obj (void)
602{
603 /* Initialize the list of OMF-style names. */
604
605 lnames = NULL; lname_add = &lnames; lname_index = 1;
606
607 /* Initialize segments. */
608
609 segdef_index = 1; sym_index = 1; group_index = 1; weak_zero_index = 0;
610
611 /* Initialize FIXUPP threads. */
612
613 text_thread = -1; data_thread = -1; bss_thread = -1; flat_thread = -1;
614 frame_thread_index = 0; target_thread_index = 0;
615
616 /* Initialize set elements management. */
617
618 sets = NULL; set_add = &sets;
619
620 /* Initialize the buffers used for converting debugging
621 information. */
622
623 buffer_init (&tt);
624 buffer_init (&sst);
625 buffer_init (&sst_reloc);
626
627 /* Init weak markers */
628
629 weak_marker[0] = '\0';
630}
631
632
633/* Find an OMF-style name. If NAME is not yet a known OMF-style name,
634 it is added to the list of OMF-style names. The index of the name
635 is returned. All the OMF-style names will be defined in LNAMES
636 records. Note: INDEX must be assigned sequentially, append to end
637 of list! Otherwise, write_lnames() would have to sort the list */
638
639static int find_lname (const char *name)
640{
641 struct lname *p;
642
643/** @todo: change this to use a stringpool for speed reasons! */
644
645 /* Walk through the list of known OMF-style names. If there is a
646 match, return the index of the name. */
647
648 for (p = lnames; p != NULL; p = p->next)
649 if (strcmp (name, p->name) == 0)
650 return p->index;
651
652 /* The name is not yet known. Create a new entry. */
653
654 p = xmalloc (sizeof (struct lname));
655 p->name = xstrdup (name);
656 p->index = lname_index++;
657
658 /* Add the new entry to the tail of the list of names. */
659
660 p->next = NULL;
661 *lname_add = p;
662 lname_add = &p->next;
663
664 /* Return the index of the new name. */
665
666 return p->index;
667}
668
669
670/* Deallocate the memory used by the list of OMF-style names. */
671
672static void free_lnames (void)
673{
674 struct lname *p, *q;
675
676 for (p = lnames; p != NULL; p = q)
677 {
678 q = p->next;
679 free (p->name);
680 free (p);
681 }
682}
683
684
685/* Start a new OMF record. TYPE is the record type. */
686
687static void init_rec (int type)
688{
689 out_buf[0] = (byte)type;
690 out_idx = 0;
691}
692
693
694/* Write an OMF record. The record type has been defined by
695 init_rec(), the data has been defined by put_8(), put_idx() etc.
696 The checksum is computed by this function. An OMF record has the
697 following format:
698
699 struct omf_record
700 {
701 byte type; The record type
702 word length; The record length, exclusive TYPE and LENGTH
703 byte data[LENGTH-1]; The record data
704 byte checksum; The check sum. The sum of all the bytes in
705 the record is 0 (module 256)
706 };
707
708 If we're writing a LIB file, we call omflib_write_record().
709 Otherwise, we build and write the record here. An OMF record
710 usually contains multiple definitions, see write_lnames() for a
711 simple instance of the loop we use for packing multiple definitions
712 into OMF records. */
713
714static void write_rec (void)
715{
716 byte chksum;
717 int i;
718
719 if (out_lib != NULL)
720 {
721
722 /* Write the record to the library file. */
723
724 if (omflib_write_record (out_lib, out_buf[0], out_idx, out_data,
725 TRUE, lib_errmsg) != 0)
726 error (lib_errmsg);
727 }
728 else
729 {
730
731 /* Store the record length, LSB first. */
732
733 out_buf[1] = (byte)(out_idx+1);
734 out_buf[2] = (byte)((out_idx+1) >> 8);
735
736 /* Compute the check sum. */
737
738 chksum = 0;
739 for (i = 0; i < 1+2+out_idx; ++i)
740 chksum += out_buf[i];
741 out_data[out_idx] = (byte)(256-chksum);
742
743 /* Write the record. */
744
745 if (fwrite (out_buf, 1+2+out_idx+1, 1, out_file) != 1)
746 error ("Write error on output file `%s'", out_fname);
747 }
748}
749
750
751/* This macro yields TRUE iff we can put another X bytes into the
752 current OMF record. */
753
754#define fits(X) (out_idx + (X) <= MAX_REC_SIZE-4)
755
756/* This function is called if we try to build too big an OMF record.
757 This cannot happen unless there is a bug in this program. Display
758 an error message and quit. */
759
760static void doesn_fit (void)
761{
762 error ("Record too long");
763}
764
765
766/* Calculates the hash for a string using the original djb2 aglorithm. */
767
768static unsigned hash_string(const char *pch, size_t cch)
769{
770 unsigned uHash;
771 for (uHash = 5381; cch > 0; pch++, cch--)
772 uHash += (uHash << 5) + *pch;
773 return uHash;
774}
775
776/* Formats a 64-bit number with a fixed with. The purpose is to encode
777 a unique number as tiny as possible while keeping within what any
778 linker should accept. The width is fixed, and the string is clipped
779 or padded with zeros to satisfy that. The return value is psz + cchWidth. */
780
781static char *format_u64(uint64_t u64, char *psz, unsigned uRadix, int cchWidth)
782{
783 static const char s_achDigits[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
784 static const unsigned s_cchDigits = sizeof(s_achDigits) / sizeof(s_achDigits[0]) - 1;
785 assert(uRadix <= s_cchDigits);
786 while (cchWidth-- > 0)
787 {
788 unsigned i = u64 % uRadix;
789 *psz++ = s_achDigits[i];
790 u64 /= uRadix;
791 }
792 assert(!u64);
793 *psz = '\0';
794 return psz;
795}
796
797
798
799
800
801/* Put the string pszName into the current OMF record.
802 In the OMF record, the string is preceded by a length byte. The
803 string length must not exceed 255; if it is too long, display a
804 warning and truncate the string. Moreover, there must be enough
805 space left in the OMF record; if there isn't, display an error
806 message and abort. */
807
808static void put_nstr(const char *pszName, size_t cch)
809{
810 if ( cch > SYMBOL_MAX_LENGTH
811 && !strstr(pszName + SYMBOL_MAX_LENGTH - SYMBOL_WEAK_LENGTH, "$w$"))
812 {
813 /* Hash the symbol to help making it unique.
814 * NOTE that the hash algorithm is not fixed, so is the !_%X marker too.
815 * the weakld is parsing it!
816 */
817 unsigned uHash = hash_string(pszName, cch);
818 char szHash[SYMBOL_HASH_LENGTH + 1];
819 char *psz;
820 szHash[0] = '!';
821 szHash[1] = '_';
822 psz = format_u64((uint32_t)uHash, &szHash[2], 62, 6);
823 assert(psz - &szHash[0] == SYMBOL_HASH_LENGTH);
824
825 if (!fits(1 + SYMBOL_MAX_LENGTH + SYMBOL_HASH_LENGTH))
826 doesn_fit();
827 out_data[out_idx++] = SYMBOL_MAX_LENGTH + SYMBOL_HASH_LENGTH;
828 memcpy(out_data + out_idx, pszName, SYMBOL_MAX_LENGTH);
829 out_idx += SYMBOL_MAX_LENGTH;
830 memcpy(out_data + out_idx, szHash, SYMBOL_HASH_LENGTH);
831 out_idx += SYMBOL_HASH_LENGTH;
832
833 warning ("Truncated symbol '%.*s' to '%.*s%s'", cch, pszName, SYMBOL_MAX_LENGTH, pszName, szHash);
834 }
835 else
836 {
837 if (!fits(1+cch))
838 doesn_fit();
839 out_data[out_idx++] = (byte)cch;
840 memcpy(out_data+out_idx, pszName, cch);
841 out_idx += cch;
842 }
843}
844
845/* Put the null-terminated string pszName into the current OMF record.
846 See put_nstr() for full details on string handling. */
847
848static inline void put_str(const char *pszName)
849{
850 put_nstr(pszName, strlen(pszName));
851}
852
853
854/* Put the symbol SRC, a null-terminated string, into the current OMF
855 record. If SRC starts with the underscore character `_', that
856 character is skipped. This is where the leading underscore
857 character of a.out symbols is removed. C modules for emx.dll are
858 treated specially here: The leading underscore is not removed
859 unless the name looks like the name of an OS/2 API function. The
860 symbol length (after removing the leading underscore) must not
861 exceed 255 characters. There must be enough space left in the OMF
862 record. If these conditions are not met, display an error message
863 and quit. */
864
865static void put_sym (const char *src)
866{
867 if (strip_underscore (src))
868 ++src;
869 put_str (src);
870}
871
872/* Put an 8-bit byte into the current OMF record. This macro does not
873 test for buffer / record overflow. */
874
875#define put_8(x) out_data[out_idx++] = (byte)(x)
876
877/* Put a 16-bit word (least significant byte first) into the current
878 OMF record. If there is not enough space left in the OMF record,
879 display an error message and quit. */
880
881static void put_16 (int x)
882{
883 if (!fits (2))
884 doesn_fit ();
885 out_data[out_idx++] = (byte)x;
886 out_data[out_idx++] = (byte)(x >> 8);
887}
888
889
890/* Put a 24-bit word (least significant byte first) into the current
891 OMF record. If there is not enough space left in the OMF record,
892 display an error message and quit. */
893
894static void put_24 (long x)
895{
896 if (!fits (3))
897 doesn_fit ();
898 out_data[out_idx++] = (byte)x;
899 out_data[out_idx++] = (byte)(x >> 8);
900 out_data[out_idx++] = (byte)(x >> 16);
901}
902
903
904/* Put a 32-bit word (least significant byte first) into the current
905 OMF record. If there is not enough space left in the OMF record,
906 display an error message and quit. */
907
908static void put_32 (long x)
909{
910 if (!fits (4))
911 doesn_fit ();
912 out_data[out_idx++] = (byte)x;
913 out_data[out_idx++] = (byte)(x >> 8);
914 out_data[out_idx++] = (byte)(x >> 16);
915 out_data[out_idx++] = (byte)(x >> 24);
916}
917
918
919/* Put the index X into the current OMF record. Indices are used for
920 identifying names (LNAMES), segments (SEGDEF), groups (GRPDEF)
921 etc. Indices are stored in one or two bytes, depending on the
922 value. Small indices (0 through 127) are stored as single byte.
923 Large indices (128 through 32767) are stored as two bytes: the
924 high-order byte comes first, with bit 7 set; the low-order byte
925 comes next. If there is not enough space left in the OMF record or
926 if the value exceeds 32767, display an error message and quit. */
927
928static void put_idx (int x)
929{
930 if (x <= 0x7f)
931 {
932 if (!fits (1))
933 doesn_fit ();
934 out_data[out_idx++] = (byte)x;
935 }
936 else if (x <=0x7fff)
937 {
938 if (!fits (2))
939 doesn_fit ();
940 out_data[out_idx++] = (byte)((x >> 8) | 0x80);
941 out_data[out_idx++] = (byte)x;
942 }
943 else
944 error ("Index too large");
945}
946
947
948/* Put SIZE bytes from SRC into the current OMF record. If there is
949 not enough space left in the OMF record, display an error message
950 and quit. */
951
952static void put_mem (const void *src, int size)
953{
954 if (!fits (size))
955 doesn_fit ();
956 memcpy (out_data+out_idx, src, size);
957 out_idx += size;
958}
959
960
961/* Write LNAMES records into the output file for defining all the
962 names stored in the LNAMES list.
963
964 LNAMES record:
965 Ú
966 ³1 String length n
967 ³n Name
968 À
969
970 Name indices are assigned sequentially. */
971
972static void write_lnames (void)
973{
974 const struct lname *p;
975 int started;
976
977 started = FALSE;
978 for (p = lnames; p != NULL; p = p->next)
979 {
980 if (started && !fits (strlen (p->name)+1))
981 {
982 write_rec ();
983 started = FALSE;
984 }
985 if (!started)
986 {
987 init_rec (LNAMES);
988 started = TRUE;
989 }
990 put_str (p->name);
991 }
992 if (started)
993 write_rec ();
994}
995
996
997/* Add a string to the current EXTDEF record or start a new EXTDEF
998 record. PSTARTED points to an object keeping state. */
999
1000static void add_extdef (int *pstarted, const char *name, int type)
1001{
1002 if (*pstarted)
1003 {
1004 size_t cchEncodedName = strlen(name);
1005 if ( cchEncodedName > SYMBOL_MAX_LENGTH
1006 && !strstr(name + SYMBOL_MAX_LENGTH - SYMBOL_WEAK_LENGTH, "$w$"))
1007 cchEncodedName = SYMBOL_MAX_LENGTH + SYMBOL_HASH_LENGTH;
1008 if (!fits(cchEncodedName + 3 + (type > 127)))
1009 {
1010 write_rec();
1011 *pstarted = FALSE;
1012 }
1013 }
1014 if (!*pstarted)
1015 {
1016 init_rec(EXTDEF);
1017 *pstarted = TRUE;
1018 }
1019 put_sym(name);
1020 put_idx(type); /* type index */
1021}
1022
1023
1024/* Write EXTDEF records into the output file for all the external
1025 symbols stored in the sym_ptr array.
1026
1027 EXTDEF record:
1028 Ú
1029 ³1 String length n
1030 ³n External name
1031 ³1-2 Type index
1032 À
1033
1034 Symbol indices are assigned sequentially. */
1035
1036static void write_extdef (void)
1037{
1038 const char *name;
1039 int i, started;
1040
1041 started = FALSE;
1042 for (i = 0; i < sym_count; ++i)
1043 if (sym_ptr[i].n_type == (N_INDR|N_EXT))
1044 ++i; /* Skip immediately following entry */
1045 else if (sym_ptr[i].n_type == N_EXT && sym_ptr[i].n_value == 0)
1046 {
1047 name = (const char *)(str_ptr + sym_ptr[i].n_un.n_strx);
1048 sym_more[i].index = sym_index++;
1049 if (memcmp (name, "_16_", 4) == 0)
1050 sym_more[i].flags |= SF_FAR16;
1051 add_extdef (&started, name, sym_more[i].hll_type);
1052 }
1053 else if (sym_ptr[i].n_type == N_WEAKU)
1054 {
1055 if (weak_zero_index == 0)
1056 {
1057 weak_zero_index = sym_index++;
1058 add_extdef (&started, "WEAK$ZERO", 0);
1059 }
1060 sym_more[i].index = sym_index++;
1061 add_extdef (&started, (const char *)(str_ptr + sym_ptr[i].n_un.n_strx), sym_more[i].hll_type);
1062 }
1063#if 1 /* this isn't actually required if only the assembler could do what it's supposed to... */
1064 else if (sym_ptr[i].n_type >= N_WEAKA && sym_ptr[i].n_type <= N_WEAKB)
1065 { /* Not convinced about this yet, I mean there should really be
1066 external records for this, perhaps...
1067 At least I can't see why this will be wrong. */
1068 name = (const char *)(str_ptr + sym_ptr[i].n_un.n_strx);
1069 sym_more[i].index = sym_index++;
1070 add_extdef (&started, name, sym_more[i].hll_type);
1071 }
1072#endif
1073 if (started)
1074 write_rec ();
1075}
1076
1077/* Write WKEXT records into the output file for all undefined weak
1078 symbols stored in the sym_ptr array.
1079
1080 WKEXT record:
1081 Ú
1082 ³1-2 weak EXTDEF index
1083 ³1-2 default resolution EXTDEF index
1084 À
1085
1086 */
1087
1088static void write_wkext (void)
1089{
1090 int i;
1091
1092 for (i = 0; i < sym_count; ++i)
1093 if (sym_ptr[i].n_type == (N_INDR|N_EXT))
1094 ++i; /* Skip immediately following entry */
1095 else if (sym_ptr[i].n_type == N_WEAKU)
1096 {
1097 init_rec (COMENT);
1098 put_8 (0x80);
1099 put_8 (CLASS_WKEXT);
1100 put_idx (sym_more[i].index);
1101 put_idx (weak_zero_index);
1102 write_rec ();
1103 }
1104}
1105
1106
1107/**
1108 * Generates new names for weak symbols.
1109 *
1110 * These names will be catch bye emxomfld and an alias from the generated to
1111 * the real name will be generated and put in a library before linking.
1112 *
1113 * @returns Pointer to pszOrgName or pszName.
1114 * @param pSym Pointer to the symbol in question.
1115 * @param pszOrgName Pointer to the symbols actual name.
1116 * @param pachName Pointer to a character buffer of size cchName where the
1117 * new name will be written.
1118 * @param cchName Size of the buffer pointed to by pachName.
1119 * This must be at least 256, the code make this assumption!
1120 * @remark I'm sorry this function is written in my coding style - not!
1121 */
1122static const char *weak_process_name(const struct nlist *pSym, const char *pszOrgName, char *pachName, int cchName)
1123{
1124 switch (pSym->n_type)
1125 {
1126 /*
1127 * Weak external.
1128 */
1129 case N_WEAKU: /* 0x0d Weak undefined symbol. */
1130 default:
1131 break;
1132
1133 /*
1134 * These symbols are defined in this module, so we need to
1135 * make a unique and recognizable name for them.
1136 */
1137 case N_WEAKA: /* 0x0e Weak absolute symbol. */
1138 case N_WEAKT: /* 0x0f Weak text symbol. */
1139 case N_WEAKD: /* 0x10 Weak data symbol. */
1140 case N_WEAKB: /* 0x11 Weak bss symbol. */
1141 {
1142 int cch;
1143
1144 /* Init the weak marker if it hasn't already been done for this module. */
1145 if (!weak_marker[0])
1146 {
1147 struct timeval tv = {0, 0};
1148 uint64_t u64;
1149 char *psz;
1150
1151 /* prefix */
1152 psz = (char *)memcpy(&weak_marker[0], "$w$", sizeof("$w$")) + sizeof("$w$") - 1;
1153
1154 /* use time-of-day + 4 random bits for the 11 char value */
1155 gettimeofday(&tv, NULL);
1156 u64 = (uint64_t)tv.tv_sec * 1000000 + tv.tv_usec;
1157 u64 <<= 12;
1158 u64 |= rand() & 0xfff;
1159 psz = format_u64(u64, psz, 62, 11);
1160
1161 /* simply hash the current filename for the next 6 chars value. */
1162 u64 = hash_string(mod_name, strlen(mod_name));
1163 psz = format_u64((uint32_t)u64, psz, 62, 6);
1164 assert((psz - &weak_marker[0]) == SYMBOL_WEAK_LENGTH);
1165 }
1166
1167
1168 /* generate the weak symbol name. */
1169 cch = strlen(pszOrgName);
1170 if (cch <= SYMBOL_MAX_LENGTH) /* Must cut exactly where add_nstr cuts. */
1171 snprintf(pachName, cchName, "%s%s", pszOrgName, weak_marker);
1172 else
1173 { /* too long. truncate to: name+!_[hash]$w$[weakmarker] */
1174 uint32_t u32Hash = hash_string(pszOrgName, cch);
1175 memcpy(pachName, pszOrgName, SYMBOL_MAX_LENGTH);
1176 pachName[SYMBOL_MAX_LENGTH + 0] = '!';
1177 pachName[SYMBOL_MAX_LENGTH + 1] = '_';
1178 format_u64(u32Hash, &pachName[SYMBOL_MAX_LENGTH + 2], 62, 6);
1179 memcpy(&pachName[SYMBOL_MAX_LENGTH + SYMBOL_HASH_LENGTH], weak_marker, SYMBOL_WEAK_LENGTH + 1);
1180 warning("Truncated symbol '%s' to '%s' (weak)", pszOrgName, pachName);
1181 }
1182
1183 return pachName;
1184 }
1185
1186 }
1187 /* default is to keep the original name */
1188 return pszOrgName;
1189}
1190
1191
1192
1193/* Write ALIAS records into the output file for all indirect references. */
1194
1195static void write_alias (void)
1196{
1197 int i;
1198 const char *pub_name;
1199
1200 for (i = 0; i < sym_count - 1; ++i)
1201 if (sym_ptr[i].n_type == (N_INDR|N_EXT) && sym_ptr[i+1].n_type == N_EXT)
1202 {
1203 init_rec (ALIAS);
1204 put_sym ((const char *)(str_ptr + sym_ptr[i].n_un.n_strx));
1205 put_sym ((const char *)(str_ptr + sym_ptr[i+1].n_un.n_strx));
1206 write_rec ();
1207
1208 if (out_lib != NULL)
1209 {
1210 pub_name = (const char *)(str_ptr + sym_ptr[i].n_un.n_strx);
1211 if (strip_underscore (pub_name))
1212 ++pub_name;
1213 if (omflib_add_pub (out_lib, pub_name, mod_page, lib_errmsg) != 0)
1214 error (lib_errmsg);
1215 }
1216 }
1217}
1218
1219
1220/* Write PUBDEF records into the output file for the public symbols of
1221 the a.out-style symbol type TYPE. Symbols of that type are defined
1222 in the segment having the OMF segment index INDEX. Ignore symbols
1223 not fitting into a 16-bit PUBDEF record if BIG is FALSE. Ignore
1224 symbols fitting into a 16-bit PUBDEF record if BIG is TRUE. START
1225 is the virtual start address of the segment in the a.out file.
1226
1227 PUBDEF record:
1228 1-2 Base group
1229 1-2 Base segment
1230 0/2 Base frame
1231 Ú
1232 ³1 String length n
1233 ³n Public name
1234 ³2/4 Public offset (4 bytes for 32-bit PUBDEF record)
1235 ³1-2 Type index
1236 À
1237
1238 The base frame field is present only if the base segment field is
1239 0. */
1240
1241static void write_pubdef1 (int type, int index, int big, dword start)
1242{
1243 int i, started;
1244 const char *name, *pub_name;
1245 dword address;
1246 char szName[256];
1247
1248 started = FALSE;
1249 for (i = 0; i < sym_count; ++i)
1250 if ( sym_ptr[i].n_type == type
1251 || ((type < N_WEAKU || type > N_WEAKB) && (sym_ptr[i].n_type & ~N_EXT) == type)
1252 )
1253 {
1254 address = sym_ptr[i].n_value - start;
1255 if ((address >= 0x10000 || force_big) == big)
1256 {
1257 name = (const char *)(str_ptr + sym_ptr[i].n_un.n_strx);
1258 if ( (sym_ptr[i].n_type & N_EXT)
1259 || (type == N_TEXT && strncmp (name, "___POST$", 8) == 0)
1260 || (sym_ptr[i].n_type >= N_WEAKU && sym_ptr[i].n_type <= N_WEAKB) )
1261 {
1262 /* for weaksymbols we may have to decorate the name */
1263 if ( sym_ptr[i].n_type >= N_WEAKU && sym_ptr[i].n_type <= N_WEAKB )
1264 name = weak_process_name(&sym_ptr[i], name, szName, sizeof(szName));
1265
1266 if ( out_lib != NULL
1267 && ( ( (sym_ptr[i].n_type & N_EXT)
1268 && sym_ptr[i].n_type != N_WEAKB
1269 && sym_ptr[i].n_type != N_WEAKU)
1270 || sym_ptr[i].n_type == N_WEAKT
1271 || sym_ptr[i].n_type == N_WEAKD ) )
1272 {
1273 pub_name = name;
1274 if (strip_underscore (pub_name))
1275 ++pub_name;
1276 if (omflib_add_pub (out_lib, pub_name, mod_page,
1277 lib_errmsg) != 0)
1278 error (lib_errmsg);
1279 }
1280
1281 if (started && !fits (strlen (name) + 6 + (sym_more[i].hll_type > 127)))
1282 {
1283 write_rec ();
1284 started = FALSE;
1285 }
1286 if (!started)
1287 {
1288 init_rec (big ? PUBDEF|REC32 : PUBDEF);
1289 put_idx (flat_index);
1290 put_idx (index);
1291 if (!index)
1292 put_16 (0);
1293 started = TRUE;
1294 }
1295 put_sym (name);
1296 if (big)
1297 put_32 (address);
1298 else
1299 put_16 (address);
1300 put_idx (sym_more[i].hll_type); /* type index */
1301 }
1302 }
1303 }
1304 if (started)
1305 write_rec ();
1306}
1307
1308/* Write main alias if _main is a pubdef.
1309 The debugger looks for 'main' not '_main' in the symbol table. */
1310static void write_pubdef_main ()
1311{
1312 int i;
1313
1314 if (opt_rmunder || strip_symbols || !a_out_h->a_syms)
1315 return;
1316
1317 for (i = 0; i < sym_count; ++i)
1318 if ((sym_ptr[i].n_type & ~N_EXT) == N_TEXT)
1319 {
1320 const char * name = (const char *)(str_ptr + sym_ptr[i].n_un.n_strx);
1321 dword address = sym_ptr[i].n_value;
1322 if ( (sym_ptr[i].n_type & N_EXT)
1323 && !strcmp(name, "_main"))
1324 {
1325 int big = ((address >= 0x10000 || force_big) == big);
1326
1327 name++; /* skip the underscore */
1328 if (out_lib != NULL)
1329 {
1330 if (omflib_add_pub (out_lib, name, mod_page, lib_errmsg) != 0)
1331 error (lib_errmsg);
1332 }
1333 init_rec (big ? PUBDEF|REC32 : PUBDEF);
1334 put_idx (flat_index);
1335 put_idx (text_index);
1336 put_sym (name);
1337 if (big)
1338 put_32 (address);
1339 else
1340 put_16 (address);
1341 put_idx (sym_more[i].hll_type); /* type index */
1342 write_rec ();
1343 break;
1344 }
1345 }
1346}
1347
1348/* Write PUBDEF records into the output file for all the public N_TEXT
1349 and N_DATA symbols stored in the sym_ptr array. Common symbols are
1350 handled by write_comdef() below. */
1351
1352static void write_pubdef (void)
1353{
1354 write_pubdef1 (N_ABS, 0, FALSE, 0);
1355 write_pubdef1 (N_ABS, 0, TRUE, 0);
1356 write_pubdef1 (N_TEXT, text_index, FALSE, 0);
1357 write_pubdef1 (N_TEXT, text_index, TRUE, 0);
1358 write_pubdef1 (N_DATA, udat_index, FALSE, text_size);
1359 write_pubdef1 (N_DATA, udat_index, TRUE, text_size);
1360 write_pubdef1 (N_BSS, bss_index, FALSE, text_size + data_size);
1361 write_pubdef1 (N_BSS, bss_index, TRUE, text_size + data_size);
1362 write_pubdef1 (N_WEAKA, 0, FALSE, 0);
1363 write_pubdef1 (N_WEAKA, 0, TRUE, 0);
1364 write_pubdef1 (N_WEAKT, text_index, FALSE, 0);
1365 write_pubdef1 (N_WEAKT, text_index, TRUE, 0);
1366 write_pubdef1 (N_WEAKD, udat_index, FALSE, text_size);
1367 write_pubdef1 (N_WEAKD, udat_index, TRUE, text_size);
1368 write_pubdef1 (N_WEAKB, bss_index, FALSE, text_size + data_size);
1369 write_pubdef1 (N_WEAKB, bss_index, TRUE, text_size + data_size);
1370 /* kso #456 2003-06-10: The debugger looks for 'main' not '_main'. */
1371 write_pubdef_main ();
1372}
1373
1374
1375/* Write COMDEF records into the output file for all the common
1376 symbols stored in the sym_ptr array. Common symbols are used for
1377 uninitialized variables. The TYPE field of these symbols is 0
1378 (plus N_EXT) and the VALUE field is non-zero (it is the size of the
1379 variable).
1380
1381 COMDEF record:
1382 Ú
1383 ³1 String length n
1384 ³n Communal name
1385 ³1-2 Type index
1386 ³1 Data type (0x61: FAR data, 0x62: NEAR data)
1387 ³1-5 Communal length
1388 À
1389
1390 The length is encoded in 1 to 5 bytes, depending on the value:
1391
1392 0 through 0x7f 1 byte, containing the value
1393 0 through 0xffff 0x81, followed by 16-bit word
1394 0 through 0xffffff 0x84, followed by 24-bit word
1395 0 through 0xffffffff 0x88, followed by 32-bit word */
1396
1397static void write_comdef (void)
1398{
1399 int i, started;
1400 long size;
1401 const char *name;
1402
1403 started = FALSE;
1404 for (i = 0; i < sym_count; ++i)
1405 if (sym_ptr[i].n_type == (N_INDR|N_EXT))
1406 ++i; /* Skip immediately following entry */
1407 else if (sym_ptr[i].n_type == N_EXT && sym_ptr[i].n_value != 0)
1408 {
1409 name = (const char *)(str_ptr + sym_ptr[i].n_un.n_strx);
1410 sym_more[i].index = sym_index++;
1411 if (memcmp (name, "_16_", 4) == 0)
1412 sym_more[i].flags |= SF_FAR16;
1413 size = sym_ptr[i].n_value;
1414 if (started && !fits (strlen (name) + 12))
1415 {
1416 write_rec ();
1417 started = FALSE;
1418 }
1419 if (!started)
1420 {
1421 init_rec (COMDEF);
1422 started = TRUE;
1423 }
1424 put_sym (name);
1425 put_idx (0); /* Type index */
1426 put_8 (0x62); /* Data type */
1427 if (size < 4)
1428 size = 4; /* VAC308 ilink freaks out if size = 1 or something */
1429 if (size < 0x80)
1430 put_8 (size);
1431 else if (size < 0x10000)
1432 {
1433 put_8 (0x81);
1434 put_16 (size);
1435 }
1436 else if (size < 0x1000000)
1437 {
1438 put_8 (0x84);
1439 put_24 (size);
1440 }
1441 else
1442 {
1443 put_8 (0x88);
1444 put_32 (size);
1445 }
1446 }
1447 if (started)
1448 write_rec ();
1449}
1450
1451
1452/* Write a SEGDEF record to define a segment. NAME_INDEX is the name
1453 index of the segment name. CLASS_INDEX is the name index of the
1454 class name. SIZE is the size of the segment in bytes. STACK is
1455 TRUE iff the segment is the stack segment. seg_def() returns the
1456 segment index of the new segment.
1457
1458 SEGDEF record:
1459 1 Segment attributes
1460 0/2 Frame number (present only if A=000)
1461 0/1 Offset (present only if A=000)
1462 2/4 Segment length (4 bytes for 32-bit SEGDEF record)
1463 1/2 Segment name index
1464 1/2 Segment class index
1465 1/2 Overlay name index
1466
1467 The segment attributes byte contains the following fields:
1468
1469 A (bits 5-7) Alignment (011=relocatable, paragraph (16b) alignment)
1470 (before gcc 3.2.2: 101=relocatable, 32-bit alignment)
1471 C (bits 2-4) Combination (010=PUBLIC, 101=STACK)
1472 B (bit 1) Big (segment length is 64KB)
1473 P (bit 0) USE32 */
1474
1475static int seg_def (int name_index, int class_index, long size, int stack, int is_set)
1476{
1477 byte seg_attr;
1478
1479 seg_attr = (is_set ? (stack ? 0xb5 : 0xa9) : (stack ? 0x75 : 0x69) );
1480 if (size > 0x10000 || force_big)
1481 {
1482 init_rec (SEGDEF|REC32);
1483 put_8 (seg_attr);
1484 put_32 (size);
1485 }
1486 else if (size == 0x10000)
1487 {
1488 init_rec (SEGDEF);
1489 put_8 (seg_attr|2);
1490 put_16 (0);
1491 }
1492 else
1493 {
1494 init_rec (SEGDEF);
1495 put_8 (seg_attr);
1496 put_16 (size);
1497 }
1498 put_idx (name_index);
1499 put_idx (class_index);
1500 put_idx (ovl_name);
1501 write_rec ();
1502 return segdef_index++;
1503}
1504
1505
1506/* This function is passed to qsort() for sorting a relocation table.
1507 X1 and X2 point to reloc structures. We compare the ADDRESS fields
1508 of the structures. */
1509
1510static int reloc_compare (const void *x1, const void *x2)
1511{
1512 dword a1, a2;
1513
1514 a1 = ((struct relocation_info *)x1)->r_address;
1515 a2 = ((struct relocation_info *)x2)->r_address;
1516 if (a1 < a2)
1517 return -1;
1518 else if (a1 > a2)
1519 return 1;
1520 else
1521 return 0;
1522}
1523
1524
1525/* Write the segment contents (data) of one OMF segment to the output
1526 file. Create LEDATA and FIXUPP records. INDEX is the segment
1527 index. SEG_NAME is the name index of the segment name (not used).
1528 SRC points to the data to be written (will be modified for
1529 fixups!), SEG_SIZE is the number of bytes to be written. REL
1530 points to the relocation table (an array of struct relocation_info), REL_SIZE
1531 is the size of the relocation table, in bytes(!). SST_FLAG is TRUE
1532 when writing the symbol segment $$SYMBOLS. BOUNDARY points to an
1533 array of indices into SRC where the data can be split between
1534 records. That array has BOUNDARY_COUNT entries. SEG_TYPE is the
1535 segment type (N_TEXT or N_DATA or -1) and is used for relocation.
1536
1537 We can split the data at arbitrary points after the last BOUNDARY
1538 entry. In consequence, write_seg() splits the data at arbitrary
1539 points if BOUNDARY_COUNT is zero.
1540
1541 LEDATA record:
1542 1-2 Segment index
1543 2/4 Enumerated data offset (4 bytes for 32-bit LEDATA record)
1544 n Data bytes (n is derived from record length)
1545
1546 FIXUPP record:
1547 Ú
1548 ³? THREAD subrecord or FIXUP subrecord
1549 À
1550
1551 THREAD subrecord:
1552 1 Flags
1553 0-2 Index (present only for FRAME methods F0, F1 and F2)
1554
1555 The flags byte contains the following fields:
1556
1557 0 (bit 7) always 0 to indicate THREAD subrecord
1558 D (bit 6) 0=target thread, 1=frame thread
1559 0 (bit 5) reserved
1560 Method (bits 2-4) method (T0 through T6 and F0 through F6)
1561 Thred (bits 0-1) thread number
1562
1563 FIXUP subrecord:
1564 2 Locat
1565 0-1 Fix data
1566 0-2 Frame datum
1567 0-2 Target datum
1568 2/4 target displacement (4 bytes for 32-bit FIXUPP record)
1569
1570 The first locat byte contains the following fields:
1571
1572 1 (bit 7) always 1 to indicate FIXUP subrecord
1573 M (bit 6) 1=segment-relative fixup, 0=self-relative fixup
1574 Location (bit 2-5) Type of location to fix up:
1575 0010=16-bit selector
1576 0011=32-bit long pointer (16:16)
1577 1001=32-bit offset
1578 Offset (bits 0-1) Most significant bits of offset into LEDATA record
1579
1580 The second locat byte contains the least significant bits of the
1581 offset into the LEDATA record.
1582
1583 The Fix data byte contains the following fields:
1584
1585 F (bit 7) 1=frame thread, 0=methods F0 through F5
1586 Frame (bits 4-6) frame thread number (F=1) or frame method (F=0)
1587 T (bit 3) 1=target thread, 1=methods
1588 P (bit 2) Bit 2 of target method
1589 Targt (bits 0-1) target thread number (T=1) or target method (T=0) */
1590
1591static void write_seg (int index, int seg_name, byte *src, long seg_size,
1592 const struct relocation_info *rel, long rel_size, int sst_flag,
1593 const int *boundary, int boundary_count, int seg_type)
1594{
1595 long n, off, tmp, end;
1596 int i, reloc_count, reloc_idx, target_index, ok, data_off, far16;
1597 int boundary_idx, started, *threadp;
1598 struct relocation_info *reloc_tab;
1599 const struct relocation_info *r;
1600 byte locat;
1601 dword start_data, start_bss;
1602
1603 target_index = 0; threadp = NULL; /* keep the compiler happy */
1604
1605 /* Copy and sort the relocation table. */
1606
1607 reloc_count = rel_size / sizeof (struct relocation_info);
1608 reloc_tab = xmalloc (reloc_count * sizeof (struct relocation_info));
1609 memcpy (reloc_tab, rel, reloc_count * sizeof (struct relocation_info));
1610 qsort (reloc_tab, reloc_count, sizeof (struct relocation_info), reloc_compare);
1611
1612 /* First pass: apply fixups to data. Adjust fixup frames for OMF
1613 fixups. In a.out files, frames are relative to address 0, in OMF
1614 files, frames are relative to the start of the segment. The
1615 following two variables are used for doing these adjustments. */
1616
1617 start_data = text_size;
1618 start_bss = start_data + data_size;
1619
1620 /* Scan the relocation table for entries applying to this segment. */
1621
1622 for (i = 0, r = reloc_tab; i < reloc_count; ++i, ++r)
1623 if (r->r_length == 2)
1624 {
1625
1626 /* Here we have a 32-bit relocation. */
1627
1628 if (r->r_extern)
1629 {
1630
1631 /* The relocation refers to a symbol. Look into the
1632 symbol table to find the fixup type and target
1633 address. */
1634 const struct nlist *sym = &sym_ptr[r->r_symbolnum];
1635/*#ifdef DEBUG
1636 const char *psz = sym->n_un.n_strx + str_ptr;
1637#endif*/
1638 switch (sym->n_type)
1639 {
1640 case N_TEXT:
1641 case N_WEAKD:
1642 case N_WEAKB:
1643 case N_WEAKA:
1644 break;
1645
1646 case N_EXT:
1647 case N_WEAKU:
1648 case N_TEXT|N_EXT:
1649 case N_WEAKT:
1650 if (r->r_pcrel)
1651 { /* example: r_address = 0xc, dw=0xfffffff6. disp=6 */
1652 dword dw = *(dword *)(src + r->r_address);
1653 dw += r->r_address + 4;
1654 *(dword *)(src + r->r_address) = dw;
1655 }
1656 break;
1657 case N_DATA:
1658 case N_DATA|N_EXT:
1659 *(dword *)(src + r->r_address) -= start_data;
1660 break;
1661 case N_BSS:
1662 case N_BSS|N_EXT:
1663 *(dword *)(src + r->r_address) -= start_bss;
1664 break;
1665
1666 default:
1667 error ("write_seg: Invalid symbol type (0x%.2x)",
1668 sym_ptr[r->r_symbolnum].n_type);
1669 }
1670 }
1671 else if (!(r->r_pcrel && (r->r_symbolnum & ~N_EXT) == seg_type))
1672 {
1673
1674 /* The relocation does not refer to a symbol, it's an
1675 internal relocation. Get the fixup type from the
1676 relocation table. */
1677
1678 switch (r->r_symbolnum & ~N_EXT)
1679 {
1680 /* kso #465 2003-06-04: WEAK hack - bogus */
1681 case N_WEAKT:
1682 case N_TEXT:
1683 break;
1684 /* kso #465 2003-06-04: WEAK hack - bogus */
1685 case N_WEAKD:
1686 case N_DATA:
1687 *(dword *)(src + r->r_address) -= start_data;
1688 break;
1689 /* kso #465 2003-06-04: WEAK hack - bogus */
1690 case N_WEAKB:
1691 case N_BSS:
1692 *(dword *)(src + r->r_address) -= start_bss;
1693 break;
1694 /* kso #465 2003-06-04: WEAK hack - bogus */
1695 case N_WEAKA:
1696 break;
1697 default:
1698 error ("write_seg: Invalid relocation type (0x%.2x)", r->r_symbolnum);
1699 }
1700 }
1701 }
1702
1703 /* Second pass: write LEDATA and FIXUPP records. */
1704
1705 off = 0; reloc_idx = 0; boundary_idx = 0;
1706 while (seg_size > 0)
1707 {
1708
1709 /* Compute the maximum number of bytes in the next LEDATA
1710 record, depending on the maximum record size, the record type
1711 (16-bit or 32-bit) and the number of bytes remaining. The
1712 number of bytes will be adjusted later to avoid splitting
1713 entries of the $$SYMBOLS and $$TYPES segments. */
1714
1715 n = MAX_REC_SIZE - 5;
1716 n -= (off >= 0x10000 || force_big ? 4 : 2);
1717 if (seg_size < n)
1718 n = seg_size;
1719
1720 /* Adjust the number of bytes to avoid splitting a fixup. Find
1721 the last relocation table entry which applies to this chunk.
1722 Then, lower the chunk size to stop at the start of the
1723 frame. */
1724
1725 i = reloc_idx; end = off + n;
1726 while (i < reloc_count && reloc_tab[i].r_address < end)
1727 ++i;
1728 if (i > reloc_idx)
1729 {
1730 --i;
1731 tmp = reloc_tab[i].r_address + (1 << reloc_tab[i].r_length) - off;
1732 if (tmp > n)
1733 n = reloc_tab[i].r_address - off;
1734 }
1735
1736 /* Consult the BOUNDARY table to find the last point where we
1737 are allowed to split the data into multiple LEDATA records.
1738 This must be done after adjusting for relocation table
1739 entries. */
1740
1741 end = off + n;
1742 while (boundary_idx < boundary_count && boundary[boundary_idx] < end)
1743 ++boundary_idx;
1744 #if 1/* kso #456 2003-06-05: This must be wrong cause we're splitting unneedingly.
1745 * Check if we acutally hit the '< end' check. */
1746 if (boundary_idx > 0 && boundary_idx < boundary_count)
1747 #else
1748 if (boundary_idx > 0)
1749 #endif
1750 {
1751 tmp = boundary[boundary_idx-1] - off;
1752 if (tmp > 0)
1753 n = tmp;
1754 }
1755
1756 /* Write the LEDATA record. This is simple. */
1757
1758 if (off >= 0x10000 || force_big)
1759 {
1760 init_rec (LEDATA|REC32);
1761 put_idx (index);
1762 put_32 (off);
1763 }
1764 else
1765 {
1766 init_rec (LEDATA);
1767 put_idx (index);
1768 put_16 (off);
1769 }
1770 put_mem (src, n);
1771 write_rec ();
1772
1773 /* Write the FIXUPP records for this LEDATA record. Quite
1774 hairy. */
1775
1776 end = off + n;
1777 started = FALSE;
1778 r = &reloc_tab[reloc_idx];
1779
1780 /* Look at all relocation table entries which apply to the
1781 current LEDATA chunk. */
1782
1783 while (reloc_idx < reloc_count && r->r_address < end)
1784 {
1785
1786 /* Set ok to TRUE if we should create a fixup for this
1787 relocation table entry. First, ignore all but 32-bit
1788 relocations. In the $$SYMBOLS segment, we also have
1789 16-bit selector fixups. far16 is later set to TRUE for
1790 16:16 fixups. */
1791
1792 ok = (r->r_length == 2 || (sst_flag && r->r_length == 1));
1793 far16 = FALSE;
1794
1795 if (r->r_extern)
1796 {
1797
1798 /* The relocation refers to a symbol -- we won't use a
1799 target thread. If the symbol is a 16:16 symbol, we
1800 set far16 to true to generate a 16:16 fixup. */
1801
1802 threadp = NULL;
1803 if (sym_more[r->r_symbolnum].flags & SF_FAR16)
1804 far16 = TRUE;
1805 }
1806 else if (r->r_pcrel && (r->r_symbolnum & ~N_EXT) == seg_type)
1807 {
1808 ok = FALSE;
1809 if (!quiet)
1810 warning ("Internal PC-relative relocation ignored");
1811 }
1812 else
1813 {
1814
1815 /* The relocation does not refer to a symbol -- we use
1816 an appropriate target thread. The target thread
1817 number is taken from or stored to *threadp.
1818 target_index is the OMF segment index. */
1819
1820 switch (r->r_symbolnum & ~N_EXT)
1821 {
1822 case N_TEXT:
1823 threadp = &text_thread;
1824 target_index = text_index;
1825 break;
1826 case N_DATA:
1827 threadp = &data_thread;
1828 target_index = udat_index;
1829 break;
1830 case N_BSS:
1831 threadp = &bss_thread;
1832 target_index = bss_index;
1833 break;
1834 case N_ABS:
1835 default:
1836 ok = FALSE;
1837 break;
1838 }
1839 }
1840
1841 if (ok)
1842 {
1843
1844 /* Now we build the FIXUPP record. */
1845
1846 if (started && !fits (32))
1847 {
1848 write_rec ();
1849 started = FALSE;
1850 }
1851 if (!started)
1852 {
1853 init_rec (FIXUPP|REC32);
1854 started = TRUE;
1855 }
1856
1857 /* If no frame thread has been defined for the FLAT
1858 group, define it now. */
1859
1860 if (flat_thread < 0 && !far16)
1861 {
1862 if (frame_thread_index >= 4)
1863 error ("Too many frame threads");
1864 /* THREAD: D=1, METHOD=F1 */
1865 put_8 (0x44 | frame_thread_index);
1866 put_idx (flat_index);
1867 flat_thread = frame_thread_index++;
1868 }
1869
1870 /* If we want to use a target thread and the target
1871 thread is not yet defined, define it now. */
1872
1873 if (threadp != NULL && *threadp < 0)
1874 {
1875 if (target_thread_index >= 4)
1876 error ("Too many target threads");
1877 /* THREAD: D=0, METHOD=T4 */
1878 put_8 (0x10 | target_thread_index);
1879 put_idx (target_index);
1880 *threadp = target_thread_index++;
1881 }
1882
1883 /* Compute and write the locat word. */
1884
1885 data_off = r->r_address - off;
1886 if (far16)
1887 locat = 0x8c; /* Method 3: 16:16 far pointer */
1888 else if (sst_flag && r->r_length == 1)
1889 locat = 0x88; /* Method 2: selector */
1890 else
1891 locat = 0xa4; /* Method 9: 32-bit offset */
1892 locat |= ((data_off >> 8) & 0x03);
1893 if (!r->r_pcrel)
1894 locat |= 0x40;
1895 put_8 (locat);
1896 put_8 (data_off);
1897
1898 /* Write the rest of the FIXUP subrecord. */
1899
1900 if (far16)
1901 {
1902 /* F=0, FRAME=F2, T=0, P=1, TARGT=T2 */
1903 put_8 (0x26);
1904 put_idx (sym_more[r->r_symbolnum].index);
1905 put_idx (sym_more[r->r_symbolnum].index);
1906 }
1907 else if (r->r_extern)
1908 {
1909 /* F=1, FRAME=F1, T=0, P=1, TARGT=T2 */
1910 put_8 (0x86 | (flat_thread << 4));
1911 put_idx (sym_more[r->r_symbolnum].index);
1912 }
1913 else
1914 {
1915 /* F=1, FRAME=F1, T=1, P=1, TARGT=T4 */
1916 put_8 (0x8c | (flat_thread << 4) | *threadp);
1917 }
1918 }
1919 ++reloc_idx; ++r;
1920 }
1921 if (started)
1922 write_rec ();
1923
1924 /* Adjust pointers and counters for the next chunk. */
1925
1926 src += n; off += n; seg_size -= n;
1927 }
1928
1929 /* Deallocate the sorted relocation table. */
1930
1931 free (reloc_tab);
1932}
1933
1934
1935/* Write a default library request record to the output file. The
1936 linker will search the library NAME to resolve external
1937 references. Create a COMENT record of class 0x9f. The name is
1938 stored without leading byte count, the linker gets the length of
1939 the name from the record length. */
1940
1941static void request_lib (const char *name)
1942{
1943 init_rec (COMENT);
1944 put_8 (0x40);
1945 put_8 (0x9f);
1946 put_mem (name, strlen (name));
1947 write_rec ();
1948}
1949
1950
1951/* Write default library request records for all the -i options. The
1952 library names are stored in a list. libreq_head points to the head
1953 of the list. */
1954
1955static void write_libs (void)
1956{
1957 struct libreq *p;
1958
1959 for (p = libreq_head; p != NULL; p = p->next)
1960 request_lib (p->name);
1961}
1962
1963
1964/* Write a record identifying the debug information style to the
1965 output file. The style we use is called HLL version 3. Create a
1966 COMENT record of class 0xa1. */
1967
1968static void write_debug_style (void)
1969{
1970 if (strip_symbols || !a_out_h->a_syms)
1971 return;
1972 init_rec (COMENT);
1973 put_8 (0x80);
1974 put_8 (0xa1); /* Debug info style */
1975 put_8 (hll_version); /* Version */
1976 put_mem ("HL", 2); /* HLL style debug tables */
1977 write_rec ();
1978}
1979
1980
1981/* Write a link pass separator to the output file. The linker makes
1982 two passes through the object modules. The first pass stops when
1983 encountering the link pass separator. This is used for improving
1984 linking speed. The second pass ignores the link pass separator.
1985 The following records must precede the link pass separator: ALIAS,
1986 CEXTDEF COMDEF, EXTDEF, GRPDEF, LCOMDEF, LEXTDEF, LNAMES, LPUBDEF,
1987 PUBDEF, SEGDEF, TYPDEF, and most of the COMENT classes. Create a
1988 COMENT record of class 0xa2. */
1989
1990static void write_pass2 (void)
1991{
1992 init_rec (COMENT);
1993 put_8 (0x40);
1994 put_8 (0xa2); /* Link pass separator */
1995 put_8 (0x01);
1996 write_rec ();
1997}
1998
1999
2000/* Create segment names for all the sets. It is here where sets are
2001 created. See write_set_data() for details. */
2002
2003static void define_set_names (void)
2004{
2005 int i, j;
2006 struct set *set_ptr;
2007 char tmp[512];
2008 const char *name;
2009 byte type;
2010
2011 /* Loop through the symbol table. */
2012
2013 for (i = 0; i < sym_count; ++i)
2014 {
2015 type = sym_ptr[i].n_type & ~N_EXT;
2016 if ((type == N_SETA && sym_ptr[i].n_value == 0xffffffff)
2017 || type == N_SETT || type == N_SETD)
2018 {
2019
2020 /* This is a set element. If type is N_SETA the symbol is
2021 the head of the set, otherwise it is an ordinary set
2022 element. Search the table of sets to find out whether
2023 this set is already known. */
2024
2025 name = (const char *)(str_ptr + sym_ptr[i].n_un.n_strx);
2026 for (set_ptr = sets; set_ptr != NULL; set_ptr = set_ptr->next)
2027 if (strcmp (set_ptr->name, name) == 0)
2028 break;
2029 if (set_ptr == NULL)
2030 {
2031
2032 /* The set is not yet known. Create a new table
2033 entry. */
2034
2035 set_ptr = xmalloc (sizeof (struct set));
2036 set_ptr->name = xstrdup (name);
2037 for (j = 0; j < 3; ++j)
2038 {
2039 set_ptr->seg_name[j] = -1;
2040 set_ptr->seg_index[j] = -1;
2041 }
2042 set_ptr->count = 0;
2043 set_ptr->data = NULL;
2044 set_ptr->seg = NULL;
2045 set_ptr->def = 0;
2046 set_ptr->next = NULL;
2047 *set_add = set_ptr;
2048 set_add = &set_ptr->next;
2049 }
2050 else if (type == N_SETA && set_ptr->def)
2051 error ("Set `%s' defined more than once", name);
2052
2053 if (type == N_SETA)
2054 set_ptr->def = 1; /* Write SET1 and SET3 segments */
2055 else
2056 {
2057
2058 /* Add the element to the set. */
2059
2060 ++set_ptr->count;
2061 set_ptr->data = xrealloc (set_ptr->data, set_ptr->count * 4);
2062 set_ptr->seg = xrealloc (set_ptr->seg, set_ptr->count);
2063 set_ptr->data[set_ptr->count-1] = sym_ptr[i].n_value;
2064 set_ptr->seg[set_ptr->count-1]
2065 = (type == N_SETT ? N_TEXT : N_DATA);
2066 }
2067
2068 /* Define the OMF segment names for this set, if not yet
2069 done. */
2070
2071 if (set_ptr->seg_name[0] < 0)
2072 {
2073 strcpy (tmp, "SET#");
2074 strcat (tmp, name);
2075 for (j = 0; j < 3; ++j)
2076 {
2077 tmp[3] = (char)('1' + j);
2078 set_ptr->seg_name[j] = find_lname (tmp);
2079 }
2080 }
2081 }
2082 }
2083}
2084
2085
2086/* Define three segments for each set. The segment names have already
2087 been defined, now write the SEGDEF records. */
2088
2089static void write_set_segs (void)
2090{
2091 int j;
2092 struct set *set_ptr;
2093
2094 for (set_ptr = sets; set_ptr != NULL; set_ptr = set_ptr->next)
2095 for (j = 0; j < 3; ++j)
2096 set_ptr->seg_index[j] =
2097 seg_def (set_ptr->seg_name[j], data_class_name,
2098 4 * (j == 1 ? set_ptr->count : set_ptr->def), FALSE, TRUE);
2099}
2100
2101
2102/* Write the PUBDEF records for all the sets. One PUBDEF record is
2103 generated for each set, it defines the set name. */
2104
2105static void write_set_pub (void)
2106{
2107 struct set *set_ptr;
2108
2109 for (set_ptr = sets; set_ptr != NULL; set_ptr = set_ptr->next)
2110 if (set_ptr->def)
2111 {
2112 init_rec (force_big ? PUBDEF|REC32 : PUBDEF);
2113 put_idx (flat_index);
2114 put_idx (set_ptr->seg_index[0]);
2115 put_sym (set_ptr->name);
2116 if (force_big)
2117 put_32 (0);
2118 else
2119 put_16 (0);
2120 put_idx (0); /* Type index */
2121 write_rec ();
2122 }
2123}
2124
2125
2126/* Write the segment contents for all the sets. One or three segments
2127 are written for each set XXX:
2128
2129 SET1XXX long start = -2
2130 SET2XXX long table[]
2131 SET3XXX long end = 0
2132
2133 SET1XXX and SET3XXX are written only if there is a N_SETA symbol
2134 for the set. The N_SETA symbol defines the start of the set and
2135 must have a value of -1 (see crt0.s). SET2XXX is written for all
2136 modules which contain N_SETT or N_SETD symbols. All three segments
2137 belong to the group GROUPXXX. The linker combines all the segments
2138 of GROUPXXX into a single object. SET1XXX comes first, followed by
2139 the SET2XXX segments of all modules of the program, followed by
2140 SET3XXX. That way, we obtain a table of all set elements of a
2141 given set, preceded by -2 and terminated by 0. A symbol XXX is
2142 defined which points to the start of SET1XXX. See
2143 /emx/lib/gcc/main.c for code which uses sets. */
2144
2145static void write_set_data (void)
2146{
2147 struct set *set_ptr;
2148 dword x;
2149 int i, max_count;
2150 dword *buf;
2151 struct relocation_info *reloc_tab;
2152
2153 max_count = 0; buf = NULL; reloc_tab = NULL;
2154 for (set_ptr = sets; set_ptr != NULL; set_ptr = set_ptr->next)
2155 {
2156
2157 /* Write the first segment. It consists of a 32-bit word
2158 containing the number -2. This is used by the startup code
2159 to detect a delimited set. */
2160
2161 if (set_ptr->def)
2162 {
2163 x = 0xfffffffe;
2164 write_seg (set_ptr->seg_index[0], set_ptr->seg_name[0],
2165 (byte *)&x, sizeof (x), NULL, 0, FALSE, NULL, 0, -1);
2166 }
2167
2168 /* Write the second segment. It consists of the set elements as
2169 taken from the a.out module. The elements are assumed to be
2170 pointers into the text segment. */
2171
2172 if (set_ptr->count >= 1)
2173 {
2174
2175 /* Enlarge the relocation table, if required. */
2176
2177 if (set_ptr->count > max_count)
2178 {
2179 max_count = set_ptr->count;
2180 buf = xrealloc (buf, 4 * max_count);
2181 memset (buf, 0, 4 * max_count);
2182 reloc_tab = xrealloc (reloc_tab,
2183 max_count * sizeof (struct relocation_info));
2184 }
2185
2186 /* Create one relocation table entry for each set
2187 element. */
2188
2189 for (i = 0; i < set_ptr->count; ++i)
2190 {
2191 buf[i] = set_ptr->data[i];
2192 reloc_tab[i].r_address = i * 4;
2193 reloc_tab[i].r_symbolnum = set_ptr->seg[i];
2194 reloc_tab[i].r_pcrel = 0;
2195 reloc_tab[i].r_length = 2;
2196 reloc_tab[i].r_extern = 0;
2197 reloc_tab[i].r_pad = 0;
2198 }
2199
2200 /* Write the segment data and fixups. */
2201
2202 write_seg (set_ptr->seg_index[1], set_ptr->seg_name[1],
2203 (byte *)buf, set_ptr->count * 4, reloc_tab,
2204 set_ptr->count * sizeof (struct relocation_info), FALSE, NULL, 0,
2205 -1);
2206 }
2207
2208 /* Write the third segment. It consists of a 32-bit word
2209 containing the value 0, marking the end of the table. */
2210
2211 if (set_ptr->def)
2212 {
2213 x = 0;
2214 write_seg (set_ptr->seg_index[2], set_ptr->seg_name[2],
2215 (byte *)&x, sizeof (x), NULL, 0, FALSE, NULL, 0, -1);
2216 }
2217 }
2218 if (buf != NULL)
2219 free (buf);
2220}
2221
2222
2223/* Find a relocation table entry by fixup address. */
2224
2225static const struct relocation_info *find_reloc_fixup (const struct relocation_info *rel,
2226 long rel_size, dword addr)
2227{
2228 int i, count;
2229
2230 count = rel_size / sizeof (struct relocation_info);
2231 for (i = 0; i < count; ++i)
2232 if (rel[i].r_address == addr)
2233 return &rel[i];
2234 return NULL;
2235}
2236
2237
2238static void free_modstr_cache (void)
2239{
2240 struct modstr *p1, *p2;
2241
2242 for (p1 = modstr_cache; p1 != NULL; p1 = p2)
2243 {
2244 p2 = p1->next;
2245 free (p1->symbol);
2246 free (p1->str);
2247 free (p1);
2248 }
2249 modstr_cache = NULL;
2250}
2251
2252
2253/* Fetch a null-terminated string from a module. REL points to the
2254 relocation table entry of the pointer, ADDR is the pointer. Copy
2255 the string to DST, a buffer of DST_SIZE bytes. Return TRUE if
2256 successful, FALSE on failure. */
2257
2258static int fetch_modstr (const struct relocation_info *rel, dword addr,
2259 char *dst, size_t dst_size)
2260{
2261 const byte *seg_ptr;
2262 dword seg_size;
2263
2264 if (rel == NULL) return FALSE;
2265 if (rel->r_extern)
2266 {
2267 struct modstr *p;
2268 byte *buf;
2269 const char *sym_name;
2270 const struct nlist *m_sym = NULL;
2271 const struct exec *m_ao = NULL;
2272
2273 /* We have to take the string from another module. First try to
2274 get the string from the cache. */
2275
2276 sym_name = (const char *)(str_ptr + sym_ptr[rel->r_symbolnum].n_un.n_strx);
2277 for (p = modstr_cache; p != NULL; p = p->next)
2278 if (strcmp (p->symbol, sym_name) == 0)
2279 break;
2280 if (p == NULL)
2281 {
2282 long pos, size, m_str_size;
2283 struct ar_hdr ar;
2284 byte *t;
2285 size_t buf_size, len;
2286 const byte *m_str;
2287 int i, m_sym_count, found;
2288
2289 /* Search all modules until finding the symbol. */
2290
2291 buf = NULL; buf_size = 0; found = FALSE;
2292 pos = SARMAG;
2293 while (ar_read_header (&ar, pos))
2294 {
2295 size = ar_member_size (&ar);
2296 pos += (sizeof (ar) + size + 1) & -2;
2297 if (strcmp (ar.ar_name, "__.SYMDEF") == 0
2298 || strcmp (ar.ar_name, "__.IMPORT") == 0
2299 || memcmp (ar.ar_name, "IMPORT#", 7) == 0)
2300 continue;
2301 if (size > buf_size)
2302 {
2303 if (buf != NULL) free (buf);
2304 buf_size = size;
2305 buf = xmalloc (buf_size);
2306 }
2307 size = fread (buf, 1, size, inp_file);
2308 if (ferror (inp_file))
2309 error ("Cannot read `%s'", inp_fname);
2310 m_ao = (const struct exec *)buf;
2311 if (size < sizeof (struct exec) || N_MAGIC(*m_ao) != OMAGIC)
2312 break;
2313 t = buf + sizeof (struct exec);
2314 t += m_ao->a_text; t += m_ao->a_data;
2315 t += m_ao->a_trsize; t += m_ao->a_drsize;
2316 m_sym = (const struct nlist *)t; t += m_ao->a_syms;
2317 m_str = t;
2318 if (m_str + 4 - buf > size)
2319 break;
2320 m_str_size = *(long *)m_str;
2321 m_sym_count = m_ao->a_syms / sizeof (struct nlist);
2322 if (m_str + m_str_size - buf > size)
2323 break;
2324 for (i = 0; i < m_sym_count; ++i)
2325 switch (m_sym[i].n_type)
2326 {
2327 case N_TEXT|N_EXT:
2328 case N_DATA|N_EXT:
2329 if (strcmp ((const char *)(m_str + m_sym[i].n_un.n_strx), sym_name) == 0)
2330 {
2331 m_sym += i; found = TRUE; break;
2332 }
2333 }
2334 if (found)
2335 break;
2336 }
2337 if (!found)
2338 error ("Symbol `%s' not found", sym_name);
2339
2340 addr = m_sym->n_value;
2341 switch (m_sym->n_type)
2342 {
2343 case N_TEXT|N_EXT:
2344 seg_ptr = buf + sizeof (struct exec);
2345 seg_size = m_ao->a_text;
2346 break;
2347 case N_DATA|N_EXT:
2348 seg_ptr = buf + sizeof (struct exec) + m_ao->a_text;
2349 seg_size = m_ao->a_data;
2350 break;
2351 default:
2352 abort ();
2353 }
2354
2355 len = 0;
2356 for (;;)
2357 {
2358 if (addr + len >= seg_size)
2359 error ("String extends beyond end of segment");
2360 if (seg_ptr[addr + len] == 0)
2361 break;
2362 ++len;
2363 }
2364
2365 p = xmalloc (sizeof (struct modstr));
2366 p->symbol = xstrdup (sym_name);
2367 p->str = xmalloc (len + 1);
2368 memcpy (p->str, seg_ptr + addr, len + 1);
2369 p->next = modstr_cache;
2370 modstr_cache = p;
2371 if (buf != NULL) free (buf);
2372 }
2373 if (strlen (p->str) >= dst_size)
2374 return FALSE;
2375 strcpy (dst, p->str);
2376 return TRUE;
2377 }
2378 else
2379 {
2380 dword si;
2381
2382 switch (rel->r_symbolnum)
2383 {
2384 case N_TEXT:
2385 seg_ptr = text_ptr;
2386 seg_size = text_size;
2387 break;
2388 case N_DATA:
2389 seg_ptr = data_ptr;
2390 seg_size = data_size;
2391 break;
2392 default:
2393 return FALSE;
2394 }
2395 for (si = 0; addr + si < seg_size && si < dst_size; ++si)
2396 {
2397 dst[si] = seg_ptr[addr + si];
2398 if (seg_ptr[addr + si] == 0)
2399 return TRUE;
2400 }
2401 return FALSE;
2402 }
2403}
2404
2405
2406/* Create an import record and a PUBDEF record. */
2407
2408static void make_import (const char *pub_name, const char *proc_name,
2409 long ord, const char *mod)
2410{
2411 /* Skip a leading underscore character if present. */
2412
2413 if (strip_underscore (pub_name))
2414 ++pub_name;
2415
2416 /* Make the symbol public in the output library. */
2417
2418 if (omflib_add_pub (out_lib, pub_name, mod_page, lib_errmsg) != 0)
2419 error (lib_errmsg);
2420
2421 /* Write the import definition record. */
2422
2423 init_rec (COMENT);
2424 put_8 (0x00);
2425 put_8 (IMPDEF_CLASS);
2426 put_8 (IMPDEF_SUBTYPE);
2427 put_8 (proc_name == NULL ? 0x01 : 0x00); /* Import by ordinal or by name */
2428 put_str (pub_name); /* Underscore already removed above */
2429 put_str (mod);
2430 if (proc_name == NULL)
2431 put_16 (ord);
2432 else if (strcmp (proc_name, pub_name) == 0)
2433 put_8 (0);
2434 else
2435 put_str (proc_name);
2436 write_rec ();
2437 init_rec (MODEND|REC32);
2438 put_8 (0x00); /* Non-main module without start address */
2439 write_rec ();
2440}
2441
2442
2443/* If the input file is an import module (method (I2) as created by
2444 emximp), create an OMF-style import module and return TRUE.
2445 Otherwise, return FALSE. */
2446
2447static int handle_import_i2 (void)
2448{
2449 int i, len1, mod_len;
2450 long ord;
2451 const char *name1, *name2, *proc_name, *p;
2452 char mod[256], *q;
2453
2454 /* Search the symbol table for N_IMP1 and N_IMP2 symbols. These are
2455 unique to import modules. */
2456
2457 name1 = NULL; name2 = NULL;
2458 for (i = 0; i < sym_count; ++i)
2459 switch (sym_ptr[i].n_type)
2460 {
2461 case N_IMP1|N_EXT:
2462 name1 = (const char *)(str_ptr + sym_ptr[i].n_un.n_strx);
2463 break;
2464 case N_IMP2|N_EXT:
2465 name2 = (const char *)(str_ptr + sym_ptr[i].n_un.n_strx);
2466 break;
2467 default:
2468 return FALSE;
2469 }
2470
2471 /* If no N_IMP1 and N_IMP2 symbols have been found, the module is
2472 not an import module. */
2473
2474 if (name1 == NULL || name2 == NULL)
2475 return FALSE;
2476
2477 /* Parse the special symbols into module name and ordinal number.
2478 name2 should look like
2479
2480 SYMBOL=MODULE.ORDINAL
2481
2482 where SYMBOL is name1, MODULE is the module name and ORDINAL is
2483 the ordinal number. */
2484
2485 len1 = strlen (name1);
2486 if (memcmp (name1, name2, len1) != 0)
2487 error ("Invalid import record: names don't match");
2488 name2 += len1;
2489 if (*name2 != '=')
2490 error ("Invalid import record: missing `='");
2491 ++name2;
2492 p = strchr (name2, '.');
2493 if (p == NULL)
2494 error ("Invalid import record: missing `.'");
2495 mod_len = p - name2;
2496 memcpy (mod, name2, mod_len);
2497 mod[mod_len] = 0;
2498 proc_name = NULL;
2499 errno = 0;
2500 ord = strtol (p + 1, &q, 10);
2501 if (q != p + 1 && *q == 0 && errno == 0)
2502 {
2503 if (ord < 1 || ord > 65535)
2504 error ("Invalid import record: invalid ordinal");
2505 }
2506 else
2507 {
2508 ord = -1;
2509 proc_name = p + 1;
2510 if (*proc_name == 0)
2511 error ("Invalid import record: invalid name");
2512 }
2513
2514 make_import (name1, proc_name, ord, mod);
2515 return TRUE;
2516}
2517
2518/* Convert import entries. */
2519static void write_import_i2 (void)
2520{
2521 int i;
2522 const char *name1, *name2;
2523
2524 /* Search the symbol table for N_IMP1 and N_IMP2 symbols. These are
2525 unique to import modules. */
2526
2527 name1 = NULL; name2 = NULL;
2528 for (i = 0; i < sym_count; ++i)
2529 {
2530 switch (sym_ptr[i].n_type)
2531 {
2532 case N_IMP1|N_EXT:
2533 name1 = (const char *)(str_ptr + sym_ptr[i].n_un.n_strx);
2534 break;
2535 case N_IMP2|N_EXT:
2536 name2 = (const char *)(str_ptr + sym_ptr[i].n_un.n_strx);
2537 break;
2538 }
2539 if (name1 && name2)
2540 {
2541 int len1, mod_len;
2542 long ord;
2543 const char *proc_name, *p;
2544 char mod[256], *q;
2545
2546 /* Parse the special symbols into module name and ordinal number.
2547 name2 should look like
2548
2549 SYMBOL=MODULE.ORDINAL
2550
2551 where SYMBOL is name1, MODULE is the module name and ORDINAL is
2552 the ordinal number. */
2553
2554 len1 = strlen (name1);
2555 if (memcmp (name1, name2, len1) != 0)
2556 error ("Invalid import record: names don't match");
2557 name2 += len1;
2558 if (*name2 != '=')
2559 error ("Invalid import record: missing `='");
2560 ++name2;
2561 p = strchr (name2, '.');
2562 if (p == NULL)
2563 error ("Invalid import record: missing `.'");
2564 mod_len = p - name2;
2565 memcpy (mod, name2, mod_len);
2566 mod[mod_len] = '\0';
2567 proc_name = NULL;
2568 errno = 0;
2569 ord = strtol (p + 1, &q, 10);
2570 if (q != p + 1 && *q == 0 && errno == 0)
2571 {
2572 if (ord < 1 || ord > 65535)
2573 error ("Invalid import record: invalid ordinal");
2574 }
2575 else
2576 {
2577 ord = -1;
2578 proc_name = p + 1;
2579 if (*proc_name == 0)
2580 error ("Invalid import record: invalid name");
2581 }
2582
2583 /* Write the import definition record. */
2584
2585 init_rec (COMENT);
2586 put_8 (0x00);
2587 put_8 (IMPDEF_CLASS);
2588 put_8 (IMPDEF_SUBTYPE);
2589 put_8 (proc_name == NULL ? 0x01 : 0x00); /* Import by ordinal or by name */
2590 put_str (name1); /* Underscore already removed above */
2591 put_str (mod);
2592 if (proc_name == NULL)
2593 put_16 (ord);
2594 else if (strcmp (proc_name, name1) == 0)
2595 put_8 (0);
2596 else
2597 put_str (proc_name);
2598 write_rec ();
2599
2600 name1 = NULL;
2601 name2 = NULL;
2602 }
2603 }
2604}
2605
2606
2607/* If the input file is an import module (method (I1) as created by
2608 emximp), create an OMF-style import module and return TRUE.
2609 Otherwise, return FALSE. */
2610
2611static int handle_import_i1 (void)
2612{
2613 int i;
2614 const char *pub_name;
2615 char proc_name[257], dll_name[257];
2616 long table_off, ord, off;
2617 long *table;
2618 const struct relocation_info *rel;
2619
2620 /* There must be exactly one public symbol (which must defined for
2621 N_TEXT), otherwise we cannot safely eliminate all the code.
2622 Moreover, there must be an N_SETT|N_EXT entry for `__os2dll'. */
2623
2624 pub_name = NULL; table_off = -1;
2625 for (i = 0; i < sym_count; ++i)
2626 switch (sym_ptr[i].n_type)
2627 {
2628 case N_TEXT|N_EXT:
2629 if (pub_name != NULL) return FALSE;
2630 pub_name = (const char *)(str_ptr + sym_ptr[i].n_un.n_strx);
2631 break;
2632
2633 case N_DATA|N_EXT:
2634 case N_BSS|N_EXT:
2635 return FALSE;
2636
2637 case N_SETT|N_EXT:
2638 if (strcmp ((const char *)(str_ptr + sym_ptr[i].n_un.n_strx), "__os2dll") != 0)
2639 return FALSE;
2640 table_off = sym_ptr[i].n_value;
2641 break;
2642 }
2643
2644 if (pub_name == NULL || table_off == -1)
2645 return FALSE;
2646
2647 /* The table must be completely present. */
2648
2649 if (table_off < 0 || table_off + 4 * 4 > text_size)
2650 error ("Invalid import table: beyond end of segment");
2651
2652 /* Fetch the procedure name or the ordinal. */
2653
2654 table = (long *)(text_ptr + table_off);
2655 if (table[0] == 0)
2656 {
2657 ord = 0;
2658
2659 /* Check and fetch the procedure name. */
2660
2661 rel = find_reloc_fixup (text_rel, a_out_h->a_trsize, table_off + 3 * 4);
2662 if (!fetch_modstr (rel, table[3], proc_name, sizeof (proc_name)))
2663 error ("Invalid import table: invalid pointer to procedure name");
2664 }
2665 else if (table[0] == 1)
2666 {
2667 ord = table[3];
2668 if (ord < 1 || ord > 65535)
2669 error ("Invalid import table: invalid ordinal number");
2670 }
2671 else
2672 error ("Invalid import table: invalid flag");
2673
2674 /* Check the fixup address -- there must be a JMP instruction. */
2675
2676 off = table[1];
2677 if (off < 1 || off + 4 > text_size)
2678 error ("Invalid import table: invalid fixup address");
2679 if (text_ptr[off-1] != 0xe9)
2680 error ("Invalid import table: fixup does not belong to a JMP instruction");
2681
2682 /* Check and fetch the module name. */
2683
2684 rel = find_reloc_fixup (text_rel, a_out_h->a_trsize, table_off + 2 * 4);
2685 if (!fetch_modstr (rel, table[2], dll_name, sizeof (dll_name)))
2686 error ("Invalid import table: invalid pointer to module name");
2687
2688 make_import (pub_name, ord != 0 ? NULL : proc_name, ord, dll_name);
2689 return TRUE;
2690}
2691
2692/**
2693 * Emits a OMF export record if the symbols is defined in this module.
2694 */
2695static void make_export(const char *pszSymbol, size_t cchSymbol,
2696 const char *pszExpName, size_t cchExpName, unsigned iOrdinal)
2697{
2698 const struct nlist *pSym;
2699 char *pszSym = alloca(cchSymbol + 1);
2700 memcpy(pszSym, pszSymbol, cchSymbol);
2701 pszSym[cchSymbol] = '\0';
2702
2703 pSym = find_symbol(pszSym);
2704 if (pSym)
2705 {
2706 /*
2707 * Write the export definition record.
2708 */
2709 uint8_t fFlags = 0;
2710 if (iOrdinal)
2711 fFlags |= 1 << 7; /* have ordinal */
2712 if (cchExpName && !iOrdinal)
2713 fFlags |= 1 << 6; /* resident name */
2714
2715 init_rec(COMENT);
2716 put_8(0x00);
2717 put_8(CLASS_OMFEXT);
2718 put_8(OMFEXT_EXPDEF);
2719 put_8(fFlags);
2720 put_nstr(pszExpName, cchExpName);
2721 put_nstr(pszSymbol, cchSymbol);
2722 if (iOrdinal)
2723 put_16(iOrdinal);
2724 write_rec();
2725 }
2726}
2727
2728
2729/* Convert export entries.
2730
2731 The exports are encoded as N_EXT (0x6c) stab entries. The value is -42,
2732 and the symbol name is on the form: "<exportname>,<ordinal>=<symbol>,code|data"
2733 The exportname can be empty if ordinal is not 0. Ordinal 0 means not exported by
2734 any special ordinal number.
2735
2736 Export entries for symbols which are not defined in the object are ignored. */
2737static void write_export (void)
2738{
2739 int i;
2740
2741 /* Search the symbol table for N_IMP1 and N_IMP2 symbols. These are
2742 unique to import modules. */
2743
2744 for (i = 0; i < sym_count; ++i)
2745 {
2746 const char *pszName;
2747 size_t cchName;
2748 const char *pszOrdinal;
2749 const char *pszSymbol;
2750 size_t cchSymbol;
2751 const char *pszType;
2752 int iOrdinal;
2753 char *pszOrdinalEnd;
2754 if (sym_ptr[i].n_type != N_EXP)
2755 continue;
2756 pszName = (const char *)(str_ptr + sym_ptr[i].n_un.n_strx);
2757
2758 /*
2759 * Parse it.
2760 */
2761 /* find equal sign first, we'll use this for validating the ordinal. */
2762 pszSymbol = strchr(pszName, '=');
2763 if (!pszSymbol)
2764 error("Invalid export record: missing `='. \nstabs: %s", pszName);
2765
2766 /* ordinal */
2767 pszOrdinal = strchr(pszName, ',');
2768 if (!pszOrdinal || pszOrdinal >= pszSymbol)
2769 error("Invalid export record: missing ordinal.\nstabs: %s", pszName);
2770 cchName = pszOrdinal - pszName;
2771 pszOrdinal++;
2772 iOrdinal = strtol(pszOrdinal, &pszOrdinalEnd, 0);
2773 if (iOrdinal < 0 || iOrdinal >= 0x10000)
2774 error("Invalid export record: ordinal value is out of range (0-65k): %d\nstabs:%s",
2775 iOrdinal, pszName);
2776 if (pszOrdinalEnd != pszSymbol)
2777 error("Invalid export record: ordinal field doesn't end at `=.\nstabs:%s", pszName);
2778
2779 /* type and symbol */
2780 pszSymbol++;
2781 pszType = strchr(pszSymbol, ',');
2782 if (!pszType)
2783 error("Invalid export record: Symbol type is missing\nstabs:%s", pszName);
2784 cchSymbol = pszType - pszSymbol;
2785 pszType++;
2786 if (strcmp(pszType, "code") && strcmp(pszType, "data") && strcmp(pszType, "bss") && strcmp(pszType, "common"))
2787 error("Invalid export record: Invalid symbol type: %s\nstabs:%s", pszType, pszName);
2788 if (!cchSymbol)
2789 error("Invalid export record: No (internal) symbol name.\nstabs:%s", pszName);
2790
2791 /*
2792 * Hand it on to the worker which looks up the symbol
2793 * and emits the OMF export record if found.
2794 */
2795 make_export(pszSymbol, cchSymbol, pszName, cchName, iOrdinal);
2796 }
2797}
2798
2799
2800/* Convert a filename from Unix format to OS/2 format. All that has
2801 to be done is replacing slashes with backslashes as IPMD doesn't
2802 like slashes in file names. The conversion is done in place. */
2803
2804static void convert_filename (char *name)
2805{
2806 while (*name != 0)
2807 {
2808 if (*name == '/')
2809 *name = '\\';
2810 ++name;
2811 }
2812}
2813
2814#if 0
2815/* Converts dashed filenames to somewhat absolute ones assuming that
2816 the current directory is what they're relative to. */
2817
2818static int abspath_filename(char *dst, const char *src, int size)
2819{
2820 int rc = -1;
2821 char *psz;
2822
2823 if (src[1] != ':' && src[0] != '\\' && src[0] != '/')
2824 rc = _abspath(dst, src, size);
2825 if (rc)
2826 {
2827 *dst = '\0';
2828 strncat(dst, src, size);
2829 }
2830
2831 for (psz = dst; *psz; psz++)
2832 if (*psz == '/')
2833 *psz = '\\';
2834 return psz - dst;
2835}
2836#endif
2837
2838/* Derive the module name and store it in the mod_name variable.
2839 Derive the current director and store it in the base_dir variable.
2840
2841 Search the symbol table for N_SO symbols. There are two kinds, base dir
2842 and main source file name. The base dir one ends with a slash.
2843
2844 We assume that the base dir name comes first, and that is it's prefect
2845 but maybe for a drive letter.
2846
2847 If there is no such symbol, use the output file name. */
2848
2849static void get_mod_name (void)
2850{
2851 int i, len, ok;
2852 const char *p1, *p2;
2853
2854 base_dir[0] = '\0';
2855 ok = FALSE;
2856 for (i = 0; i < sym_count; ++i)
2857 if (sym_ptr[i].n_type == N_SO)
2858 {
2859 p1 = (const char *)(str_ptr + sym_ptr[i].n_un.n_strx);
2860 len = strlen (p1);
2861 if (len > 0 && p1[len-1] == '/' )
2862 {
2863 if (!base_dir[0])
2864 {
2865 _strncpy (base_dir, p1, sizeof(base_dir));
2866 convert_filename (base_dir);
2867 }
2868 }
2869 else if (len > 0)
2870 {
2871 ok = TRUE;
2872 _strncpy (mod_name, p1, sizeof (mod_name));
2873 convert_filename (mod_name);
2874 /* The base dir doesn't currently have any drive letter.
2875 steal that from the source filename if possible.
2876 ASSUME: that it's more like that source is right than curdir
2877 bacause of stuff like makeomflibs.cmd and autoconv. */
2878 if ( (base_dir[0] == '\\' || base_dir[0] == '/')
2879 && base_dir[1] != '\\' && base_dir[1] != '/' /* unc */
2880 && mod_name[1] == ':')
2881 {
2882 len = strlen(base_dir) + 1;
2883 memmove(base_dir + 2, base_dir, len);
2884 base_dir[0] = mod_name[0];
2885 base_dir[1] = mod_name[1];
2886 }
2887 break;
2888 }
2889 }
2890 if (!ok && out_lib == NULL)
2891 {
2892 p1 = out_fname;
2893 for (p2 = p1; *p2 != 0; ++p2)
2894 if (*p2 == '/' || *p2 == '\\' || *p2 == ':')
2895 p1 = p2 + 1;
2896 _strncpy (mod_name, p1, sizeof (mod_name));
2897 }
2898
2899 /* make sure we have base_dir and that it's an abspath */
2900 if (!base_dir[0])
2901 {
2902 getcwd(base_dir, sizeof(base_dir));
2903 len = strlen(base_dir);
2904 base_dir[len++] = '\\';
2905 base_dir[len] = '\0';
2906 }
2907 else if ( (base_dir[0] == '\\' || base_dir[0] == '/')
2908 && base_dir[1] != '\\' && base_dir[1] != '/') /* unc */
2909 { /* make it absolute using current drive */
2910 len = strlen(base_dir) + 1;
2911 memmove(base_dir + 2, base_dir, len);
2912 base_dir[0] = _getdrive();
2913 base_dir[1] = ':';
2914 }
2915}
2916
2917
2918/* Write the translator module header record. When creating a .LIB
2919 file, this function does nothing. Otherwise, the module name is
2920 expected in the mod_name variable. */
2921
2922static void write_theadr (void)
2923{
2924 if (out_lib == NULL)
2925 {
2926 init_rec (THEADR);
2927 put_str (mod_name);
2928 write_rec ();
2929 }
2930}
2931
2932/* Tell LINK386 what identifier manipulator DLL to call. The name of
2933 the DLL is given by `idmdll_name', the default value of which is
2934 GPPDEMID. The name can be changed with the -I option. If -I- is
2935 given, no IDMDLL record will be written. The IDMDLL record will
2936 also be suppressed if the program hasn't been compiled by the GNU
2937 C++ compiler. */
2938
2939static void write_idmdll ()
2940{
2941 /* kso #465 2003-06-04: This test doesn't work any longer, sorry.
2942 * Pretend everything is C++ */
2943 #if 1
2944 if (idmdll_name != NULL)
2945 #else
2946 if (idmdll_name != NULL && find_symbol ("__gnu_compiled_cplusplus") != NULL)
2947 #endif
2948 {
2949 init_rec (COMENT);
2950 put_8 (0x00);
2951 put_8 (CLASS_IDMDLL);
2952 put_str (idmdll_name);
2953 put_str (""); /* Initialization parameter */
2954 write_rec ();
2955 }
2956}
2957
2958
2959/* Tell ilink which TIS (Tools I Standard) version we follow.
2960 (At least that's what I think this comment record is good for). */
2961static void write_tis ()
2962{
2963 unsigned short ver = 0;
2964 char *type = getenv ("EMXOMFLD_TYPE");
2965 if (type && !stricmp (type, "VAC308"))
2966 ver = 0x0100;
2967 else if (!type || !stricmp (type, "VAC365"))
2968 ver = 0x0101;
2969 /* else: no TIS record for link386! */
2970
2971 if (ver)
2972 {
2973 init_rec (COMENT);
2974 put_8 (0x00);
2975 put_8 (CLASS_TIS);
2976 put_mem ("TIS", 3);
2977 put_16 (ver);
2978 write_rec ();
2979 }
2980}
2981
2982
2983/* Tell ilink which dll to use when /DBGPACK is specificed. The dllname
2984 is given without extension. */
2985static void write_dbgpack ()
2986{
2987 const char *name = dbgpack_name;
2988 if (strip_symbols || !a_out_h->a_syms)
2989 return;
2990 if (!name)
2991 {
2992 char *type = getenv ("EMXOMFLD_TYPE");
2993 if (type && !stricmp (type, "VAC308"))
2994 name = "LNKOH410";
2995 else if (!type || !stricmp (type, "VAC365"))
2996 name = NULL /* hll_version == 4 ? "CPPLH436" : "CPPLH636"
2997 - this linker figures it out by it self. */;
2998 /* no DLL for link386! */
2999 }
3000
3001 if (name)
3002 {
3003 init_rec (COMENT);
3004 put_8 (0x80);
3005 put_8 (CLASS_DBGPACK);
3006 put_str (name);
3007 write_rec ();
3008 }
3009}
3010
3011
3012/* Find a file name for creating line number information. */
3013
3014static int file_find (const char *name)
3015{
3016 int i;
3017 char *psz;
3018
3019 /* canonize the filename - slashes and possibly abs path. */
3020 if (name[0] != '/' && name[0] != '\\' && name[1] != ':')
3021 { /* need to add base_dir. */
3022 int cch1 = strlen(base_dir);
3023 int cch2 = strlen(name) + 1;
3024 psz = xmalloc(cch1 + cch2);
3025 memcpy(psz, base_dir, cch1);
3026 memcpy(psz + cch1, name, cch2);
3027 }
3028 else
3029 psz = xstrdup(name);
3030 convert_filename(psz);
3031
3032 /* search for previous instances */
3033 for (i = 0; i < file_grow.count; ++i)
3034 if (!strcmp(file_list[i], psz))
3035 {
3036 free(psz);
3037 return i;
3038 }
3039
3040 /* new source file, add it if possible. */
3041 if (hll_version <= 3 && file_grow.count >= 255)
3042 {
3043 warning ("Too many source files, cannot convert line number info");
3044 free(psz);
3045 return file_grow.count;
3046 }
3047 grow_by (&file_grow, 1);
3048 i = file_grow.count++;
3049 file_list[i] = psz;
3050 return i;
3051}
3052
3053
3054/* This function is passed to qsort() for sorting line numbers. X1
3055 and X2 point to struct line structures. Line number entries are
3056 sorted by address, file and line number. */
3057
3058static int line_compare (const void *x1, const void *x2)
3059{
3060 dword a1, a2;
3061 int i1, i2;
3062
3063 a1 = ((const struct line *)x1)->addr;
3064 a2 = ((const struct line *)x2)->addr;
3065 if (a1 < a2)
3066 return -1;
3067 else if (a1 > a2)
3068 return 1;
3069 i1 = ((const struct line *)x1)->file_index;
3070 i2 = ((const struct line *)x2)->file_index;
3071 if (i1 < i2)
3072 return -1;
3073 else if (i1 > i2)
3074 return 1;
3075 i1 = ((const struct line *)x1)->line;
3076 i2 = ((const struct line *)x2)->line;
3077 if (i1 < i2)
3078 return -1;
3079 else if (i1 > i2)
3080 return 1;
3081 return 0;
3082}
3083
3084/* Write linenumber fixups for HLL v4 records
3085 * We need fixups for segment idx and offset in the special
3086 * first entry. */
3087static void write_linenumfixup(void)
3088{
3089 /* ASSUME! flat_thread is defined. */
3090 /* ASSUME! base seg idx of linnum rec < 128. */
3091 init_rec (FIXUPP|REC32);
3092 /* LOC=16-bit sel;I=1;M=1; */
3093 put_8 (0xc8);
3094 /* offset 6 (segment number). */
3095 put_8 (0x06);
3096 /* F=1;Frame=flat_thread;T=0;P=1;TARGT=0; */
3097 put_8 (0x84 | (flat_thread << 4));
3098 /* target seg index? */
3099 put_8 (text_index);
3100
3101 /* LOC=32-offset sel;I=1;M=1; */
3102 put_8 (0xe4);
3103 /* offset 8 (offset). */
3104 put_8 (0x08);
3105 /* F=1;Frame=flat_thread;T=0;P=1;TARGT=0; */
3106 put_8 (0x84 | (flat_thread << 4));
3107 /* target seg index? */
3108 put_8 (text_index);
3109 write_rec ();
3110}
3111
3112
3113/* Write line number information to the output file. Unfortunately,
3114 the line number information format currently used by IPMD is not
3115 documented. This code is based on experimentation. */
3116
3117static void write_linnum (void)
3118{
3119 int i, started, len, file_index;
3120 int valid_lines;
3121 struct line *line_list;
3122 struct grow line_grow;
3123 char buf[256];
3124
3125 /* Initialize growing arrays for file names and line numbers. */
3126
3127 grow_init (&file_grow, &file_list, sizeof (*file_list), 8);
3128 grow_init (&line_grow, &line_list, sizeof (*line_list), 64);
3129
3130 /* Define file index for main source file. */
3131
3132 file_index = file_find (mod_name);
3133 started = FALSE;
3134
3135 /* Go through the symbol table, defining line numbers and additional
3136 source files. */
3137
3138 for (i = 0; i < sym_count; ++i)
3139 switch (sym_ptr[i].n_type)
3140 {
3141 case N_SOL:
3142 file_index = file_find ((const char *)(str_ptr + sym_ptr[i].n_un.n_strx));
3143 break;
3144 case N_SLINE:
3145 grow_by (&line_grow, 1);
3146 line_list[line_grow.count].file_index = file_index;
3147 line_list[line_grow.count].line = sym_ptr[i].n_desc;
3148 line_list[line_grow.count].addr = sym_ptr[i].n_value;
3149 ++line_grow.count;
3150 }
3151
3152 /* Sort the line numbers by address, file and line number. */
3153
3154 qsort (line_list, line_grow.count, sizeof (*line_list), line_compare);
3155
3156 /* If there are multiple line numbers assigned to the same address,
3157 keep but the last line number. Delete line numbers by setting
3158 the line number to -1. */
3159
3160 for (i = 0; i < line_grow.count - 1; ++i)
3161 if (line_list[i].line >= 0 && line_list[i+1].line >= 0
3162 && line_list[i].addr == line_list[i+1].addr)
3163 line_list[i].line = -1;
3164
3165 /* Count the number of valid line numbers, that is, non-negative
3166 line numbers. */
3167
3168 valid_lines = 0;
3169 for (i = 0; i < line_grow.count; ++i)
3170 if (line_list[i].line >= 0)
3171 ++valid_lines;
3172
3173
3174 /*
3175 * If no lines or no files, we don't want to issue any LINNUM records.
3176 */
3177 if (valid_lines <= 0 || file_grow.count <= 0)
3178 return;
3179
3180 /* Compute the size of the file names table. */
3181
3182 len = 3 * 4;
3183 for (i = 0; i < file_grow.count; ++i)
3184 len += 1 + strlen (file_list[i]);
3185
3186 /*
3187 * This is the VAC way, too bad link386 doesn't fancy it.
3188 */
3189 if (hll_version >= 4)
3190 {
3191 int first_linnum;
3192 /* Filename table first - a first entry like visual age does it and does hints on */
3193
3194 init_rec (LINNUM|REC32);
3195 started = TRUE;
3196 put_idx (0); /* Base Group */
3197 put_idx (0); /* Base Segment */
3198
3199 put_16 (0); /* Line number = 0 (special entry) */
3200 put_8 (3); /* Entry type: some visual age stuff I believe */
3201 put_8 (0); /* Reserved */
3202 put_16 (file_grow.count); /* Count of line number entries */
3203 put_16 (0); /* Segment number */
3204 put_32 (len); /* Size of file names table */
3205 /* no linenumber */
3206 put_32 (0); /* First column */
3207 put_32 (0); /* Number of columns */
3208 put_32 (file_grow.count); /* Number of source and listing files */
3209
3210 for (i = 0; i < file_grow.count; ++i)
3211 {
3212 len = strlen(file_list[i]);
3213 if (started && !fits (1 + len))
3214 {
3215 write_rec ();
3216 started = FALSE;
3217 }
3218 if (!started)
3219 {
3220 init_rec (LINNUM|REC32);
3221 put_idx (0); /* Base Group */
3222 put_idx (text_index); /* Base Segment */
3223 started = TRUE;
3224 }
3225 put_8 (len);
3226 put_mem (file_list[i], len);
3227 }
3228
3229 if (started)
3230 write_rec ();
3231
3232
3233 /* Write the line number table. */
3234 first_linnum = 1;
3235 init_rec (LINNUM|REC32);
3236 started = TRUE;
3237 put_idx (0); /* Base Group */
3238 put_idx (text_index); /* Base Segment */
3239
3240 put_16 (0); /* Line number = 0 (special entry) */
3241 put_8 (0); /* Entry type: source and offset */
3242 put_8 (0); /* Reserved */
3243 put_16 (valid_lines); /* Count of line number entries */
3244 put_16 (0); /* Segment number - Fixup required */
3245 put_32 (0); /* Segment offset - Fixup required */
3246
3247 for (i = 0; i < line_grow.count; ++i)
3248 if (line_list[i].line >= 0)
3249 {
3250 if (started && !fits (8))
3251 {
3252 write_rec ();
3253 started = FALSE;
3254 if (first_linnum)
3255 {
3256 first_linnum = 0;
3257 write_linenumfixup();
3258 }
3259 }
3260 if (!started)
3261 {
3262 init_rec (LINNUM|REC32);
3263 put_idx (0); /* Base Group */
3264 put_idx (text_index); /* Base Segment */
3265 started = TRUE;
3266 }
3267 put_16 (line_list[i].line);
3268 put_16 (line_list[i].file_index + 1);
3269 put_32 (line_list[i].addr);
3270 }
3271
3272 if (started)
3273 {
3274 write_rec ();
3275 if (first_linnum)
3276 write_linenumfixup();
3277 }
3278 }
3279 else
3280 { /* hll version 3 */
3281 /* Write the line number table. */
3282
3283 init_rec (LINNUM|REC32);
3284 started = TRUE;
3285 put_idx (0); /* Base Group */
3286 put_idx (text_index); /* Base Segment */
3287
3288 put_16 (0); /* Line number = 0 (special entry) */
3289 put_8 (0); /* Entry type: source and offset */
3290 put_8 (0); /* Reserved */
3291 put_16 (valid_lines); /* Count of line number entries */
3292 put_16 (0); /* Segment number */
3293 put_32 (len); /* Size of file names table */
3294
3295 for (i = 0; i < line_grow.count; ++i)
3296 if (line_list[i].line >= 0)
3297 {
3298 if (started && !fits (8))
3299 {
3300 write_rec ();
3301 started = FALSE;
3302 }
3303 if (!started)
3304 {
3305 init_rec (LINNUM|REC32);
3306 put_idx (0); /* Base Group */
3307 put_idx (text_index); /* Base Segment */
3308 started = TRUE;
3309 }
3310 put_16 (line_list[i].line);
3311 put_16(line_list[i].file_index + 1);
3312 put_32 (line_list[i].addr);
3313 }
3314
3315 /* Now write the file names table. */
3316
3317 if (started && !fits (12))
3318 {
3319 write_rec ();
3320 started = FALSE;
3321 }
3322 if (!started)
3323 {
3324 init_rec (LINNUM|REC32);
3325 put_idx (0); /* Base Group */
3326 put_idx (text_index); /* Base Segment */
3327 started = TRUE;
3328 }
3329 put_32 (0); /* First column */
3330 put_32 (0); /* Number of columns */
3331 put_32 (file_grow.count); /* Number of source and listing files */
3332
3333 for (i = 0; i < file_grow.count; ++i)
3334 {
3335 len = strlen (file_list[i]);
3336 if (len > sizeof (buf) - 1)
3337 len = sizeof (buf) - 1;
3338 memcpy (buf, file_list[i], len);
3339 buf[len] = 0;
3340 convert_filename (buf);
3341 if (started && !fits (1 + len))
3342 {
3343 write_rec ();
3344 started = FALSE;
3345 }
3346 if (!started)
3347 {
3348 init_rec (LINNUM|REC32);
3349 put_idx (0); /* Base Group */
3350 put_idx (text_index); /* Base Segment */
3351 started = TRUE;
3352 }
3353 put_8 (len);
3354 put_mem (buf, len);
3355 }
3356
3357 if (started)
3358 write_rec ();
3359 }
3360
3361 grow_free (&line_grow);
3362 grow_free (&file_grow);
3363}
3364
3365
3366/* Print unknown symbol table entries (-u option). */
3367
3368static void list_unknown_stabs (void)
3369{
3370 int i;
3371
3372 for (i = 0; i < sym_count; ++i)
3373 switch (sym_ptr[i].n_type)
3374 {
3375 case 0: case 0 |N_EXT:
3376 case N_ABS: case N_ABS |N_EXT:
3377 case N_TEXT: case N_TEXT|N_EXT:
3378 case N_DATA: case N_DATA|N_EXT:
3379 case N_BSS: case N_BSS |N_EXT:
3380 case N_INDR|N_EXT:
3381 case N_WEAKU:
3382 case N_WEAKA:
3383 case N_WEAKT:
3384 case N_WEAKD:
3385 case N_WEAKB:
3386 case N_SETA: case N_SETA|N_EXT:
3387 case N_SETT: case N_SETT|N_EXT:
3388 case N_SETD: case N_SETD|N_EXT:
3389 case N_GSYM:
3390 case N_FUN:
3391 case N_STSYM:
3392 case N_LCSYM:
3393 case N_RSYM:
3394 case N_SLINE:
3395 case N_SO:
3396 case N_IMP1|N_EXT:
3397 case N_IMP2|N_EXT:
3398 case N_EXP: case N_EXP|N_EXT:
3399 case N_LSYM:
3400 case N_SOL:
3401 case N_PSYM:
3402 case N_LBRAC:
3403 case N_RBRAC:
3404 break;
3405 default:
3406 fprintf (stderr, "Unknown symbol table entry: 0x%.2x \"%s\"\n",
3407 sym_ptr[i].n_type, str_ptr + sym_ptr[i].n_un.n_strx);
3408 break;
3409 }
3410}
3411
3412/* Convert an a.out module to an OMF module. SIZE is the number of
3413 bytes in the input file inp_file. */
3414
3415static void o_to_omf (long size)
3416{
3417 byte *t;
3418 const struct nlist *entry_symbol;
3419 struct set *set_ptr;
3420 int j;
3421
3422 /* Simplify things by reading the complete a.out module into
3423 memory. */
3424
3425 inp_buf = xmalloc (size);
3426 size = fread (inp_buf, 1, size, inp_file);
3427 if (ferror (inp_file))
3428 goto read_error;
3429
3430 /* Set up pointers to various sections of the module read into
3431 memory. */
3432
3433 a_out_h = (struct exec *)inp_buf;
3434 if (size < sizeof (struct exec) || N_MAGIC(*a_out_h) != OMAGIC)
3435 error ("Input file `%s' is not an a.out file", error_fname);
3436 text_size = a_out_h->a_text;
3437 data_size = a_out_h->a_data;
3438 t = inp_buf + sizeof (struct exec);
3439 text_ptr = t; t += text_size;
3440 data_ptr = t; t += data_size;
3441 text_rel = (const struct relocation_info *)t; t += a_out_h->a_trsize;
3442 data_rel = (const struct relocation_info *)t; t += a_out_h->a_drsize;
3443 sym_ptr = (const struct nlist *)t; t += a_out_h->a_syms;
3444 str_ptr = t;
3445 if (a_out_h->a_syms == 0)
3446 str_size = 0;
3447 else
3448 {
3449 if (str_ptr + 4 - inp_buf > size)
3450 goto invalid;
3451 str_size = *(long *)str_ptr;
3452 }
3453 sym_count = a_out_h->a_syms / sizeof (struct nlist);
3454 if (str_ptr + str_size - inp_buf > size)
3455 goto invalid;
3456
3457 /* Build the complementary array of symbol data. */
3458
3459 sym_more = xmalloc (sym_count * sizeof (struct symbol));
3460 memset(sym_more, 0, sym_count * sizeof (struct symbol));
3461
3462 /* Print unknown symbol table entries if the -u option is given. */
3463
3464 if (unknown_stabs)
3465 list_unknown_stabs ();
3466
3467 /* Find the start symbol if converting a main module. */
3468
3469 if (entry_name != NULL)
3470 {
3471 entry_symbol = find_symbol (entry_name);
3472 if (entry_symbol == NULL)
3473 error ("Entry symbol not found");
3474 if ((entry_symbol->n_type & ~N_EXT) != N_TEXT)
3475 error ("Entry symbol not in text segment");
3476 }
3477 else
3478 entry_symbol = NULL; /* keep the compiler happy */
3479
3480 /* Initialize variables for a new OMF module. */
3481
3482 init_obj ();
3483
3484 /* If the a.out module is an import module as created by emximp,
3485 create an OMF import module. Everything is done by
3486 handle_import_i2() or handle_import_i1() in that case, therefore
3487 we can simply return. */
3488
3489 if (out_lib != NULL && (handle_import_i2 () || handle_import_i1 ()))
3490 return;
3491
3492 /* Initialize growing arrays for debug information conversion.
3493 These two arrays contain indices at which the $$SYMBOLS and
3494 $$TYPES segments, respectively, can be split into LEDATA records
3495 by write_seg(). */
3496
3497 grow_init (&sst_boundary_grow, &sst_boundary, sizeof (*sst_boundary), 32);
3498 grow_init (&tt_boundary_grow, &tt_boundary, sizeof (*tt_boundary), 32);
3499
3500 /* Create some OMF names. */
3501
3502 ovl_name = find_lname ("");
3503 text_seg_name = find_lname ("TEXT32");
3504 data_seg_name = find_lname ("DATA32");
3505 bss_seg_name = find_lname ("BSS32");
3506 if (udat_seg_string != NULL)
3507 udat_seg_name = find_lname (udat_seg_string);
3508 else
3509 udat_seg_name = data_seg_name;
3510 if (!strip_symbols && a_out_h->a_syms)
3511 {
3512 symbols_seg_name = find_lname ("$$SYMBOLS");
3513 types_seg_name = find_lname ("$$TYPES");
3514 }
3515 code_class_name = find_lname ("CODE");
3516 data_class_name = find_lname ("DATA");
3517 bss_class_name = find_lname ("BSS");
3518 if (!strip_symbols && a_out_h->a_syms)
3519 {
3520 debsym_class_name = find_lname ("DEBSYM");
3521 debtyp_class_name = find_lname ("DEBTYP");
3522 }
3523 define_set_names ();
3524 if (mod_type == MT_MAIN)
3525 {
3526 stack_seg_name = find_lname ("STACK");
3527 stack_class_name = find_lname ("STACK");
3528 }
3529 flat_group_name = find_lname ("FLAT");
3530 dgroup_group_name = find_lname ("DGROUP");
3531
3532 /* Write the THREADR record. */
3533
3534 get_mod_name ();
3535 write_theadr ();
3536
3537 /* Tell ilink what TIS standard we follow. */
3538
3539 write_tis ();
3540
3541 /* Write default library requests and the debug information style
3542 record (COMENT records). */
3543
3544 write_libs ();
3545 write_debug_style ();
3546
3547 /* Tell ilink what DBGPACK DLL to use. */
3548
3549 write_dbgpack ();
3550
3551 /* Tell LINK386 what identifier manipulator DLL to use. */
3552
3553 write_idmdll ();
3554
3555 /* Define all the OMF names (LNAMES record). Of course, we must not
3556 define new OMF names after this point. */
3557
3558 write_lnames ();
3559
3560 /* Define segments (SEGDEF records). This must be done after
3561 defining the names and before defining the groups. */
3562
3563 text_index = seg_def (text_seg_name, code_class_name, text_size,
3564 FALSE, FALSE);
3565 if (udat_seg_string != NULL)
3566 udat_index = seg_def (udat_seg_name, data_class_name, data_size,
3567 FALSE, FALSE);
3568 data_index = seg_def (data_seg_name, data_class_name,
3569 (udat_seg_string == NULL ? data_size : 0),
3570 FALSE, FALSE);
3571 if (udat_seg_string == NULL)
3572 udat_index = data_index;
3573
3574 write_set_segs ();
3575
3576 bss_index = seg_def (bss_seg_name, bss_class_name, a_out_h->a_bss,
3577 FALSE, FALSE);
3578
3579 if (mod_type == MT_MAIN)
3580 stack_index = seg_def (stack_seg_name, stack_class_name, 0x8000, TRUE, FALSE);
3581
3582 if (!strip_symbols && a_out_h->a_syms)
3583 {
3584 convert_debug (); /* After seg_def of text, data & bss */
3585 symbols_index = seg_def (symbols_seg_name, debsym_class_name,
3586 sst.size, FALSE, FALSE);
3587 types_index = seg_def (types_seg_name, debtyp_class_name,
3588 tt.size, FALSE, FALSE);
3589 }
3590
3591 /* Define groups (GRPDEF records). This must be done after defining
3592 segments.
3593 We lazily assumes that the number of sets will not make the GRPDEF
3594 record too big. Rather safe unless a hundred setvectors are used... */
3595
3596 flat_index = group_index++;
3597 init_rec (GRPDEF);
3598 put_idx (flat_group_name);
3599 write_rec ();
3600
3601 dgroup_index = group_index++;
3602 init_rec (GRPDEF);
3603 put_idx (dgroup_group_name);
3604 put_8 (0xff); put_idx (bss_index);
3605 put_8 (0xff); put_idx (data_index);
3606 for (set_ptr = sets; set_ptr != NULL; set_ptr = set_ptr->next)
3607 for (j = 0; j < 3; ++j)
3608 {
3609 put_8 (0xff); put_idx (set_ptr->seg_index[j]);
3610 }
3611 write_rec ();
3612
3613 /* Convert imports and exports. These show up very early in VAC
3614 generated OMF files. */
3615 write_import_i2 ();
3616 write_export ();
3617
3618 /* Define external, communal and public symbols (EXTDEF, WKEXT,
3619 COMDEF, PUBDEF, and ALIAS records). This must be done after
3620 defining the groups. */
3621
3622 write_extdef ();
3623 write_wkext ();
3624 write_comdef ();
3625 write_pubdef ();
3626 write_set_pub ();
3627 write_alias ();
3628
3629 /* Write link pass separator. */
3630
3631 write_pass2 ();
3632
3633 /* Write segment contents (LEDATA and FIXUPP records) and line
3634 number information (LINNUM record). */
3635
3636 write_seg (text_index, text_seg_name, text_ptr, text_size,
3637 text_rel, a_out_h->a_trsize, FALSE, NULL, 0, N_TEXT);
3638 write_seg (udat_index, udat_seg_name, data_ptr, data_size,
3639 data_rel, a_out_h->a_drsize, FALSE, NULL, 0, N_DATA);
3640
3641 write_set_data ();
3642
3643 if (!strip_symbols && a_out_h->a_syms)
3644 {
3645 write_seg (types_index, types_seg_name, tt.buf, tt.size, NULL, 0, FALSE,
3646 tt_boundary, tt_boundary_grow.count, -1);
3647 write_seg (symbols_index, symbols_seg_name, sst.buf, sst.size,
3648 (const struct relocation_info *)sst_reloc.buf, sst_reloc.size, TRUE,
3649 sst_boundary, sst_boundary_grow.count, -1);
3650 write_linnum ();
3651 }
3652
3653 /* End of module. */
3654
3655 init_rec (MODEND|REC32);
3656 if (entry_name != NULL)
3657 {
3658 put_8 (0xc1); /* Main module with start address */
3659 put_8 (0x50); /* ENDDAT: F5, T0 */
3660 put_idx (text_index);
3661 put_32 (entry_symbol->n_value);
3662 }
3663 else
3664 put_8 (0x00); /* Non-main module without start address */
3665 write_rec ();
3666
3667 /* Clean up memory. */
3668
3669 free_lnames ();
3670 free (inp_buf);
3671 free (sym_more);
3672 buffer_free (&tt);
3673 buffer_free (&sst);
3674 buffer_free (&sst_reloc);
3675 grow_free (&sst_boundary_grow);
3676 grow_free (&tt_boundary_grow);
3677 return;
3678
3679read_error:
3680 error ("Cannot read `%s'", error_fname);
3681
3682invalid:
3683 error ("Malformed a.out file `%s'", error_fname);
3684}
3685
3686
3687/* Display some hints on using this program, then quit. */
3688
3689static void usage (void)
3690{
3691 puts ("emxomf " VERSION INNOTEK_VERSION " -- Copyright (c) 1992-1995 by Eberhard Mattes\n");
3692 puts ("Usage:");
3693 puts (" emxomf [-dgqs] [-l[<symbol>]] [-m <symbol>] [-p <page_size>]");
3694 puts (" [-i <default_lib>] [-I <idmdll>] [-D <dataseg>]");
3695 puts (" -o <output_file> <input_file>");
3696 puts (" emxomf [-dgqsx] [-l[<symbol>]] [-m <symbol>] [-p <page_size>]");
3697 puts (" [-O <directory>] [-r|R <response_file>] [-i <default_lib>]");
3698 puts (" [-I <idmdll>] [-D <dataseg>] <input_file>...");
3699 puts ("\nOptions:");
3700 puts (" -d Delete input files except for archives");
3701 puts (" -i <default_lib> Add default library request");
3702 puts (" -l[<symbol>] Convert library modules, with optional entrypoint");
3703 puts (" -m <symbol> Convert main module with entrypoint <symbol>");
3704 puts (" -o <output_file> Write output to <output_file>");
3705 puts (" -p <page_size> Set page size for LIB files");
3706 puts (" -q Suppress certain warnings");
3707 puts (" -r <response_file> Write response file for adding modules");
3708 puts (" -R <response_file> Write response file for replacing modules");
3709 puts (" -s Strip debugging information");
3710 puts (" -u List symbol table entries unknown to emxomf");
3711 puts (" -x Extract archive members");
3712 puts (" -D <dataseg> Change the name of the data segment");
3713 puts (" -I <idmdll> Name the identifier manipulation DLL");
3714 puts (" -O <directory> Extract files to <directory>");
3715 puts (" -z Remove underscores from all symbol names");
3716 puts (" -P <dbgpackdll> Name the dbgpack DLL (ilink)");
3717 exit (1);
3718}
3719
3720
3721/* Create the output file. If the -r or -R option is used, create the
3722 LIB resonse file. */
3723
3724static void open_output (void)
3725{
3726 char *tmp, *p;
3727
3728 out_file = fopen (out_fname, "wb");
3729 if (out_file == NULL)
3730 error ("Cannot create output file `%s'", out_fname);
3731 if (response_file != NULL)
3732 {
3733 if (response_first)
3734 response_first = FALSE;
3735 else
3736 fprintf (response_file, " &\n");
3737 tmp = alloca (strlen (out_fname) + 1);
3738 strcpy (tmp, out_fname);
3739 for (p = tmp; *p != 0; ++p)
3740 if (*p == '/')
3741 *p = '\\';
3742 fprintf (response_file, "%s %s", (response_replace ? "-+" : "+"), tmp);
3743 }
3744}
3745
3746
3747/* Close the output file. Display an error message and quit on
3748 failure. */
3749
3750static void close_output (void)
3751{
3752 if (fflush (out_file) != 0 || fclose (out_file) != 0)
3753 {
3754 out_file = NULL;
3755 error ("Write error on output file `%s'", out_fname);
3756 }
3757 out_file = NULL;
3758}
3759
3760
3761/* Define or build the name of the output file. If DST_FNAME is not
3762 NULL, use it as name of the output file. Otherwise, build the name
3763 from INP_FNAME (the input file name) and EXT (the extension). If
3764 an output directory has been specified with the -O option, remove
3765 the directory part of INP_FNAME and use output_dir instead. */
3766
3767static void make_out_fname (const char *dst_fname, const char *inp_fname,
3768 const char *ext)
3769{
3770 static char tmp1[MAXPATHLEN+3];
3771 char tmp2[MAXPATHLEN+3];
3772
3773 if (dst_fname == NULL)
3774 {
3775 if (*output_dir != 0)
3776 _splitpath (inp_fname, NULL, NULL, tmp2, NULL);
3777 else
3778 _strncpy (tmp2, inp_fname, MAXPATHLEN);
3779 if (strlen (output_dir) + strlen (tmp2) + 5 > MAXPATHLEN)
3780 error ("File name `%s' too long", inp_fname);
3781 strcpy (tmp1, output_dir);
3782 strcat (tmp1, tmp2);
3783 _remext (tmp1);
3784 strcat (tmp1, ext);
3785 out_fname = tmp1;
3786 }
3787 else
3788 out_fname = dst_fname;
3789}
3790
3791
3792/* Read the header of an archive member at file position POS. Return
3793 FALSE when reaching the end of the file. */
3794
3795static int ar_read_header (struct ar_hdr *dst, long pos)
3796{
3797 int size, i;
3798
3799 fseek (inp_file, pos, SEEK_SET);
3800 size = fread (dst, 1, sizeof (struct ar_hdr), inp_file);
3801 if (size == 0)
3802 return FALSE;
3803 else if (size != sizeof (struct ar_hdr))
3804 error ("Malformed archive `%s'", inp_fname);
3805
3806 /* Remove trailing blanks from the member name. */
3807
3808 i = sizeof (dst->ar_name) - 1;
3809 while (i > 0 && dst->ar_name[i-1] == ' ')
3810 --i;
3811 dst->ar_name[i] = 0;
3812 return TRUE;
3813}
3814
3815
3816/* Retrieve the size from the header of an archive member. */
3817
3818static long ar_member_size (const struct ar_hdr *p)
3819{
3820 long size;
3821 char *e;
3822
3823 errno = 0;
3824 size = strtol (p->ar_size, &e, 10);
3825 if (e == p->ar_size || errno != 0 || size <= 0 || *e != ' ')
3826 error ("Malformed archive header in `%s'", inp_fname);
3827 return size;
3828}
3829
3830
3831/* Convert the a.out file SRC_FNAME to an OMF file named DST_FNAME.
3832 If DST_FNAME is NULL, the output file name is derived from
3833 SRC_FNAME. */
3834
3835static void convert (const char *src_fname, const char *dst_fname)
3836{
3837 char tmp1[MAXPATHLEN+3], tmp2[MAXPATHLEN+3];
3838 char *p = NULL, *name, *end;
3839 long size, index;
3840 static char ar_magic[SARMAG+1] = ARMAG;
3841 char ar_test[SARMAG];
3842 struct ar_hdr ar;
3843 long ar_pos;
3844 struct delete *del;
3845 char *long_names = NULL;
3846 size_t long_names_size = 0;
3847
3848 inp_fname = src_fname;
3849 error_fname = inp_fname;
3850 mod_name[0] = 0;
3851 inp_file = fopen (inp_fname, "rb");
3852 if (inp_file == NULL)
3853 error ("Cannot open input file `%s'", inp_fname);
3854
3855 /* Read some bytes from the start of the file to find out whether
3856 this is an archive (.a) file or not. */
3857
3858 if (fread (ar_test, sizeof (ar_test), 1, inp_file) != 1)
3859 error ("Cannot read input file `%s'", inp_fname);
3860
3861 /* Create a LIB response file if requested and not yet done. */
3862
3863 if (response_fname != NULL && response_file == NULL)
3864 {
3865 response_file = fopen (response_fname, "wt");
3866 if (response_file == NULL)
3867 error ("Cannot create response file `%s'", response_fname);
3868 }
3869
3870 /* The rest of this function (save closing the input file) depends
3871 on whether the input file is an archive or not. */
3872
3873 if (memcmp (ar_test, ar_magic, SARMAG) == 0)
3874 {
3875
3876 /* The input file is an archive. We cannot procede if the user
3877 has specified an output file name and wants one OMF file to
3878 be written for each module in the archive (well, we could do
3879 it if there's exactly one module in the archive, but we
3880 don't). */
3881
3882 if (dst_fname != NULL && opt_x)
3883 error ("Cannot process archive if -o and -x are used");
3884 ar_pos = SARMAG;
3885
3886 /* Create an OMF library file (.LIB file) if the -x option is
3887 not given. */
3888
3889 if (!opt_x)
3890 {
3891 /* calculate a page size based on the size of the aout library.
3892 Since we don't yet know the number of files it contains, we'll
3893 assum the converted library isn't more than the double it's size.
3894 Or at least we can hope it's not... */
3895 struct stat s;
3896 int calculated_page_size = page_size;
3897 if (calculated_page_size <= 0)
3898 {
3899 /* For a better calculation we would need the file count. */
3900 calculated_page_size = 16;
3901 if (!stat(src_fname, &s))
3902 {
3903 int cbPage = (s.st_size * 2) / 65536;
3904 /* Don't allow page size larger than 32K since omflib
3905 won't allow that ... */
3906 while ((calculated_page_size < cbPage)
3907 && (calculated_page_size <= 16384))
3908 calculated_page_size <<= 1;
3909 }
3910 }
3911
3912 make_out_fname (dst_fname, inp_fname, ".lib");
3913 out_lib = omflib_create (out_fname, calculated_page_size, lib_errmsg);
3914 if (out_lib == NULL)
3915 error (lib_errmsg);
3916 if (omflib_header (out_lib, lib_errmsg) != 0)
3917 error (lib_errmsg);
3918 }
3919
3920 /* Loop over all the members of the archive. */
3921
3922 while (ar_read_header (&ar, ar_pos))
3923 {
3924 /* Decode the header. */
3925
3926 size = ar_member_size (&ar);
3927 ar_pos += (sizeof (ar) + size + 1) & -2;
3928
3929 if (strcmp (ar.ar_name, "ARFILENAMES/") == 0)
3930 {
3931 size_t i;
3932
3933 /* The "ARFILENAMES/" member contains the long file
3934 names, each one is terminated with a newline
3935 character. Member names starting with a space are
3936 also considered long file names because a leading
3937 space is used for names pointing into the
3938 "ARFILENAMES/" table. Read the "ARFILENAMES/" member
3939 to LONG_NAMES. */
3940
3941 if (size != 0)
3942 {
3943 long_names_size = (size_t)size;
3944 long_names = xmalloc (long_names_size);
3945 size = fread (long_names, 1, long_names_size, inp_file);
3946 if (ferror (inp_file))
3947 error ("Cannot read `%s'", inp_fname);
3948 if (size != long_names_size)
3949 error ("%s: ARFILENAMES/ member is truncated", inp_fname);
3950
3951 /* Replace the newlines with nulls to make
3952 processing a bit more convenient. */
3953
3954 for (i = 0; i < long_names_size; ++i)
3955 if (long_names[i] == '\n')
3956 long_names[i] = 0;
3957 if (long_names[long_names_size-1] != 0)
3958 error ("%s: ARFILENAMES/ member corrupt", inp_fname);
3959 }
3960 }
3961
3962 /* Ignore the __.SYMDEF and __.IMPORT members. Ignore
3963 import modules unless creating a library file. */
3964
3965 else if (strcmp (ar.ar_name, "__.SYMDEF") != 0
3966 && strcmp (ar.ar_name, "__.IMPORT") != 0
3967 && (memcmp (ar.ar_name, "IMPORT#", 7) != 0 || !opt_x))
3968 {
3969
3970 /* Convert the current member to OMF. First, fetch the
3971 name of the member. If the ar_name starts with a
3972 space, the decimal number following that space is an
3973 offset into the "ARFILENAMES/" member. The number
3974 may be followed by a space and a substring of the
3975 long file name. */
3976
3977 name = ar.ar_name;
3978 if (name[0] == ' ' && long_names != NULL
3979 && (index = strtol (name + 1, &end, 10)) >= 0
3980 && index < long_names_size - 1
3981 && (*end == 0 || *end == ' ')
3982 && (index == 0 || long_names[index-1] == 0))
3983 name = long_names + index;
3984
3985 /* Extract the base name of the member. */
3986
3987 _splitpath (name, NULL, NULL, tmp2, NULL);
3988 if (strlen (output_dir) + strlen (tmp2) + 5 > MAXPATHLEN)
3989 error ("File name `%s' too long", tmp2);
3990
3991 /* Provide for informative error message. Memory leak. */
3992
3993 p = xmalloc (strlen (inp_fname) + 3 + strlen (name));
3994 sprintf (p, "%s(%s)", inp_fname, name);
3995 error_fname = p;
3996
3997 /* Construct the module name for the THREADR record
3998 etc. */
3999
4000 _strncpy (mod_name, tmp2, sizeof (mod_name));
4001 strcat (tmp2, ".obj");
4002
4003 /* Create the output file (-x option) or add a new
4004 module to the output library (no -x option). */
4005
4006 if (opt_x)
4007 {
4008 strcpy (tmp1, output_dir);
4009 strcat (tmp1, tmp2);
4010 out_fname = tmp1;
4011 open_output ();
4012 }
4013 else
4014 {
4015 if (omflib_write_module (out_lib, tmp2, &mod_page,
4016 lib_errmsg) != 0)
4017 error (lib_errmsg);
4018 }
4019
4020 /* Convert the member and close the output file. */
4021
4022 o_to_omf (size);
4023 if (opt_x)
4024 close_output ();
4025 }
4026 if (p != NULL) free (p);
4027 }
4028
4029 /* Finish and close the library library if creating a library
4030 file. */
4031
4032 if (!opt_x)
4033 {
4034 if (omflib_finish (out_lib, lib_errmsg) != 0
4035 || omflib_close (out_lib, lib_errmsg) != 0)
4036 error (lib_errmsg);
4037 out_lib = NULL;
4038 }
4039 }
4040 else
4041 {
4042
4043 /* The input file is not an archive. We assume it being an
4044 a.out object file. Get the size of the file for
4045 o_to_omf(). */
4046
4047 if (fseek (inp_file, 0L, SEEK_END) != 0)
4048 error ("Input file `%s' is not seekable", inp_fname);
4049 size = ftell (inp_file);
4050 fseek (inp_file, 0L, SEEK_SET);
4051
4052 /* Convert the file. */
4053
4054 make_out_fname (dst_fname, inp_fname, ".obj");
4055 open_output ();
4056 o_to_omf (size);
4057 close_output ();
4058
4059 /* If input files are to be deleted (-d option), add the current
4060 input file to the list of files to be deleted. */
4061
4062 if (delete_input_files)
4063 {
4064 del = xmalloc (sizeof (struct delete));
4065 del->name = xstrdup (inp_fname);
4066 del->next = files_to_delete;
4067 files_to_delete = del;
4068 }
4069 }
4070 fclose (inp_file);
4071 free_modstr_cache ();
4072 if (long_names != NULL)
4073 free (long_names);
4074}
4075
4076
4077/* Delete all the files stored in the FILES_TO_DELETE list. While
4078 deleting the files, the list elements are deallocated. */
4079
4080static void delete_files (void)
4081{
4082 struct delete *p, *q;
4083
4084 for (p = files_to_delete; p != NULL; p = q)
4085 {
4086 q = p->next;
4087 remove (p->name);
4088 free (p->name);
4089 free (p);
4090 }
4091}
4092
4093
4094/* Main function of emxomf. Parse the command line and perform the
4095 requested actions. */
4096
4097int main (int argc, char *argv[])
4098{
4099 int c, i;
4100 char *opt_o, *opt_O, *tmp;
4101 struct libreq *lrp;
4102
4103 /* Keep emxomf in memory for the number of minutes indicated by the
4104 GCCLOAD environment variable. */
4105
4106 _emxload_env ("GCCLOAD");
4107
4108 /* Get options from the EMXOMFOPT environment variable, expand
4109 response files (@filename) and wildcard (*.o) on the command
4110 line. */
4111
4112 _envargs (&argc, &argv, "EMXOMFOPT");
4113 _response (&argc, &argv);
4114 _wildcard (&argc, &argv);
4115
4116 /* Set default values of some options. */
4117
4118 opt_o = NULL; opt_O = NULL;
4119 opterr = FALSE;
4120
4121 tmp = getenv("EMXOMFLD_TYPE");
4122 if (tmp)
4123 {
4124 if (!stricmp (tmp, "VAC308"))
4125 hll_version = 4;
4126 else if (!stricmp (tmp, "LINK386"))
4127 hll_version = 3;
4128 }
4129
4130 /* Parse the command line options. */
4131
4132 while ((c = getopt_long (argc, argv, "bdD:h:i:jI:m:l::o:P:p:qO:r:R:tsuxwz", NULL, NULL)) != EOF) /* use long for getting optional -l argument working (FLAG_PERMUTE). */
4133 switch (c)
4134 {
4135 case 'b':
4136 force_big = TRUE;
4137 break;
4138 case 'd':
4139 delete_input_files = TRUE;
4140 break;
4141 case 'D':
4142 udat_seg_string = optarg;
4143 break;
4144 case 'h':
4145 hll_version = optarg ? atoi(optarg) : 4;
4146 if (hll_version != 4 && hll_version != 3 && hll_version != 6)
4147 {
4148 printf ("syntax error: Invalid HLL version specified (%d)\n", hll_version);
4149 usage ();
4150 }
4151 break;
4152 case 'i':
4153 lrp = xmalloc (sizeof (*lrp));
4154 lrp->next = NULL;
4155 lrp->name = xstrdup (optarg);
4156 *libreq_add = lrp;
4157 libreq_add = &lrp->next;
4158 break;
4159 case 'I':
4160 if (strcmp (optarg, "-") == 0)
4161 idmdll_name = NULL;
4162 else
4163 idmdll_name = optarg;
4164 break;
4165 case 'l':
4166 if (mod_type != MT_MODULE)
4167 usage ();
4168 mod_type = MT_LIB;
4169 entry_name = optarg;
4170 break;
4171 case 'm':
4172 if (mod_type != MT_MODULE)
4173 usage ();
4174 mod_type = MT_MAIN;
4175 entry_name = optarg;
4176 break;
4177 case 'o':
4178 if (opt_o != NULL || opt_O != NULL)
4179 usage ();
4180 opt_o = optarg;
4181 break;
4182 case 'P':
4183 if (strcmp (optarg, "-") == 0)
4184 dbgpack_name = NULL;
4185 else
4186 dbgpack_name = optarg;
4187 break;
4188 case 'p':
4189 errno = 0;
4190 page_size = (int)strtol (optarg, &tmp, 0);
4191 if (tmp == optarg || errno != 0 || *tmp != 0
4192 || page_size < 16 || page_size > 32768
4193 || (page_size & (page_size - 1)) != 0)
4194 usage ();
4195 break;
4196 case 'q':
4197 quiet = TRUE;
4198 break;
4199 case 'O':
4200 if (opt_o != NULL || opt_O != NULL)
4201 usage ();
4202 opt_O = optarg;
4203 break;
4204 case 'r':
4205 case 'R':
4206 if (response_fname != NULL)
4207 usage ();
4208 response_fname = optarg;
4209 response_replace = (c == 'R');
4210 break;
4211 case 's':
4212 strip_symbols = TRUE;
4213 break;
4214 case 'u':
4215 unknown_stabs = TRUE;
4216 break;
4217 case 'x':
4218 opt_x = TRUE;
4219 break;
4220 case 'z':
4221 opt_rmunder = TRUE;
4222 break;
4223 default:
4224 usage ();
4225 }
4226
4227 /* Check for non-option arguments. */
4228
4229 if (argc - optind == 0)
4230 usage ();
4231
4232 if (opt_o != NULL)
4233 {
4234 /* If the -o option is used, there must be exactly one input
4235 file name. */
4236
4237 if (argc - optind != 1)
4238 usage ();
4239 convert (argv[optind], opt_o);
4240 }
4241 else
4242 {
4243
4244 /* The -o option is not used. If the -O option is used, set up
4245 output_dir. */
4246
4247 if (opt_O != NULL)
4248 {
4249 i = strlen (opt_O);
4250 tmp = xmalloc (i + 2);
4251 strcpy (tmp, opt_O);
4252 if (i > 0 && strchr (":\\/", tmp[i-1]) == NULL)
4253 strcat (tmp, "/");
4254 output_dir = tmp;
4255 }
4256
4257 /* Convert all the files named on the command line. */
4258
4259 for (i = optind; i < argc; ++i)
4260 convert (argv[i], NULL);
4261 }
4262
4263 /* If a LIB response file has been created, finish and close it. */
4264
4265 if (response_file != NULL)
4266 {
4267 if (!response_first)
4268 fprintf (response_file, "\n");
4269 if (fflush (response_file) != 0 || fclose (response_file) != 0)
4270 error ("Write error on response file `%s'", response_fname);
4271 }
4272
4273 /* If the user wants input files to be deleted, delete them now. */
4274
4275 if (delete_input_files)
4276 delete_files ();
4277 return 0;
4278}
Note: See TracBrowser for help on using the repository browser.