]> Shamusworld >> Repos - rln/blob - rln.c
Next try in supporting ar (*.a) archive files.
[rln] / rln.c
1 //
2 // RLN - Reboot's Linker for the Atari Jaguar Console System
3 // RLN.C - Application Code
4 // Copyright (C) 199x, Allan K. Pratt, 2014 Reboot & Friends
5 //
6
7 #include "rln.h"
8
9 unsigned errflag = 0;                           // Error flag, goes TRUE on error
10 unsigned waitflag = 0;                          // Wait for any keypress flag
11 unsigned versflag = 0;                          // Version banner has been shown flag
12 unsigned aflag = 0;                                     // Absolute linking flag
13 unsigned bflag = 0;                                     // Don't remove mulitply def locals flag
14 unsigned cflag = 0;                                     // COF executable
15 unsigned dflag = 0;                                     // Wait for key after link flag
16 unsigned gflag = 0;                                     // Source level debug include flag
17 unsigned lflag = 0;                                     // Add local symbols to output flag
18 unsigned mflag = 0;                                     // Produce symbol load map flag
19 unsigned oflag = 0;                                     // Output filename specified
20 unsigned rflag = 0;                                     // Segment alignment size flag
21 unsigned sflag = 0;                                     // Output only global symbols
22 unsigned vflag = 0;                                     // Verbose flag
23 unsigned wflag = 0;                                     // Show warnings flag
24 unsigned zflag = 0;                                     // Suppress banner flag
25 unsigned pflag, uflag;                          // Unimplemented flags
26 unsigned hd = 0;                                        // Index of next file handle to fill
27 unsigned secalign = 7;                          // Section Alignment (8=phrase)
28 unsigned tbase = 0;                                     // TEXT base address
29 unsigned dbase = 0;                                     // DATA base address
30 unsigned bbase = 0;                                     // BSS base address
31 unsigned textoffset = 0;                        // COF TEXT segment offset
32 unsigned dataoffset = 0;                        // COF DATA segment offset
33 unsigned bssoffset = 0;                         // COF BSS segment offset
34 unsigned displaybanner = 1;                     // Display version banner
35 unsigned symoffset = 0;                         // Symbol table offset in output file
36 unsigned dosymi = 0;                            // Dosym() processing iterator
37 unsigned dbgsymbase = 0;                        // Debug symbol base address
38 //unsigned symtrunc = 0;                        // Symbol truncation -i and -ii
39 int noheaderflag = 0;                           // No header flag for ABS files
40 int hflags;                                                     // Value of the arg to -h option
41 int ttype, dtype, btype;                        // Type flag: 0, -1, -2, -3, -4
42 int tval, dval, bval;                           // Values of these abs bases
43 int hflag[NHANDLES];                            // True for include files
44 int handle[NHANDLES];                           // Open file handles
45 int textsize, datasize, bsssize;        // Cumulative segment sizes
46 char libdir[FARGSIZE * 3];                      // Library directory to search
47 char ofile[FARGSIZE];                           // Output file name (.o)
48 char * name[NHANDLES];                          // Associated file names
49 char * cmdlnexec = NULL;                        // Executable name - pointer to ARGV[0]
50 char * hsym1[SYMLEN];                           // First symbol for include files
51 char * hsym2[SYMLEN];                           // Second symbol for include files
52 struct OFILE * plist = NULL;            // Object image list pointer
53 struct OFILE * plast;                           // Last object image list pointer
54 struct OFILE * olist = NULL;            // Pointer to first object file in list
55 struct OFILE * olast;                           // Pointer to last object file in list
56 char obj_fname[16384][FNLEN];           // Object file names
57 unsigned obj_segsize[16384][3];         // Object file seg sizes; TEXT,DATA,BSS
58 unsigned obj_index = 0;                         // Object file index/count
59 char * arPtr[512];
60 uint32_t arIndex = 0;
61 struct HREC * htable[NBUCKETS];         // Hash table
62 struct HREC * unresolved = NULL;        // Pointer to unresolved hash list
63 struct HREC * lookup(char *);           // Hash lookup
64 char * ost;                                                     // Output symbol table
65 char * ost_ptr;                                         // Output symbol table; current pointer
66 char * ost_end;                                         // Output symbol table; end pointer
67 char * oststr;                                          // Output string table
68 char * oststr_ptr;                                      // Output string table; current pointer
69 char * oststr_end;                                      // Output string table; end pointer
70 int ost_index = 0;                                      // Index of next ost addition
71 int endian;                                                     // Processor endianess
72
73 // Some human readable defines for endianess
74 #define ENDIANNESS_BIG     1
75 #define ENDIANNESS_LITTLE  0
76
77
78 //
79 // Get a Long Word from Memory
80 //
81 uint32_t getlong(uint8_t * src)
82 {
83         uint32_t temp;
84         uint8_t * out;
85
86         out = (uint8_t *)&temp;
87
88         if (endian == ENDIANNESS_BIG)
89         {
90                 *out++ = src[0];
91                 *out++ = src[1];
92                 *out++ = src[2];
93                 *out = src[3];
94         }
95         else
96         {
97                 *out++ = src[3];
98                 *out++ = src[2];
99                 *out++ = src[1];
100                 *out = src[0];
101         }
102
103         return temp;
104 }
105
106
107 //
108 // Put a Long Word into Memory
109 //
110 void putlong(uint8_t * dest, uint32_t val)
111 {
112         *dest++ = (uint8_t)(val >> 24);
113         *dest++ = (uint8_t)(val >> 16);
114         *dest++ = (uint8_t)(val >> 8);
115         *dest = (uint8_t)val;
116 }
117
118
119 //
120 // Get a Word from Memory
121 //
122 uint16_t getword(uint8_t * src)
123 {
124         uint16_t temp;
125         uint8_t * out = (uint8_t *)&temp;
126
127         if (endian == ENDIANNESS_BIG)
128         {
129                 out[0] = src[0];
130                 out[1] = src[1];
131         }
132         else
133         {
134                 out[0] = src[1];
135                 out[1] = src[0];
136         }
137
138         return temp;
139 }
140
141
142 //
143 // Put a Word into Memory
144 //
145 void putword(uint8_t * dest, uint16_t val)
146 {
147         *dest++ = (uint8_t)(val >> 8);
148         *dest = (uint8_t)val;
149 }
150
151
152 //
153 // Find passed in file's length in bytes
154 // N.B.: This also resets the file's pointer to the start of the file
155 //
156 long FileSize(int fd)
157 {
158         long size = lseek(fd, 0, SEEK_END);
159         lseek(fd, 0, SEEK_SET);
160
161         return size;
162 }
163
164
165 //
166 // For this object file, add symbols to the output symbol table after
167 // relocating them. Returns TRUE if ost_lookup returns an error (-1).
168 //
169 int dosym(struct OFILE * ofile)
170 {
171         char * symptr;                          // Symbol pointer
172         char * symend;                          // Symbol end pointer
173         int type;                                       // Symbol type
174         long value;                                     // Symbol value
175         int index;                                      // Symbol index
176         int j;                                          // Iterator
177         int ssidx;                                      // Segment size table index
178         unsigned tsegoffset;            // Cumulative TEXT segment offset
179         unsigned dsegoffset;            // Cumulative DATA segment offset
180         unsigned bsegoffset;            // Cumulative BSS segment offset
181         struct HREC * hptr;                     // Hash table pointer for globl/extrn
182         char sym[SYMLEN];                       // String for symbol name/hash search
183
184         // Point to first symbol record in the object file
185         symptr = (ofile->o_image + 32
186                 + ofile->o_header.tsize
187                 + ofile->o_header.dsize
188                 + ofile->o_header.absrel.reloc.tsize
189                 + ofile->o_header.absrel.reloc.dsize);
190
191         // Point to end of symbol record in the object file
192         symend = symptr + ofile->o_header.ssize;
193
194         // Search through object segment size table to accumulated segment sizes to
195         // ensure the correct offsets are used in the resulting COF file.
196         ssidx = -1;                                                                     // Initialise segment index
197         tsegoffset = dsegoffset = bsegoffset = 0;       // Initialise segment offsets
198
199         // Search for object file name
200         for(j=0; j<(int)obj_index; j++)
201         {
202                 if (!strcmp(ofile->o_name, obj_fname[j]))
203                 {
204                         ssidx = j;                                                      // Object file name found
205                         break;
206                 }
207
208                 tsegoffset += obj_segsize[j][0];                // Accumulate segment sizes
209                 dsegoffset += obj_segsize[j][1];
210                 bsegoffset += obj_segsize[j][2];
211         }
212
213         if (ssidx == -1)
214         {
215                 printf("dosym() : Cannot get object file segment size : %s\n", ofile->o_name);
216                 return 1;
217         }
218
219         // Process each record in the symbol table
220         for(; symptr!=symend; symptr+=12)
221         {
222                 index = getlong(symptr + 0);                    // Obtain symbol string index
223                 type  = getlong(symptr + 4);                    // Obtain symbol type
224                 value = getlong(symptr + 8);                    // Obtain symbol value
225
226                 // Global/External symbols have a pre-processing stage
227                 if (type & 0x01000000)
228                 {
229                         // Obtain the string table index for the relocation symbol, look
230                         // for it in the globals hash table to obtain information on that
231                         // symbol. For the hash calculation to work correctly it must be
232                         // placed in a 'clean' string before looking it up.
233                         memset(sym, 0, SYMLEN);
234                         strcpy(sym, symend + index);
235                         hptr = lookup(sym);
236
237                         if (hptr == NULL)
238                         {
239                                 printf("dosym() : Cannot determine symbol : %s\n", sym);
240                                 return 1;
241                         }
242
243                         // Search through object segment size table to obtain segment sizes
244                         // for the object that has the required external/global as a local
245                         // symbol. As each object is interrogated the segment sizes are
246                         // accumulated to ensure the correct offsets are used in the
247                         // resulting COF file.  This is effectively 'done again' only as we
248                         // are working with a different object file.
249                         ssidx = -1;                                                                     // Initialise segment index
250                         tsegoffset = dsegoffset = bsegoffset = 0;       // Initialise segment offsets
251
252                         for(j=0; j<(int)obj_index; j++)
253                         {              // Search for object filename
254                                 if (!strcmp((const char *)hptr->h_ofile, obj_fname[j]))
255                                 {
256                                         ssidx = j;                                      // Symbol object filename
257                                         break;
258                                 }
259
260                                 tsegoffset += obj_segsize[j][0];                // Accumulate segment sizes
261                                 dsegoffset += obj_segsize[j][1];
262                                 bsegoffset += obj_segsize[j][2];
263                         }
264
265                         if (ssidx == -1)
266                         {
267                                 printf("dosym() : Cannot get object file segment size : %s\n",
268                                         ofile->o_name);
269                                 return 1;
270                         }
271
272                         type = hptr->h_type;                            // Update type with global type
273
274                         if (type == 0x03000000)
275                                 type = 0x02000000;                              // Reset external flag if absolute
276
277                         // If the global/external has a value then update that vaule in
278                         // accordance with the segment sizes of the object file it
279                         // originates from
280                         if (hptr->h_value)
281                         {
282                                 switch (hptr->h_type & 0x0E000000)
283                                 {
284                                 case 0x02000000:                                // Absolute value
285                                 case 0x04000000:                                // TEXT segment
286                                         value = hptr->h_value;
287                                         break;
288                                 case 0x06000000:                                // DATA segment
289                                         value = hptr->h_value - (hptr->h_ofile->o_header.tsize);
290                                         break;
291                                 case 0x08000000:                                // BSS segment
292                                         value = hptr->h_value
293                                                 - (hptr->h_ofile->o_header.tsize + hptr->h_ofile->o_header.dsize);
294                                 break;
295                                 }
296                         }
297                 }
298
299                 // Process and update the value dependant on whether the symbol is a
300                 // debug symbol or not
301                 if (type & 0xF0000000)
302                 {
303                         // DEBUG SYMBOL
304                         // Set the correct debug symbol base address (TEXT segment)
305                         dbgsymbase = 0;
306
307                         for(j=0; (unsigned)j<dosymi; j++)
308                                 dbgsymbase += obj_segsize[j][0];
309
310                         switch (type & 0xFF000000)
311                         {
312                         case 0x64000000:
313                                 value = tval + dbgsymbase;
314                                 break;
315                         case 0x44000000:
316                         case 0x46000000:
317                         case 0x48000000:
318                                 value = tval + dbgsymbase + value;
319                         default:
320                                 break;
321                         }
322
323                         putlong(symptr + 8, value);
324                 }
325                 else
326                 {
327                         // NON-DEBUG SYMBOL
328                         // Now make modifications to the symbol value, local or global,
329                         // based on the segment sizes of the object file currently being
330                         // processed.
331                         switch (type & T_SEG)
332                         {
333                         case 0x02000000:                                // Absolute value
334                                 break;
335                         case T_TEXT:                                    // TEXT segment
336                                 if (type & 0x01000000)
337                                         value = tbase + tsegoffset + value;
338                                 else
339                                         value = tbase + tsegoffset + value;
340
341                                 putlong(symptr + 8, value);
342                                 break;
343                         case T_DATA:                                    // DATA segment
344                                 if (type & 0x01000000)
345                                         value = dbase + dsegoffset + value;
346                                 else
347                                         value = dbase + dsegoffset + (value - ofile->o_header.tsize);
348
349                                 putlong(symptr + 8, value);
350                                 break;
351                         case T_BSS:                                     // BSS segment
352                                 if (type & 0x01000000)
353                                         value = bbase + bsegoffset + value;
354                                 else
355                                         value = bbase + bsegoffset
356                                                 + (value - (ofile->o_header.tsize + ofile->o_header.dsize));
357
358                                 putlong(symptr + 8, value);
359                                 break;
360                         default:
361                                 break;
362                         }
363                 }
364
365                 // Add to output symbol table
366                 if (lflag || !islocal(type))
367                 {
368                         if (islocal(type) || isglobal(type))
369                         {
370                                 if ((index = ost_add(symend + index, type, value)) == -1)
371                                         return 1;
372                         }
373                         else
374                         {
375                                 // Belongs in OST, but don't look it up yet
376                                 index = -1;
377                         }
378                 }
379         }
380
381         // Increment dosym() processsing
382         dosymi++;
383
384         return 0;
385 }
386
387
388 //
389 // Free up hash memory
390 //
391 void hash_free(void)
392 {
393         int i;
394         struct HREC * htemp, * hptr;
395
396         for(i=0; i<NBUCKETS; i++)
397         {
398                 hptr = htable[i];
399
400                 while (hptr)
401                 {
402                         htemp = hptr->h_next;
403                         free(hptr);
404                         hptr = htemp;
405                 }
406         }
407 }
408
409
410 //
411 // Add all Global and External Symbols to the Output Symbol Table
412 //
413 long docommon(void)
414 {
415         struct HREC * hptr;                                                     // Hash record pointer
416         int i;                                                                          // Iterator
417
418         for(i=0; i<NBUCKETS; i++)
419         {
420                 for(hptr=htable[i]; hptr!=NULL; hptr=hptr->h_next)
421                 {
422 //NO!                   if (iscommon(hptr->h_type))
423                         if (isglobal(hptr->h_type) || isextern(hptr->h_type))
424                         {
425                                 if (hptr->h_type == 0x03000000)
426                                         hptr->h_type = 0x02000000;      // Absolutes can't be externals
427
428                                 if (ost_add(hptr->h_sym, hptr->h_type, hptr->h_value) == -1)
429                                         return -1;
430                         }
431                 }
432         }
433
434         return 0;
435 }
436
437
438 //
439 // Add a Symbol's Name, Type, and Value to the OST.
440 // Return the Index of the Symbol in OST, or -1 for Error.
441 //
442 int ost_add(char * name, int type, long value)
443 {
444         int ost_offset_p, ost_offset_e = 0;                     // OST table offsets for position calcs
445         int slen = 0;                                                           // Symbol string length
446         int ostresult;                                                          // OST index result
447
448         slen = strlen(name);
449
450         // If the OST or OST String Table has not been initialised then do so
451         if (ost_index == 0)
452         {
453                 if ((ost = malloc(OST_BLOCK)) == NULL)
454                 {
455                         printf("OST memory allocation error (stringtable).\n");
456                         return -1;
457                 }
458
459                 ost_ptr = ost;                                                  // Set OST start pointer
460                 ost_end = ost + OST_BLOCK;                              // Set OST end pointer
461
462                 if ((oststr = malloc(OST_BLOCK)) == NULL)
463                 {
464                         printf("OST memory allocation error (string).\n");
465                         return -1;
466                 }
467
468                 putlong(oststr, 0x00000004);            // Just null long for now
469                 oststr_ptr = oststr + 4;                        // Skip size of str table long (incl null long)
470                 putlong(oststr_ptr, 0x00000000);        // Null terminating long
471                 oststr_end = oststr + OST_BLOCK;
472         }
473         else
474         {
475                 // If next symbol record exceeds current allocation then expand symbol
476                 // table.
477                 ost_offset_p = (ost_ptr - ost);
478                 ost_offset_e = (ost_end - ost);
479
480                 // 3 x int (12)
481                 if ((ost_ptr + 12) > ost_end)
482                 {
483 #warning "!!! Bad logic in realloc call !!!"
484                         if ((ost = realloc(ost, (ost_end + OST_BLOCK))) == NULL)
485                         {
486                                 printf("OST memory reallocation error.\n");
487                                 return -1;
488                         }
489
490                         ost_ptr = ost + ost_offset_p;
491                         ost_end = (ost + ost_offset_e) + OST_BLOCK;
492                 }
493
494                 ost_offset_p = (oststr_ptr - oststr);
495                 ost_offset_e = (oststr_end - oststr);
496
497                 if ((oststr_ptr + (slen + 1 + 4)) > oststr_end)
498                 {
499 #warning "!!! Bad logic in realloc call !!!"
500                         if ((oststr = realloc(oststr, (oststr_end + OST_BLOCK))) == NULL)
501                         {
502                                 printf("OSTSTR memory reallocation error.\n");
503                                 return -1;
504                         }
505
506                         oststr_ptr = oststr + ost_offset_p;
507                         oststr_end = (oststr + ost_offset_e) + OST_BLOCK;
508                 }
509         }
510
511         // If this is a debug symbol and the include debug symbol flag (-g) is not
512         // set then do nothing
513         if ((type & 0xF0000000) && !gflag)
514         {
515                 // Do nothing
516         }
517         else
518         {
519                 ostresult = ost_lookup(name);           // Get symbol index in OST
520
521                 // If the symbol is in the output symbol table and the bflag is set
522                 // (don't remove multiply defined locals) and this is not an
523                 // external/global symbol *** OR *** the symbol is not in the output
524                 // symbol table then add it.
525                 if (((ostresult != -1) && bflag && !(type & 0x01000000))
526                         || ((ostresult != -1) && gflag && (type & 0xF0000000)) || (ostresult == -1))
527                 {
528                         if ((type & 0xF0000000) == 0x40000000)
529                                 putlong(ost_ptr, 0x00000000);   // Zero string table offset for dbg line
530                         else
531                                 putlong(ost_ptr, (oststr_ptr - oststr));        // String table offset of symbol string
532
533                         putlong(ost_ptr + 4, type );
534                         putlong(ost_ptr + 8, value);
535                         ost_ptr += 12;
536
537                         // If the symbol type is anything but a debug line information
538                         // symbol then write the symbol string to the string table
539                         if ((type & 0xF0000000) != 0x40000000)
540                         {
541                                 strcpy(oststr_ptr, name);               // Put symbol name in string table
542                                 *(oststr_ptr + slen) = '\0';    // Add null terminating character
543                                 oststr_ptr += (slen + 1);
544                                 putlong(oststr_ptr, 0x00000000);        // Null terminating long
545                                 putlong(oststr, (oststr_ptr - oststr)); // Update size of string table
546                         }
547
548                         if (vflag > 1)
549                         {
550                                 printf("ost_add: (%s), type=$%08X, val=$%08X\n", name, type, value);
551                         }
552
553                         return ost_index++;
554                 }
555         }
556
557         // Not sure about this as it could affect return indices. Needed to stop
558         // return error.
559         return 0;
560 }
561
562
563 //
564 // Return the Index of a Symbol in the Output Symbol Table
565 //
566 int ost_lookup(char * sym)
567 {
568         int i;                          // Iterator
569         int stro = 4;           // Offset in string table
570
571         for(i=0; i<ost_index; i++)
572         {
573                 if (strcmp(oststr + stro, sym) == 0)
574                         return i + 1;
575
576                 stro += strlen(oststr + stro) + 1;
577         }
578
579         return -1;
580 }
581
582
583 //
584 // Add Unresolved Externs to the Output Symbol Table
585 //
586 int dounresolved(void)
587 {
588         struct HREC * hptr, * htemp;            // Hash record pointers
589         hptr = unresolved;                                      // Point to unresolved symbols list
590
591         // While unresolved list is valid
592         while (hptr != NULL)
593         {
594                 if (ost_add(hptr->h_sym, T_EXT, 0L) == -1)
595                         return 1;
596
597                 if (vflag > 1)
598                         printf("dounresolved(): added %s\n", hptr->h_sym);
599
600                 htemp = hptr->h_next;                   // Temporarily get ptr to next record
601                 free(hptr);                                             // Free current record
602                 hptr = htemp;                                   // Make next record ptr, current
603         }
604
605         unresolved = NULL;                                      // Zero unresolved record list
606         return 0;
607 }
608
609
610 //
611 // Update Object File TEXT and DATA Segments Based on Relocation Records. Take
612 // in an OFILE header and flag (T_TEXT, T_DATA) to process. Return (0) is
613 // successful or non-zero (1) if failed.
614 //
615 int reloc_segment(struct OFILE * ofile, int flag)
616 {
617         char * symtab;                                  // Start of symbol table
618         char * symbols;                                 // Start of symbols
619         char * sptr;                                    // Start of segment data
620         char * rptr;                                    // Start of segment relocation records
621         unsigned symidx;                                // Offset to symbol
622         unsigned addr;                                  // Relocation address
623         unsigned rflg;                                  // Relocation flags
624         unsigned olddata;                               // Old segment data at reloc address
625         unsigned newdata = 0;                   // New segment data at reloc address
626         unsigned pad;                                   // Temporary to calculate phrase padding
627         int i;                                                  // Iterator
628         char sym[SYMLEN];                               // String for symbol name/hash search
629         int ssidx;                                              // Segment size table index
630         unsigned glblreloc;                             // Global relocation flag
631         unsigned absreloc;                              // Absolute relocation flag
632         unsigned relreloc;                              // Relative relocation flag
633         unsigned swcond;                                // Switch statement condition
634         unsigned relocsize;                             // Relocation record size
635
636         // If there is no TEXT relocation data for the selected object file segment
637         // then update the COF TEXT segment offset allowing for the phrase padding
638         if ((flag == T_TEXT) && !ofile->o_header.absrel.reloc.tsize)
639         {
640                 // TEXT segment size plus padding
641                 pad = ((ofile->o_header.tsize + secalign) & ~secalign);
642                 textoffset += (ofile->o_header.tsize + (pad - ofile->o_header.tsize));
643
644                 if (vflag > 1)
645                         printf("reloc_segment(%s, TEXT) : No Relocation Data\n", ofile->o_name);
646
647                 return 0;
648         }
649
650         // If there is no DATA relocation data for the selected object file segment
651         // then update the COF DATA and BSS segment offsets allowing for the phrase
652         // padding
653         if ((flag == T_DATA) && !ofile->o_header.absrel.reloc.dsize)
654         {
655                 // DATA segment size plus padding
656                 pad = ((ofile->o_header.dsize + secalign) & ~secalign);
657                 dataoffset += (ofile->o_header.dsize + (pad - ofile->o_header.dsize));
658                 // BSS segment size plus padding
659                 pad = ((ofile->o_header.bsize + secalign) & ~secalign);
660                 bssoffset += (ofile->o_header.bsize + (pad - ofile->o_header.bsize));
661
662                 if (vflag > 1)
663                         printf("reloc_segment(%s, DATA) : No Relocation Data\n", ofile->o_name);
664
665                 return 0;
666         }
667
668         // Verbose mode information
669         if (vflag > 1)
670         {
671                 printf("reloc_segment(%s, %s) : Processing Relocation Data\n",
672                         ofile->o_name, flag == T_DATA ? "DATA" : "TEXT");
673         }
674
675         // Obtain pointer to start of symbol table
676         symtab = (ofile->o_image + 32 + ofile->o_header.tsize + ofile->o_header.dsize
677                 + ofile->o_header.absrel.reloc.tsize + ofile->o_header.absrel.reloc.dsize);
678
679         // Obtain pointer to start of symbols
680         symbols = symtab + ofile->o_header.ssize;
681
682         // Obtain pointer to start of TEXT segment
683         sptr = ofile->o_image + 32;
684
685         // Obtain pointer to start of TEXT relocation records
686         rptr = sptr + (ofile->o_header.tsize + ofile->o_header.dsize);
687
688         relocsize = ofile->o_header.absrel.reloc.tsize;
689
690     if (vflag)
691     {
692         printf("RELOCSIZE :: %d  Records = %d\n",relocsize,relocsize/8);
693     }
694
695         // Update pointers if DATA relocation records are being processed
696         if (flag == T_DATA)
697         {
698                 sptr += ofile->o_header.tsize;              // Start of DATA segment
699                 rptr += ofile->o_header.absrel.reloc.tsize; // Start of DATA relocation records
700                 relocsize = ofile->o_header.absrel.reloc.dsize;
701         }
702
703         // Process each relocation record for the TEXT segment
704         for(i=0; i<(int)relocsize; i+=8)
705         {
706                 // Obtain both the relocation address and the relocation flags from the
707                 // object file image
708                 addr = getlong(rptr);
709                 rflg = getlong(rptr + 4);
710                 glblreloc = (rflg & 0x00000010 ? 1 : 0);    // Set global relocation flag
711                 absreloc = (rflg & 0x00000040 ? 1 : 0);     // Set absolute relocation flag
712                 relreloc = (rflg & 0x000000A0 ? 1 : 0);     // Set relative relocation flag
713
714                 // Additional processing required for global relocations
715                 if (glblreloc)
716                 {
717                         // Obtain the string table index for the relocation symbol, look
718                         // for it in the globals hash table to obtain information on that
719                         // symbol. For the hash calculation to work correctly it must be
720                         // placed in a 'clean' string before looking it up.
721                         symidx = getlong(symtab + ((rflg >> 8) * 12));
722                         memset(sym, 0, SYMLEN);
723                         strcpy(sym, symbols + symidx);
724                         olddata = newdata = 0;              // Initialise old and new segment data
725                         ssidx = ost_lookup(sym);
726                         newdata = getlong(ost + ((ssidx - 1) * 12) + 8);
727                 }
728
729                 // Obtain the existing long word segment data and flip words if the
730                 // relocation flags indicate it relates to a RISC MOVEI instruction
731                 olddata = getlong(sptr + addr);
732
733                 if (rflg & 0x01)
734                         olddata = _SWAPWORD(olddata);
735
736                 // Process record dependant on segment it relates to; TEXT, DATA or
737                 // BSS. Construct a new relocated segment long word based on the
738                 // required segment base address, the segment data offset in the
739                 // resulting COF file and the offsets from the incoming object file.
740                 //swcond = glblreloc ? ((hptr->h_type & 0x0E000000) >> 16) : (rflg & 0xFFFFFF00);
741                 swcond = (rflg & 0xFFFFFF00);
742
743                 if (!glblreloc)
744                 {
745                         switch (swcond)
746                         {
747                         case 0x00000200:                    // Absolute Value
748                                 break;
749                         case 0x00000400:                    // TEXT segment relocation record
750 //AARRRGGGGHHHHH! does the else belong to the 1st 'if' or the 2nd?
751 // can we trust the indention to tell the truth here???
752 // Braces were not here, so if something breaks, try pairing the else to the 1st 'if'...
753                                 if (!glblreloc)
754                                 {
755                                         if (flag == T_TEXT)     // Is this a TEXT section record?
756                                                 newdata = tbase + textoffset + olddata;
757                                         else
758                                                 newdata = tbase + dataoffset + olddata; // Nope, must be DATA section
759                                 }
760
761                                 break;
762                         case 0x00000600:                    // DATA segment relocation record
763                                 if (!glblreloc)
764                                         newdata = dbase + dataoffset + (olddata - ofile->o_header.tsize);
765
766                                 break;
767                         case 0x00000800:                    // BSS segment relocation record
768                                 if (!glblreloc)
769                                         newdata = bbase + bssoffset
770                                                 + (olddata - (ofile->o_header.tsize + ofile->o_header.dsize));
771
772                                 break;
773                         }
774                 }
775                 else
776                 {
777                         if (!relreloc)
778                                 newdata += olddata;
779                 }
780
781                 // Set absolute (long) or relative (word) address of symbol
782                 if (absreloc)
783                 {
784                         // Flip the new long word segment data if the relocation record
785                         // indicated a RISC MOVEI instruction and place the resulting data
786                         // back in the COF segment
787                         if (rflg & 0x01)
788                                 newdata = _SWAPWORD(newdata);
789
790                         putlong(sptr + addr, newdata);
791                 }
792                 else if (relreloc)
793                 {
794                         putword(sptr + addr, newdata - tbase - addr - ofile->o_tbase);
795                 }
796
797                 // Shamus: Let's output some info to aid in debugging this crap
798                 if (vflag > 1)
799                 {
800                         char ssiString[128];
801                         ssiString[0] = 0;
802
803                         if (glblreloc)
804                                 sprintf(ssiString, " [ssi:%i]", ssidx);
805
806                         printf("reloc_segment($%08X): %s, $%08X: $%08X => $%08X%s\n", rflg, (glblreloc ? sym : "(LOCAL)"), addr, olddata, getlong(sptr + addr), ssiString);
807                 }
808
809                 rptr += 8;                              // Point to the next relocation record
810         }
811
812         // Update the COF segment offset allowing for the phrase padding.
813         if (flag == T_TEXT)
814         {
815                 // TEXT segment plus padding
816                 pad = ((ofile->o_header.tsize + secalign) & ~secalign);
817                 textoffset += (ofile->o_header.tsize + (pad - ofile->o_header.tsize));
818         }
819         else
820         {
821                 // DATA segment plus padding
822                 pad = ((ofile->o_header.dsize + secalign) & ~secalign);
823                 dataoffset += (ofile->o_header.dsize + (pad - ofile->o_header.dsize));
824                 // BSS segment plus padding
825                 pad = ((ofile->o_header.bsize + secalign) & ~secalign);
826                 bssoffset += (ofile->o_header.bsize + (pad - ofile->o_header.bsize));
827         }
828
829         // Return value, should always be zero
830         return 0;
831 }
832
833
834 //
835 // Add a path character to the end of string 's' if it doesn't already end with
836 // one. The last occurrance of '/' or '\\' in the string is assumed to be the
837 // path character.
838 //
839 void pathadd(char * s)
840 {
841         // And hope to God that there's enough space in the buffer...
842         char pathchar = 0;
843
844         while (*s)
845         {
846                 if (*s == '/' || *s == '\\')
847                         pathchar = *s;
848
849                 s++;
850         }
851
852         s--;
853
854         if (*s == pathchar)
855                 return;
856
857         *++s = pathchar;
858         *++s = 0;
859 }
860
861
862 //
863 // Try to open "name", "name.o", "${libdir}name", "${libdir}name.o". Return the
864 // handle of the file successfully opened. p_name is updated to point to a
865 // malloc()'ed string which is the name which actually got opened. p_name will
866 // return unchanged if the file can't be found.
867 //
868 int tryopen(char ** p_name)
869 {
870         char * name = * p_name;                 // Filename
871         char * tmpbuf, * lastdot;               // Buffer and 'dot' pointers
872         int fd, hasdot;                                 // File descriptor and 'has dot' flag
873
874         // Note that libdir will be an empty string if there is none specified
875         if ((tmpbuf = malloc((long)strlen(name) + strlen(libdir) + 3)) == NULL)
876         {
877                 printf("tryopen() : out of memory\n");
878                 return -1;
879         }
880
881         strcpy(tmpbuf, name);
882         hasdot = ((lastdot = strrchr(tmpbuf, '.')) > strrchr(tmpbuf, '/'))
883                 && (lastdot > strrchr(tmpbuf, '\\'));
884
885         if ((fd = open(tmpbuf, _OPEN_FLAGS)) >= 0)
886                 goto ok;                                        // Try to open file as passed first
887
888         if (!hasdot)
889         {
890                 strcat(tmpbuf, ".o");           // Try to open file with '.o' added
891
892                 if ((fd = open(tmpbuf, _OPEN_FLAGS)) >= 0)
893                         goto ok;
894         }
895
896         // Try the libdir only if the name isn't already anchored
897         if (*name != '/' && *name != '\\' && !strchr(name, ':'))
898         {
899                 strcpy(tmpbuf, libdir);
900                 // Add a trailing path char if there isn't one already
901                 pathadd(tmpbuf);
902                 strcat(tmpbuf, name);
903
904                 if ((fd = open(tmpbuf, _OPEN_FLAGS)) >= 0)
905                         goto ok;
906
907                 if (!hasdot)
908                 {
909                         strcat(tmpbuf, ".o");
910
911                         if ((fd = open(tmpbuf, _OPEN_FLAGS)) >= 0)
912                                 goto ok;
913                 }
914         }
915
916         // Couldn't open file at all
917         return -1;
918
919 // There are worse things... :-P
920 ok:
921         if ((tmpbuf = realloc(tmpbuf, (long)strlen(tmpbuf) + 1)) == NULL)
922         {
923                 printf("tryopen() : out of memory\n");
924                 return -1;
925         }
926
927         *p_name = tmpbuf;
928         return fd;                                              // Return file descriptor
929 }
930
931
932 //
933 // Archive File Use, Needs to be Removed
934 //
935 void put_name(struct OFILE * p)
936 {
937         int flag = *(p->o_arname);
938         printf("%s%s%s", (flag ? (char *)(p->o_arname) : ""), (flag ? ":" : ""), p->o_name);
939 }
940
941
942 //
943 // Collect file names and handles in a buffer so there is less disk activity.
944 // Call dofile with flag FALSE for normal object files and archives.
945 // Call it with flag TRUE and a symbol name for include files (-i).
946 //
947 int dofile(char * fname, int flag, char * sym)
948 {
949         int fd;
950         int temp;
951
952         // Verbose information
953         if (vflag)
954         {
955                 printf("dofile() : `%s' %s", fname, flag ? "INCLUDE" : "NORMAL");
956
957                 if (flag)
958                         printf(" symbol %s", sym);
959
960                 printf("\n");
961         }
962
963         // Reached maximum file handles
964         if (hd == NHANDLES)
965         {
966                 if (ProcessObjectFiles())
967                         return 1;
968         }
969
970         // Attempt to open input file
971         if ((fd = tryopen(&fname)) < 0)
972         {
973                 printf("Cannot find input module %s\n", fname);
974                 return 1;
975         }
976
977         // The file is open; save its info in the handle and name arrays
978         handle[hd] = fd;
979         name[hd] = fname;                       // This is the name from tryopen()
980         hflag[hd] = flag;
981
982         // Include files
983         if (flag)
984         {
985                 temp = strlen(sym);             // Get symbol length
986
987                 // 100 chars is max length of a symbol
988                 if (temp > 99)
989                 {
990                         sym[99] = '\0';
991                         temp = 99;
992                 }
993
994                 // Malloc enough space for two symbols, then build the second one.
995                 // Second one may be one character longer than first
996                 if ((hsym1[hd] = malloc((long)temp + 1)) == NULL
997                         || (hsym2[hd] = malloc((long)temp + 2)) == NULL)
998                 {
999                         printf("dofile() : out of memory for include-file symbols\n");
1000                         return 1;
1001                 }
1002
1003                 strcpy(hsym1[hd], sym);
1004                 strcpy(hsym2[hd], sym);
1005
1006                 if (temp == 99)
1007                 {
1008                         if (sym[99] == 'x')
1009                         {
1010                                 printf("Last char of %s is already 'x': choose another name\n", sym);
1011                                 return 1;
1012                         }
1013
1014                         hsym2[hd][99] = 'x';
1015                 }
1016                 else
1017                 {
1018                         hsym2[hd][temp] = 'x';
1019                         hsym2[hd][temp+1] = '\0';
1020                 }
1021         }
1022
1023         // Increment next handle index
1024         hd++;
1025         // No problems
1026         return 0;
1027 }
1028
1029
1030 //
1031 // Pad TEXT or DATA Segment to the Requested Boundary
1032 //
1033 int segmentpad(FILE * fd, long segsize, int value)
1034 {
1035         long padsize;                            // Number of pad bytes needed
1036         int i;                                   // Good 'ol iterator
1037         char padarray[32];                       // Array of padding bytes
1038         char * padptr;                           // Pointer to array
1039
1040         // Determine the number of padding bytes that are needed
1041         padsize = (segsize + secalign) & ~secalign;
1042         padsize = padsize - segsize;
1043
1044         // Fill pad array if padding is required
1045         if (padsize)
1046         {
1047                 padptr = padarray;
1048
1049                 for(i=0; i<16; i++)
1050                 {
1051                         putword(padptr, value);
1052                         padptr += 2;
1053                 }
1054
1055                 symoffset += padsize;
1056
1057                 if (fwrite(padarray, padsize, 1, fd) != 1) // Write padding bytes
1058                         return 1;
1059         }
1060
1061         return 0;
1062 }
1063
1064
1065 //
1066 // Write the Output File
1067 //
1068 int write_ofile(struct OHEADER * header)
1069 {
1070         FILE * fd;                                                      // File descriptor
1071         unsigned osize;                                         // Object segment size
1072         struct OFILE * otemp;                           // Object file pointer
1073         int i, j;                                                       // Iterators
1074         char himage[0x168];                                     // Header image (COF = 0xA8)
1075         unsigned tsoff, dsoff, bsoff;           // Segment offset values
1076         unsigned index, type, value;            // Symbol table index, type and value
1077         short abstype;                                          // ABS symbol type
1078         char symbol[14];                                        // Symbol record for ABS files
1079         int slen;                                                       // Symbol string length
1080
1081         symoffset = 0;                                          // Initialise symbol offset
1082
1083         // Add correct output extension if none
1084         if (strchr(ofile, '.') == NULL)
1085         {
1086                 if (aflag && cflag)
1087                         strcat(ofile, ".cof");          // COF files
1088                 else if (aflag && !cflag)
1089                         strcat(ofile, ".abs");          // ABS files
1090                 else
1091                         strcat(ofile, ".o");            // Object files (partial linking etc)
1092         }
1093
1094         fd = fopen(ofile, "wb");                        // Attempt to open output file
1095
1096         if (!fd)
1097         {
1098                 printf("Can't open output file %s\n", ofile);   // Error opening output file
1099                 return 1;
1100         }
1101
1102         // Build the output file header
1103         // Absolute (COF) header
1104         if (cflag)
1105         {
1106                 tsoff = dsoff = bsoff = 0xA8;   // Initialises segment offsets
1107
1108                 // Process each object file segment size to obtain a cumulative segment
1109                 // size for both the TEXT and DATA segments
1110                 for(i=0; i<(int)obj_index; i++)
1111                 {
1112                         dsoff += obj_segsize[i][0];     // Adding TEXT segment sizes
1113                         bsoff += obj_segsize[i][0] + obj_segsize[i][1]; // Adding TEXT and DATA segment sizes
1114                 }
1115
1116                 // Currently this only builds a COF absolute file. Conditionals and
1117                 // additional code will need to be added for ABS and partial linking.
1118
1119                 // Build the COF_HDR
1120                 putword(himage + 0,   0x0150               );         // Magic Number (0x0150)
1121                 putword(himage + 2,   0x0003               );         // Sections Number (3)
1122                 putlong(himage + 4,   0x00000000           );         // Date (0L)
1123                 putlong(himage + 8,   dsoff + header->dsize);         // Offset to Symbols Section
1124                 putlong(himage + 12,  ost_index);                     // Number of Symbols
1125                 putword(himage + 16,  0x001C               );         // Size of RUN_HDR (0x1C)
1126                 putword(himage + 18,  0x0003               );         // Executable Flags (3)
1127
1128                 // Build the RUN_HDR
1129                 putlong(himage + 20,  0x00000107           );         // Magic/vstamp
1130                 putlong(himage + 24,  header->tsize        );         // TEXT size in bytes
1131                 putlong(himage + 28,  header->dsize        );         // DATA size in bytes
1132                 putlong(himage + 32,  header->bsize        );         // BSS size in bytes
1133                 putlong(himage + 36,  tbase                );         // Start of executable, normally @TEXT
1134                 putlong(himage + 40,  tbase                );         // @TEXT
1135                 putlong(himage + 44,  dbase                );         // @DATA
1136
1137                 // Build the TEXT SEC_HDR
1138                 putlong(himage + 48,  0x2E746578           );
1139                 putlong(himage + 52,  0x74000000           );         // ".text"
1140                 putlong(himage + 56,  tbase                );         // TEXT START
1141                 putlong(himage + 60,  tbase                );         // TEXT START
1142                 putlong(himage + 64,  header->tsize        );         // TEXT size in bytes
1143                 putlong(himage + 68,  tsoff                );         // Offset to section data in file
1144                 putlong(himage + 72,  0x00000000           );         // Offset to section reloc in file (0L)
1145                 putlong(himage + 76,  0x00000000           );         // Offset to debug lines structures (0L)
1146                 putlong(himage + 80,  0x00000000           );         // Nreloc/nlnno (0L)
1147                 putlong(himage + 84,  0x00000020           );         // SEC_FLAGS: STYP_TEXT
1148
1149                 // Build the DATA SEC_HDR
1150                 putlong(himage + 88,  0x2E646174           );
1151                 putlong(himage + 92,  0x61000000           );         // ".data"
1152                 putlong(himage + 96,  dbase                );         // DATA START
1153                 putlong(himage + 100, dbase                );         // DATA START
1154                 putlong(himage + 104, header->dsize        );         // DATA size in bytes
1155                 putlong(himage + 108, dsoff                );         // Offset to section data in file
1156                 putlong(himage + 112, 0x00000000           );         // Offset to section reloc in file (0L)
1157                 putlong(himage + 116, 0x00000000           );         // Offset to debugging lines structures (0L)
1158                 putlong(himage + 120, 0x00000000           );         // Nreloc/nlnno (0L)
1159                 putlong(himage + 124, 0x00000040           );         // SEC_FLAGS: STYP_DATA
1160
1161                 // Build the BSS SEC_HDR
1162                 putlong(himage + 128, 0x2E627373           );
1163                 putlong(himage + 132, 0x00000000           );         // ".bss"
1164                 putlong(himage + 136, bbase                );         // BSS START
1165                 putlong(himage + 140, bbase                );         // BSS START
1166                 putlong(himage + 144, header->bsize        );         // BSS size in bytes
1167                 putlong(himage + 148, bsoff                );         // Offset to section data in file
1168                 putlong(himage + 152, 0x00000000           );         // Offset to section reloc in file (0L)
1169                 putlong(himage + 156, 0x00000000           );         // Offset to debugging lines structures (0L)
1170                 putlong(himage + 160, 0x00000000           );         // Nreloc/nlnno (0L)
1171                 putlong(himage + 164, 0x00000080           );         // SEC_FLAGS: STYP_BSS
1172
1173                 symoffset = 168;                                      // Update symbol offset
1174         }
1175         // Absolute (ABS) header
1176         else
1177         {
1178                 // Build the ABS header
1179                 putword(himage + 0,   0x601B               );         // Magic Number (0x601B)
1180                 putlong(himage + 2,   header->tsize        );         // TEXT segment size
1181                 putlong(himage + 6,   header->dsize        );         // DATA segment size
1182                 putlong(himage + 10,  header->bsize        );         // BSS segment size
1183                 putlong(himage + 14,  ost_index * 14       );         // Symbol table size (?)
1184                 putlong(himage + 18,  0x00000000           );         //
1185                 putlong(himage + 22,  tbase                );         // TEXT base address
1186                 putword(himage + 26,  0xFFFF               );         // Flags (?)
1187                 putlong(himage + 28,  dbase                );         // DATA base address
1188                 putlong(himage + 32,  bbase                );         // BSS base address
1189
1190                 symoffset = 36;                                       // Update symbol offset
1191         }
1192
1193         // Write the header, but not if noheaderflag
1194         // Absolute (ABS) header
1195         if (!cflag)
1196         {
1197                 if (!noheaderflag)
1198                         if (fwrite(himage, 36, 1, fd) != 1)
1199                                 goto werror;
1200         }
1201         // Absolute (COF) header
1202         else
1203         {
1204                 if (fwrite(himage, 168, 1, fd) != 1)
1205                         goto werror;
1206         }
1207
1208         // Write the TEXT segment of each object file
1209         for(otemp=olist; otemp!=NULL; otemp=otemp->o_next)
1210         {
1211                 osize = otemp->o_header.tsize;
1212
1213                 // Write only if segment has size
1214                 if (osize)
1215                 {
1216                         if (vflag > 1)
1217                                 printf("Writing TEXT Segment of %s\n", otemp->o_name);
1218
1219                         if (fwrite(otemp->o_image + 32, osize, 1, fd) != 1)
1220                                 goto werror;
1221
1222                         // Pad to required alignment boundary
1223                         if (segmentpad(fd, osize, 0x0000))
1224                                 goto werror;
1225
1226                         symoffset += osize;
1227                 }
1228         }
1229
1230         // Write the DATA segment of each object file
1231         for(otemp=olist; otemp!=NULL; otemp=otemp->o_next)
1232         {
1233                 osize = otemp->o_header.dsize;
1234
1235                 // Write only if the segment has size
1236                 if (osize)
1237                 {
1238                         if (vflag > 1)
1239                                 printf("Writing DATA Segment of %s\n", otemp->o_name);
1240
1241                         if (fwrite((otemp->o_image + 32 + otemp->o_header.tsize), osize, 1, fd) != 1)
1242                                 goto werror;
1243
1244                         // Pad to required alignment boundary
1245                         if (segmentpad(fd, osize, 0))
1246                                 goto werror;
1247
1248                         symoffset += osize;
1249                 }
1250         }
1251
1252         if (!noheaderflag)
1253         {
1254                 // Write the symbols table and string table
1255                 // Absolute (COF) symbol/string table
1256                 if (cflag)
1257                 {
1258                         if (header->ssize)
1259                         {
1260                                 if (fwrite(ost, (ost_ptr - ost), 1, fd) != 1) goto werror;
1261                                 if (fwrite(oststr, (oststr_ptr - oststr), 1, fd) != 1) goto werror;
1262                         }
1263                 }
1264                 // Absolute (ABS) symbol/string table
1265                 else
1266                 {
1267                         // The symbol and string table have been created as part of the
1268                         // dosym() function and the output symbol and string tables are in
1269                         // COF format. For an ABS file we need to process through this to
1270                         // create the 14 character long combined symbol and string table.
1271                         // Format of symbol table in ABS: AAAAAAAATTVVVV, where (A)=STRING,
1272                         // (T)=TYPE & (V)=VALUE
1273
1274                         for(i=0; i<ost_index; i++)
1275                         {
1276                                 memset(symbol, 0, 14);                          // Initialise symbol record
1277                                 abstype = 0;                                            // Initialise ABS symbol type
1278                                 slen = 0;                                                       // Initialise symbol string length
1279                                 index = getlong(ost + (i * 12));        // Get symbol index
1280                                 type  = getlong((ost + (i * 12)) + 4);  // Get symbol type
1281
1282                                 if (type & 0xF0000000)
1283                                         continue;                    // Not doing debug symbols
1284
1285                                 value = getlong((ost + (i * 12)) + 8);  // Get symbol value
1286                                 slen = strlen(oststr + index);
1287
1288                                 // Get symbol string (maximum 8 chars)
1289                                 if (slen > 8)
1290                                 {
1291                                         for(j=0; j<8; j++)
1292                                                 *(symbol + j) = *(oststr + index + j);
1293                                 }
1294                                 else
1295                                 {
1296                                         for(j=0; j<slen; j++)
1297                                                 *(symbol + j) = *(oststr + index + j);
1298                                 }
1299
1300                                 // Modify to ABS symbol type
1301                                 switch (type)
1302                                 {
1303                                 case 0x02000000: abstype = (short)ABST_DEFINED;                           break;
1304                                 case 0x04000000: abstype = (short)ABST_DEFINED | ABST_TEXT;               break;
1305                                 case 0x05000000: abstype = (short)ABST_DEFINED | ABST_GLOBAL | ABST_TEXT; break;
1306                                 case 0x06000000: abstype = (short)ABST_DEFINED | ABST_DATA;               break;
1307                                 case 0x07000000: abstype = (short)ABST_DEFINED | ABST_GLOBAL | ABST_DATA; break;
1308                                 case 0x08000000: abstype = (short)ABST_DEFINED | ABST_BSS;                break;
1309                                 case 0x09000000: abstype = (short)ABST_DEFINED | ABST_GLOBAL | ABST_BSS;  break;
1310                                 default:
1311                                         printf("write_ofile: abs, cannot determine symbol type\n");
1312                                         type = 0;
1313                                         break;
1314                                 }
1315
1316                                 putword(symbol + 8, abstype);           // Write back new ABS type
1317                                 putlong(symbol + 10, value);            // Write back value
1318
1319                                 if (fwrite(symbol, 14, 1, fd) != 1) goto werror;    // Write symbol record
1320                         }
1321                 }
1322         }
1323
1324         // Close the file
1325         if (fclose(fd))
1326         {
1327                 printf("Close error on output file %s\n",ofile);
1328                 return 1;
1329         }
1330
1331         return 0;
1332
1333 werror:
1334         printf("Write error on output file %s\n", ofile);
1335         fclose(fd);                     // Try to close output file anyway
1336         return 1;
1337 }
1338
1339
1340 //
1341 // Display the Symbol Load Map
1342 //
1343 int write_map(struct OHEADER * header)
1344 {
1345         unsigned i, o;                  // Inner and outer loop iterators
1346         unsigned c;                             // Column number
1347         unsigned index;                 // Symbol string index
1348         unsigned type;                  // Symbol type
1349         unsigned value;                 // Symbol value
1350         char * symbol;                  // Symbol string value
1351
1352         if (ost_index == 0)
1353                 return 0;                       // Return if no symbols to map
1354
1355         printf("LOAD MAP\n\n");
1356
1357         // Outer loop for each of the symbol areas to map out;
1358         // 0 = NON-RELOCATABLE SYMBOLS
1359         // 1 = TEXT-SEGMENT RELOCATABLE SYMBOLS
1360         // 2 = DATA-SEGMENT RELOCATABLE SYMBOLS
1361         // 3 = BSS-SEGMENT RELOCATABLE SYMBOLS
1362         for(o=0; o<4; o++)
1363         {
1364                 // Display the correct map header for the symbols being processed
1365                 switch (o)
1366                 {
1367                 case 0: printf("NON-RELOCATABLE SYMBOLS\n\n");          break;
1368                 case 1: printf("TEXT-SEGMENT RELOCATABLE SYMBOLS\n\n"); break;
1369                 case 2: printf("DATA-SEGMENT RELOCATABLE SYMBOLS\n\n"); break;
1370                 case 3: printf("BSS-SEGMENT RELOCATABLE SYMBOLS\n\n");  break;
1371                 }
1372
1373                 c = 0;                          // Initialise column number
1374
1375                 // Inner loop to process each record in the symbol table
1376                 for(i=0; i<(unsigned)ost_index; i++)
1377                 {
1378                         index  = getlong(ost + (i * 12));               // Get symbol string index
1379                         type   = getlong(ost + (i * 12) + 4);   // Get symbol type
1380                         value  = getlong(ost + (i * 12) + 8);   // Get symbol value
1381                         symbol = oststr + index;                                // Get symbol string
1382
1383                         // Display only three columns
1384                         if (c == 3)
1385                         {
1386                                 printf("\n");
1387                                 c = 0;
1388                         }
1389
1390                         // If local symbols not included and the type is local then go to
1391                         // next symbol record
1392                         if (!lflag & !(type & 0x01000000))
1393                                 continue;
1394
1395                         // Output each symbol to the display, dependant on type
1396                         switch (o)
1397                         {
1398                         case 0:
1399                                 // Non-relocatable symbols
1400                                 if (type == 0x02000000 || type == 0x03000000)
1401                                 {
1402                                         printf("%-8s %c  %08X   ", symbol, (type & 0x01000000) ? 'G' : 'L', value);
1403                                         c++;
1404                                 }
1405
1406                                 break;
1407                         case 1:
1408                                 // TEXT segment relocatable symbols
1409                                 if (type == 0x04000000 || type == 0x05000000)
1410                                 {
1411                                         printf("%-8s %c  %08X   ", symbol, (type & 0x01000000) ? 'G' : 'L', value);
1412                                         c++;
1413                                 }
1414
1415                                 break;
1416                         case 2:
1417                                 // DATA segment relocatble symbols
1418                                 if (type == 0x06000000 || type == 0x07000000)
1419                                 {
1420                                         printf("%-8s %c  %08X   ", symbol, (type & 0x01000000) ? 'G' : 'L', value);
1421                                         c++;
1422                                 }
1423
1424                                 break;
1425                         case 3:
1426                                 // BSS segment relocatable symbols
1427                                 if (type == 0x08000000 || type == 0x09000000)
1428                                 {
1429                                         printf("%-8s %c  %08X   ", symbol, (type & 0x01000000) ? 'G' : 'L', value);
1430                                         c++;
1431                                 }
1432
1433                                 break;
1434                         }
1435                 }
1436
1437                 printf("\n\n");
1438         }
1439
1440         return 0;
1441 }
1442
1443
1444 //
1445 // Convert ASCII to Hexadecimal
1446 //
1447 //int atolx(char * string, long * value)
1448 int atolx(char * string, int * value)
1449 {
1450         *value = 0;
1451
1452         while (isxdigit(*string))
1453         {
1454                 if (isdigit(*string))
1455                 {
1456                         *value = (*value << 4) + (*string++ - '0');
1457                 }
1458                 else
1459                 {
1460                         if (isupper(*string))
1461                                 *string = tolower(*string);
1462
1463                         *value = (*value << 4) + ((*string++ - 'a') + 10);
1464                 }
1465         }
1466
1467         if (*string != '\0')
1468         {
1469                 printf("Invalid hexadecimal value");
1470                 return 1;
1471         }
1472
1473         return 0;
1474 }
1475
1476
1477 //
1478 // Stuff the (long) value of a string into the value argument. RETURNS TRUE if
1479 // the string doesn't parse.  Parses only as a hex string.
1480 //
1481 int getval(char * string, int * value)
1482 {
1483         return atolx(string, value);
1484 }
1485
1486
1487 //
1488 // Create one big .o file from the images already in memory, returning a
1489 // pointer to an OHEADER. Note that the oheader is just the header for the
1490 // output (plus some other information). The text, data, and fixups are all
1491 // still in the ofile images hanging off the global `olist'.
1492 //
1493 struct OHEADER * make_ofile()
1494 {
1495         unsigned tptr, dptr, bptr;                                      // Bases in runtime model
1496         int ret = 0;                                                            // Return value
1497         struct OFILE * otemp, * oprev, * ohold;         // Object file list pointers
1498         struct OHEADER * header;                                        // Output header pointer
1499
1500         // Initialize cumulative segment sizes
1501         textsize = datasize = bsssize = 0;
1502
1503         // For each object file, accumulate the sizes of the segments but remove
1504         // those object files which are unused
1505         oprev = NULL;                   // Init previous obj file list ptr
1506         otemp = olist;                  // Set temp pointer to object file list
1507
1508         while (otemp != NULL)
1509         {
1510                 // UNUSED !!!!!
1511                 if (!(otemp->o_flags & O_ARCHIVE))
1512                 {
1513                         if ((otemp->o_flags & O_USED) == 0)
1514                         {
1515                                 if (wflag)
1516                                 {
1517                                         printf("Unused object file ");
1518                                         put_name(otemp);
1519                                         printf(" discarded.\n");
1520                                 }
1521
1522                                 if (oprev == NULL)
1523                                 {
1524                                         olist = otemp->o_next;
1525                                 }
1526                                 else
1527                                 {
1528                                         oprev->o_next = otemp->o_next;
1529                                 }
1530
1531                                 ohold = otemp;
1532
1533                                 if (!ohold->isArchiveFile)
1534                                         free(ohold->o_image);
1535
1536                                 free(ohold);
1537                         }
1538                         else
1539                         {
1540                                 // Increment total of segment sizes ensuring requested alignment
1541                                 textsize += (otemp->o_header.tsize + secalign) & ~secalign;
1542                                 datasize += (otemp->o_header.dsize + secalign) & ~secalign;
1543                                 bsssize  += (otemp->o_header.bsize + secalign) & ~secalign;
1544                                 oprev = otemp;
1545                         }
1546                 }
1547
1548                 // Go to next object file list pointer
1549                 otemp = otemp->o_next;
1550         }
1551
1552         // Update base addresses and create symbols _TEXT_E, _DATA_E and _BSS_E
1553         tbase = tval;
1554         ost_add("_TEXT_E", 0x05000000, tval + textsize);
1555
1556         if (!dval)
1557         {
1558                 // DATA follows TEXT
1559                 dbase = tval + textsize;
1560                 ost_add("_DATA_E", 0x07000000, tval + textsize + datasize);
1561
1562                 if (!bval)
1563                 {
1564                         // BSS follows DATA
1565                         bbase = tval + textsize + datasize;
1566                         ost_add("_BSS_E", 0x09000000, tval + textsize + datasize + bsssize);
1567                 }
1568                 else
1569                 {
1570                         // BSS is independant of DATA
1571                         bbase = bval;
1572                         ost_add("_BSS_E", 0x09000000, bval + bsssize);
1573                 }
1574         }
1575         else
1576         {
1577                 // DATA is independant of TEXT
1578                 dbase = dval;
1579                 ost_add("_DATA_E", 0x07000000, dval + datasize);
1580
1581                 if (!bval)
1582                 {
1583                         // BSS follows DATA
1584                         bbase = dval + datasize;
1585                         ost_add("_BSS_E", 0x09000000, dval + datasize + bsssize);
1586                 }
1587                 else
1588                 {
1589                         // BSS is independant of DATA
1590                         bbase = bval;
1591                         ost_add("_BSS_E", 0x09000000, bval + bsssize);
1592                 }
1593         }
1594
1595         // Place each unresolved symbol in the output symbol table
1596         if (dounresolved())
1597                 return NULL;
1598
1599         tptr = 0;                                                               // Initialise base addresses
1600         dptr = 0;
1601         bptr = 0;
1602
1603         // For each file, relocate its symbols and add them to the output symbol table
1604         otemp = olist;
1605         oprev = NULL;
1606
1607         while (otemp != NULL)
1608         {
1609                 otemp->o_tbase = tptr;
1610
1611                 // Do rest only for non-ARCHIVE markers
1612                 if (!(otemp->o_flags & O_ARCHIVE))
1613                 {
1614                         otemp->o_dbase = dptr;
1615                         otemp->o_bbase = bptr;
1616                         tptr += (otemp->o_header.tsize + secalign) & ~secalign;
1617                         dptr += (otemp->o_header.dsize + secalign) & ~secalign;
1618                         bptr += (otemp->o_header.bsize + secalign) & ~secalign;
1619                 }
1620
1621                 // For each symbol, (conditionally) add it to the ost
1622                 // For ARCHIVE markers, this adds the symbol for the file & returns
1623                 if (dosym(otemp))
1624                         return NULL;
1625
1626                 if (otemp->o_flags & O_ARCHIVE)
1627                 {
1628                         // Now that the archive is marked, remove it from list
1629                         if (oprev == NULL)
1630                                 olist = otemp->o_next;
1631                         else
1632                                 oprev->o_next = otemp->o_next;
1633
1634                         ohold = otemp;
1635
1636                         if (ohold->o_image)
1637                                 if (!ohold->isArchiveFile)
1638                                         free(ohold->o_image);
1639
1640                         free(ohold);
1641                 }
1642                 else
1643                 {
1644                         oprev = otemp;
1645                 }
1646
1647                 otemp = otemp->o_next;
1648         }
1649
1650         // Places all the externs, globals etc into the output symbol table
1651         if (docommon() == -1)
1652                 return NULL;
1653
1654         // Create a new output file header
1655         if ((header = new_oheader()) == NULL)
1656         {
1657                 printf("make_ofile: out of memory!\n");
1658                 return NULL;
1659         }
1660
1661         // Fill in the output header. Does not match the actual output but values
1662         // used as reference
1663         header->magic = 0x0150;                     // COF magic number
1664         header->tsize = textsize;                   // TEXT segment size
1665         header->dsize = datasize;                   // DATA segment size
1666         header->bsize = bsssize;                    // BSS segment size
1667         header->ssize = (ost_ptr - ost);            // Symbol table size
1668         header->ostbase = ost;                      // Output symbol table base address
1669
1670         // For each object file, relocate its TEXT and DATA segments. OR the result
1671         // into ret so all files get moved (and errors reported) before returning
1672         // with the error condition
1673         for(otemp=olist; otemp!=NULL; otemp=otemp->o_next)
1674         {
1675                 if (!(otemp->o_flags & O_ARCHIVE))
1676                 {
1677                         ret |= reloc_segment(otemp, T_TEXT);    // TEXT segment relocations
1678                         ret |= reloc_segment(otemp, T_DATA);    // DATA segment relocations
1679                 }
1680         }
1681
1682         hash_free();                                // Done with global symbol hash tables
1683
1684         return (ret ? (struct OHEADER *)NULL : header);
1685 }
1686
1687
1688 //
1689 // Add Symbol to Hash List
1690 //
1691 int add_to_hlist(struct HREC ** hptr, char * sym, struct OFILE * ofile, long value, int type)
1692 {
1693         struct HREC * htemp;                                    // Temporary hash record pointer
1694         int i;
1695
1696         // Attempt to allocate new hash record
1697         if ((htemp = new_hrec()) == NULL)
1698         {
1699                 printf("Out of memory\n");
1700                 return 1;
1701         }
1702
1703         // Shamus: Moar testing...
1704         if (vflag > 1)
1705         {
1706                 printf("add_to_hlist(): hptr=$%08X, sym=\"%s\", ofile=$%08X, value=$%X, type=$%X\n", hptr, sym, ofile, value, type);
1707         }
1708
1709         for(i=0; i<SYMLEN; i++)
1710                 htemp->h_sym[i] = '\0';
1711
1712         strcpy(htemp->h_sym, sym);                              // Populate hash record
1713         htemp->h_ofile = ofile;
1714         htemp->h_value = value;
1715         htemp->h_type = type;
1716
1717         htemp->h_next = *hptr;                                  // Update hash record pointers
1718         *hptr = htemp;
1719
1720         return 0;
1721 }
1722
1723
1724 //
1725 // Add Symbol to the Unresolved Symbols Hash Table
1726 //
1727 add_unresolved(char * sym, struct OFILE * ofile)
1728 {
1729         if (vflag > 1)
1730                 printf("add_unresolved(%s, %s)\n", sym, ofile->o_name);
1731
1732         return add_to_hlist(&unresolved, sym, ofile, 0L, 0);
1733 }
1734
1735
1736 //
1737 // Generate hash value
1738 //
1739 int DoHash(char * s)
1740 {
1741         int i = (s[0] + s[1] + s[2] + s[3] + s[4] + s[5] + s[6] + s[7]  + s[8]
1742                 + s[9] + s[10] + s[11] + s[12] + s[13] + s[14]) % NBUCKETS;
1743         return i;
1744 }
1745
1746
1747 //
1748 // Lookup a symbol in the hash table
1749 //
1750 struct HREC * lookup(char * sym)
1751 {
1752         struct HREC * hptr = htable[DoHash(sym)];       // Hash index to record based on sym
1753         char symbol[SYMLEN];                                            // Temporary symbol storage
1754
1755         memset(symbol, 0, SYMLEN);                                      // Clean string for comparison
1756         strcpy(symbol, sym);
1757
1758         while (hptr != NULL)
1759         {
1760 //This is utter failure...
1761 //              if (symcmp(symbol, hptr->h_sym))  <-- left here for giggles :D  - LinkoVitch
1762                 // Return hash pointer if found
1763                 if (strcmp(symbol, hptr->h_sym) == 0)
1764                         return hptr;
1765
1766                 hptr = hptr->h_next;
1767         }
1768
1769         // Symbol was not found in hash table
1770         return NULL;
1771 }
1772
1773
1774 //
1775 // Add symbol to the hash table
1776 //
1777 int hash_add(char * sym, long type, long value, struct OFILE * ofile)
1778 {
1779         struct HREC * hptr;
1780         int flag = !iscommon(type);
1781
1782         if (vflag > 1)
1783         {
1784                 printf("hash_add(%s,%s,%lx,", sym, ofile->o_name, value);
1785                 printf("%x,%s)\n", (unsigned int)type, (flag ? "GLOBAL" : "COMMON"));
1786         }
1787
1788         if ((hptr = lookup(sym)) == NULL)
1789         {
1790                 return add_to_hlist(&htable[DoHash(sym)], sym, ofile, value, type);
1791         }
1792
1793         // Already there!
1794         if (iscommon(type) && !iscommon(hptr->h_type))
1795         {
1796                 // Mismatch: global came first; warn and keep the global one
1797                 if (wflag)
1798                 {
1799                         printf("Warning: %s: global from ", sym);
1800                         put_name(hptr->h_ofile);
1801                         printf(" used, common from ");
1802                         put_name(ofile);
1803                         printf(" discarded.\n");
1804                 }
1805
1806                 putword(sym + 8, ABST_EXTERN);
1807                 putlong(sym + 10, 0L);
1808         }
1809         else if (iscommon(hptr->h_type) && !iscommon(type))
1810         {
1811                 // Mismatch: common came first; warn and keep the global one
1812                 if (wflag)
1813                 {
1814                         printf("Warning: %s: global from ", sym);
1815                         put_name(ofile);
1816                         printf(" used, common from ");
1817                         put_name(hptr->h_ofile);
1818                         printf(" discarded.\n");
1819                 }
1820
1821                 hptr->h_type = type;
1822                 hptr->h_ofile = ofile;
1823                 hptr->h_value = value;
1824         }
1825         // They're both global
1826         else if (flag)
1827         {
1828                 // Global exported by another ofile; warn and make this one extern
1829                 if (wflag)
1830                 {
1831                         printf("Duplicate symbol %s: ", sym);
1832                         put_name(hptr->h_ofile);
1833                         printf(" used, ");
1834                         put_name(ofile);
1835                         printf(" discarded\n");
1836                 }
1837
1838                 putword(sym + 8, ABST_EXTERN);
1839         }
1840         // They're both common
1841         else
1842         {
1843                 if (hptr->h_value < value)
1844                 {
1845                         hptr->h_value = value;
1846                         hptr->h_ofile = ofile;
1847                 }
1848         }
1849
1850         return 0;
1851 }
1852
1853
1854 //
1855 // Add the imported symbols from this file to unresolved, and the global and
1856 // common symbols to the exported hash table.
1857 //
1858 // Change old-style commons (type == T_EXTERN, value != 0) to new-style ones
1859 // (type == (T_GLOBAL | T_EXTERN)).
1860 //
1861 int add_symbols(struct OFILE * Ofile)
1862 {
1863         long nsymbols;                          // Number of symbols in object file
1864         char * ptr;                                     // Object data base pointer
1865         char * sfix;                            // Symbol fixup table pointer
1866         char * sstr;                            // Symbol string table pointer
1867         long index;                                     // String index
1868         long type;                                      // Symbol type
1869         long value;                                     // Symbol value
1870         struct HREC * hptr;                     // Hash record pointer
1871         char symbol[SYMLEN];
1872
1873         if (vflag > 1)
1874                 printf("Add symbols for file %s\n", Ofile->o_name);
1875
1876         ptr = Ofile->o_image + 32                               // Get base pointer, start of sym fixups
1877                 + Ofile->o_header.tsize
1878                 + Ofile->o_header.dsize
1879                 + Ofile->o_header.absrel.reloc.tsize
1880                 + Ofile->o_header.absrel.reloc.dsize;
1881         sfix = ptr;                                                             // Set symbol fixup pointer
1882         sstr = sfix + Ofile->o_header.ssize;    // Set symbol table pointer
1883         nsymbols = Ofile->o_header.ssize / 12;  // Obtain number of symbols
1884
1885         while (nsymbols)
1886         {
1887                 index = getlong(sfix);                          // Get symbol string index
1888                 type  = getlong(sfix + 4);                      // Get symbol type
1889                 value = getlong(sfix + 8);                      // Get symbol value
1890                 memset(symbol, 0, SYMLEN);
1891                 strcpy(symbol, sstr + index);
1892
1893                 // If this is a global/external
1894                 if (type & T_EXT)
1895                 {
1896                         if ((type - T_EXT))
1897                         {
1898                                 // Then add to hash table
1899                                 if (hash_add(symbol, type, value, Ofile))
1900                                 {
1901                                         return 1;                               // Error if addition failed
1902                                 }
1903                         }
1904                         else
1905                         {
1906                                 // If value is zero and in hash table
1907                                 if ((hptr = lookup(symbol)) != NULL)
1908                                 {
1909                                         hptr->h_ofile->o_flags |= O_USED;       // Mark symbol as used
1910                                 }
1911                                 // Otherwise add to unresolved list
1912                                 else if (add_unresolved(symbol, Ofile))
1913                                 {
1914                                         return 1;                               // Error if addition failed
1915                                 }
1916                         }
1917                 }
1918
1919                 sfix += 12;                                                     // Increment symbol fixup pointer
1920                 nsymbols--;                                                     // Decrement num of symbols to process
1921         }
1922
1923         // Success loading symbols
1924         return 0;
1925 }
1926
1927
1928 //
1929 // Process object file for symbols
1930 //
1931 int doobj(char * fname, char * ptr, char * aname, int flags)
1932 {
1933         struct OFILE * Ofile;           // Object record pointer
1934         char * temp;                            // Temporary data pointer
1935
1936         // Allocate memory for object record ptr
1937         if ((Ofile = new_ofile()) == NULL)
1938         {
1939                 printf("Out of memory processing %s\n",fname);
1940                 return 1;
1941         }
1942
1943         // Starting after all pathnames, etc., copy .o file name to Ofile
1944         temp = path_tail(fname);
1945
1946         // Check filename length
1947         if (strlen(temp) > FNLEN - 1)
1948         {
1949                 printf("File name too long: %s\n", temp);
1950                 return 1;
1951         }
1952
1953         // Check archive name length
1954         if (strlen(aname) > FNLEN - 1)
1955         {
1956                 printf("Archive name too long: %s\n", aname);
1957                 return 1;
1958         }
1959
1960         strcpy(Ofile->o_name, temp);            // Store filename
1961         strcpy(Ofile->o_arname, aname);         // Store archive name
1962
1963         Ofile->o_next  = NULL;                          // Initialise object record information
1964         Ofile->o_tbase = 0;
1965         Ofile->o_dbase = 0;
1966         Ofile->o_bbase = 0;
1967         Ofile->o_flags = flags;
1968         Ofile->o_image = ptr;
1969         Ofile->isArchiveFile = 0;
1970
1971         // Don't do anything if this is just an ARCHIVE marker, just add the file
1972         // to the olist
1973         if (!(flags & O_ARCHIVE))
1974         {
1975                 Ofile->o_header.magic = getlong(ptr);
1976                 Ofile->o_header.tsize = getlong(ptr+4);
1977                 Ofile->o_header.dsize = getlong(ptr+8);
1978                 Ofile->o_header.bsize = getlong(ptr+12);
1979                 Ofile->o_header.ssize = getlong(ptr+16);
1980                 Ofile->o_header.absrel.reloc.tsize = getlong(ptr+24);
1981                 Ofile->o_header.absrel.reloc.dsize = getlong(ptr+28);
1982
1983                 // Round BSS off to alignment boundary
1984                 Ofile->o_header.bsize = (Ofile->o_header.bsize + secalign) & ~secalign;
1985
1986                 if ((Ofile->o_header.dsize & 7) && wflag)
1987                 {
1988                         printf("Warning: data segment size of ");
1989                         put_name(Ofile);
1990                         printf(" is not a phrase multiple\n");
1991                 }
1992
1993                 // Check for odd segment sizes
1994                 if ((Ofile->o_header.tsize & 1) || (Ofile->o_header.dsize & 1)
1995                         || (Ofile->o_header.bsize & 1))
1996                 {
1997                         printf("Error: odd-sized segment in ");
1998                         put_name(Ofile);
1999                         printf("; link aborted.\n");
2000                         return 1;
2001                 }
2002
2003                 if (add_symbols(Ofile))
2004                         return 1;
2005         }
2006
2007         // Add this file to the olist
2008         if (olist == NULL)
2009                 olist = Ofile;
2010         else
2011                 olast->o_next = Ofile;
2012
2013         olast = Ofile;
2014         return 0;
2015 }
2016
2017
2018 //
2019 // Remove elements from unresolved list which are resolvable
2020 //
2021 int dolist(void)
2022 {
2023         struct HREC * uptr;                             // Unresolved hash record pointer
2024         struct HREC * prev = NULL;              // Previous hash record pointer
2025         struct HREC * htemp;                    // Temporary hash record pointer
2026         struct OFILE * ptemp;                   // Temporary object file record pointer
2027
2028         // Process object file list
2029         while (plist != NULL)
2030         {
2031                 if (doobj(plist->o_name, plist->o_image, plist->o_arname, plist->o_flags))
2032                         return 1;
2033
2034                 ptemp = plist;
2035                 plist = plist->o_next;
2036                 free(ptemp);
2037         }
2038
2039         // Process unresolved list
2040         for(uptr=unresolved; uptr!=NULL; )
2041         {
2042                 if (vflag > 1)
2043                         printf("lookup(%s) => ", uptr->h_sym);
2044
2045                 if ((htemp = lookup(uptr->h_sym)) != NULL)
2046                 {
2047                         if (vflag > 1)
2048                                 printf("%s in %s (=$%06X)\n", (isglobal(htemp->h_type) ? "global" : "common"), htemp->h_ofile->o_name, htemp->h_value);
2049
2050                         htemp->h_ofile->o_flags |= O_USED;
2051
2052                         if (prev == NULL)
2053                         {
2054                                 unresolved = uptr->h_next;
2055                                 free(uptr);
2056                                 uptr = unresolved;
2057                         }
2058                         else
2059                         {
2060                                 prev->h_next = uptr->h_next;
2061                                 free(uptr);
2062                                 uptr = prev->h_next;
2063                         }
2064                 }
2065                 else
2066                 {
2067                         if (vflag > 1)
2068                                 printf("NULL\n");
2069
2070                         prev = uptr;
2071                         uptr = uptr->h_next;
2072                 }
2073         }
2074
2075         return 0;
2076 }
2077
2078
2079 //
2080 // Extract filename from path
2081 //
2082 char * path_tail(char * name)
2083 {
2084         char * temp = strrchr(name, PATH_DELIMITER);
2085
2086         // Return what was passed in if path delimiter was not found
2087         if (temp == NULL)
2088                 return name;
2089
2090         return temp + 1;
2091 }
2092
2093
2094 //
2095 // Add input file to processing list
2096 //
2097 int AddToProcessingList(char * ptr, char * fname, uint8_t arFile)
2098 {
2099         if (plist == NULL)
2100         {
2101                 plist = new_ofile();                    // First time object record allocation
2102                 plast = plist;                                  // Update last object record pointer
2103         }
2104         else
2105         {
2106                 plast->o_next = new_ofile();    // Next object record allocation
2107                 plast = plast->o_next;                  // Update last object record pointer
2108         }
2109
2110         if (plast == NULL)
2111         {
2112                 printf("Out of memory.\n");             // Error if memory allocation fails
2113                 return 1;
2114         }
2115
2116         if (strlen(path_tail(fname)) > FNLEN - 1)
2117         {
2118                 // Error on excessive filename length
2119                 printf("File name too long: %s (sorry!)\n", fname);
2120                 return 1;
2121         }
2122
2123         strcpy(plast->o_name, path_tail(fname));        // Store filename, not path
2124         *plast->o_arname = 0;                           // No archive name for this file
2125         plast->o_image = ptr;                           // Store data pointer
2126         plast->o_flags = O_USED;                        // File is used
2127         plast->o_next = NULL;                           // Initialise next record pointer
2128         plast->isArchiveFile = arFile;          // Shamus: Temp until can sort out
2129
2130         return 0;                                                       // Return without errors
2131 }
2132
2133
2134 //
2135 // Process in Binary Include Files and Add them to the Processing List. This
2136 // routine takes in the binary file and creates an 'object' file in memory.
2137 // Sym1/Sym2 point to the start and end of data.
2138 //
2139 // Image size for include files is:
2140 // Header ....... 32 bytes
2141 // Data ......... dsize
2142 // Sym Fixups ... 2 * 12 bytes
2143 // Symbol Size .. 4 bytes (Value to include symbols and terminating null)
2144 // Symbols ...... (strlen(sym1) + 1) + (strlen(sym2) + 1)
2145 // Terminate .... 4 bytes (0x00000000)
2146 //
2147 int doinclude(char * fname, int handle, char * sym1, char * sym2, int segment)
2148 {
2149         long fsize, dsize, size;              // File, DATA segment and image sizes
2150         char * ptr, * sptr;                   // Data pointers
2151         int i;                                // Iterators
2152         int sym1len = 0;                      // Symbol 1 length
2153         int sym2len = 0;                      // Symbol 2 length
2154         unsigned symtype = 0;
2155
2156         fsize = FileSize(handle);             // Get size of include file
2157         dsize = (fsize + secalign) & ~secalign; // Round up to a alignment boundary
2158
2159         sym1len = strlen(sym1) + 1;           // Get sym1 length + null termination
2160         sym2len = strlen(sym2) + 1;           // Get sym2 length + null termination
2161
2162         size = 32 + dsize + 24 + 4 + sym1len + sym2len + 4;
2163
2164         // Use calloc so the header & fixups initialize to zero
2165         // Allocate object image memory
2166         if ((ptr = calloc(size, 1L)) == NULL)
2167         {
2168                 printf("Out of memory while including %s\n", fname);
2169                 close(handle);
2170                 return 1;
2171         }
2172
2173         // Read in binary data
2174         if (read(handle, ptr + 32, fsize) != fsize)
2175         {
2176                 printf("File read error on %s\n", fname);
2177                 close(handle);
2178                 free(ptr);
2179                 return 1;
2180         }
2181
2182         close(handle);
2183
2184         strcpy(obj_fname[obj_index], path_tail(fname));
2185
2186         // Build this image's dummy header
2187         putlong(ptr, 0x00000107);              // Magic number
2188
2189         if (segment)
2190         {
2191                 putlong(ptr+4, dsize);             // Text size
2192                 putlong(ptr+8, 0L);                // Data size
2193                 symtype = 0x05000000;
2194                 obj_segsize[obj_index][0] = dsize;
2195                 obj_segsize[obj_index][1] = 0;
2196                 obj_segsize[obj_index][2] = 0;
2197         }
2198         else
2199         {
2200                 putlong(ptr+4, 0L);                // Text size
2201                 putlong(ptr+8, dsize);             // Data size
2202                 symtype = 0x07000000;
2203                 obj_segsize[obj_index][0] = 0;
2204                 obj_segsize[obj_index][1] = dsize;
2205                 obj_segsize[obj_index][2] = 0;
2206         }
2207
2208         obj_index++;                           // Increment object count
2209
2210         putlong(ptr+12, 0L);                   // BSS size
2211         putlong(ptr+16, 24);                   // Symbol table size
2212         putlong(ptr+20, 0L);                   // Entry point
2213         putlong(ptr+24, 0L);                   // TEXT relocation size
2214         putlong(ptr+28, 0L);                   // DATA relocation size
2215
2216         sptr = ptr + 32 + dsize;               // Set sptr to symbol table location
2217
2218         putlong(sptr,    4L);                  // String offset of symbol1
2219         putlong(sptr+4,  symtype);             // Symbol type
2220         putlong(sptr+8,  0x00000000);          // Symbol has no value (START)
2221         putlong(sptr+12, 4L + (sym2len - 1));  // String offset of symbol2
2222         putlong(sptr+16, symtype);             // Symbol type
2223         putlong(sptr+20, dsize);               // Symbol is data size (END)
2224
2225         sptr = ptr + 32 + dsize + 24;          // Set sptr to symbol table size loc
2226
2227         putlong(sptr, sym1len + 4L);           // Size of symbol table
2228
2229         sptr = ptr + 32 + dsize + 24 + 4;      // Set sptr to symbol table location
2230
2231         for(i=0; i<(sym1len-1); i++)           // Write symbol1 to string table
2232                 sptr[i] = *sym1++;
2233
2234         sptr += (sym1len - 1);                 // Step past symbol string
2235         *sptr = '\0';                          // Terminate symbol string
2236         sptr += 1;                             // Step past termination
2237
2238         for(i=0; i<(sym2len-1); i++)           // Write symbol2 to string table
2239                 sptr[i] = *sym2++;
2240
2241         sptr += (sym2len - 1);                 // Step past symbol string
2242         *sptr = '\0';                          // Terminate symbol string
2243         sptr += 1;                             // Step past termination
2244
2245         putlong(sptr, 0L);                     // Terminating long for object file
2246
2247         return AddToProcessingList(ptr, fname, 0);
2248 }
2249
2250
2251 //
2252 // Takes a file name, gets in its image, puts it on plist. The image may
2253 // already be in memory: If so, the ptr arg is non-null.  If so, the file is
2254 // already closed. Note that the file is already open (from dofile()). RETURNS
2255 // a pointer to the OFILE structure for this file, so you can diddle its flags
2256 // (dofile sets O_USED for files on the command line).
2257 //
2258 int DoObject(char * fname, int fd, char * ptr)
2259 {
2260         if (ptr == NULL)
2261         {
2262                 long size = FileSize(fd);
2263
2264                 // Allocate memory for file data
2265                 if ((ptr = malloc(size)) == NULL)
2266                 {
2267                         printf("Out of memory while processing %s\n", fname);
2268                         close(fd);
2269                         return 1;
2270                 }
2271
2272                 // Read in file data
2273                 if (read(fd, ptr, size) != size)
2274                 {
2275                         printf("File read error on %s\n", fname);
2276                         close(fd);
2277                         free(ptr);
2278                         return 1;
2279                 }
2280
2281                 // SCPCD : get the name of the file instead of all pathname
2282                 strcpy(obj_fname[obj_index], path_tail(fname));
2283                 obj_segsize[obj_index][0] = (getlong(ptr + 4) + secalign) & ~secalign;
2284                 obj_segsize[obj_index][1] = (getlong(ptr + 8) + secalign) & ~secalign;
2285                 obj_segsize[obj_index][2] = (getlong(ptr + 12) + secalign) & ~secalign;
2286                 obj_index++;
2287
2288                 close(fd);                                            // Close file
2289         }
2290
2291         // Now add this image to the list of pending ofiles (plist)
2292         // This routine is shared by doinclude after it builds the image
2293         return AddToProcessingList(ptr, fname, 0);
2294 }
2295
2296
2297 //
2298 // What it says on the tin: check for a .o suffix on the passed in string
2299 //
2300 uint8_t HasDotOSuffix(char * s)
2301 {
2302         char * temp = strrchr(s, '.');
2303
2304         if ((temp == NULL) || (strncmp(temp, ".o", 2) != 0))
2305                 return 0;
2306
2307         return 1;
2308 }
2309
2310
2311 //
2312 // Process an ar archive file (*.a)
2313 //
2314 int DoArchive(char * fname, int fd)
2315 {
2316         // Read in the archive file to memory and process
2317         long size = FileSize(fd);
2318         char * ptr = malloc(size);
2319         char * endPtr = ptr + size;
2320
2321         if (ptr == NULL)
2322         {
2323                 printf("Out of memory while processing %s\n", fname);
2324                 close(fd);
2325                 return 1;
2326         }
2327
2328         if (read(fd, ptr, size) != size)
2329         {
2330                 printf("File read error on %s\n", fname);
2331                 close(fd);
2332                 free(ptr);
2333                 return 1;
2334         }
2335
2336         close(fd);
2337
2338         // Save the pointer for later...
2339         arPtr[arIndex++] = ptr;
2340         char objName[17];
2341         char objSize[11];
2342         int i;
2343 //printf("\nProcessing AR file \"%s\"...\n", fname);
2344         ptr += 8;
2345
2346         // Loop through all objects in the archive and process them
2347         do
2348         {
2349                 memset(objName, 0, 17);
2350                 objSize[10] = 0;
2351
2352                 for(i=0; i<16; i++)
2353                 {
2354                         if ((ptr[i] == '/') || (ptr[i] == ' '))
2355                         {
2356                                 objName[i] = 0;
2357                                 break;
2358                         }
2359
2360                         objName[i] = ptr[i];
2361                 }
2362
2363                 for(i=0; i<10; i++)
2364                 {
2365                         if (ptr[48 + i] == ' ')
2366                         {
2367                                 objSize[i] = 0;
2368                                 break;
2369                         }
2370
2371                         objSize[i] = ptr[48 + i];
2372                 }
2373
2374                 if (HasDotOSuffix(objName))
2375                 {
2376 //printf("Processing object \"%s\" (size == %i, obj_index == %i)...\n", objName, atoi(objSize), obj_index);
2377                         strcpy(obj_fname[obj_index], objName);
2378                         obj_segsize[obj_index][0] = (getlong(ptr + 60 + 4) + secalign) & ~secalign;
2379                         obj_segsize[obj_index][1] = (getlong(ptr + 60  + 8) + secalign) & ~secalign;
2380                         obj_segsize[obj_index][2] = (getlong(ptr + 60  + 12) + secalign) & ~secalign;
2381                         obj_index++;
2382
2383                         if (AddToProcessingList(ptr + 60, objName, 1))
2384                                 return 1;
2385                 }
2386
2387                 uint32_t size = atoi(objSize);
2388                 size += (size & 0x01 ? 1 : 0);
2389                 ptr += 60 + size;
2390         }
2391         while (ptr < endPtr);
2392
2393         return 0;
2394 }
2395
2396
2397 //
2398 // Process files (*.o, *.a) passed in on the command line
2399 //
2400 int ProcessObjectFiles(void)
2401 {
2402         int i;                          // Iterator
2403         char magic[8];          // Magic header number
2404
2405         // Process all handles
2406         for(i=0; i<(int)hd; i++)
2407         {
2408                 // Verbose mode information
2409                 if (vflag == 1)
2410                 {
2411                         printf("Read file %s%s\n", name[i], hflag[i] ? " (include)" : "");
2412                 }
2413
2414                 if (!hflag[i])
2415                 {
2416                         // Attempt to read file magic number
2417                         // OBJECT/ARCHIVE FILES 
2418                         if (read(handle[i], magic, 8) != 8)
2419                         {
2420                                 printf("Error reading file %s\n", name[i]);
2421                                 close(handle[i]);
2422                                 return 1;
2423                         }
2424
2425                         lseek(handle[i], 0L, 0);        // Reset to start of input file
2426
2427                         // Look for RMAC/MAC/GCC ($20107) object files
2428                         if ((getlong(magic) == 0x00000107) || (getlong(magic) == 0x00020107))
2429                         {
2430                                 // Process input object file
2431                                 if (DoObject(name[i], handle[i], 0L))
2432                                         return 1;
2433                         }
2434                         // Otherwise, look for an object archive file
2435                         else if (strncmp(magic, "!<arch>\x0A", 8) == 0)
2436                         {
2437                                 if (DoArchive(name[i], handle[i]))
2438                                         return 1;
2439                         }
2440                         else
2441                         {
2442                                 // Close file and error
2443                                 printf("%s is not a supported object or archive file\n", name[i]);
2444 #if 0
2445 printf("Magic number: [ ");
2446 for(i=0; i<8; i++)
2447         printf("%02X ", (uint8_t)magic[i]);
2448 printf("]\n");
2449 #endif
2450                                 close(handle[i]);
2451                                 return 1;
2452                         }
2453                 }
2454                 else
2455                 {
2456                         // INCLUDE FILES
2457                         // If hflag[i] is 1, include this in the data segment; if 2, put it
2458                         // in text segment
2459                         if (doinclude(name[i], handle[i], hsym1[i], hsym2[i], hflag[i] - 1))
2460                                 return 1;
2461                 }
2462         }
2463
2464         // Free include, symbol & object handles
2465         for(i=0; i<(int)hd; i++)
2466         {
2467                 free(name[i]);
2468
2469                 if (hflag[i])
2470                 {
2471                         free(hsym1[i]);
2472                         free(hsym2[i]);
2473                 }
2474         }
2475
2476         // Reset next handle indicator
2477         hd = 0;
2478         return 0;
2479 }
2480
2481
2482 //
2483 // Load newargv with pointers to arguments found in the buffer
2484 //
2485 int parse(char * buf, char * newargv[])
2486 {
2487         int i = 1;
2488
2489         if (vflag)
2490                 printf("begin parsing\n");
2491
2492         while (1)
2493         {
2494                 while (*buf && strchr(",\t\n\r\14 ", *buf))
2495                         buf++;
2496
2497                 /* test for eof */
2498                 if (*buf == '\0' || *buf == 26)
2499                 {
2500                         if (i == 0)
2501                         {
2502                                 printf("No commands in command file\n");
2503                                 return -1;
2504                         }
2505                         else
2506                         {
2507                                 return i;
2508                         }
2509                 }
2510
2511                 /* test for comment */
2512                 if (*buf == '#')
2513                 {
2514                         /* found a comment; skip to next \n and start over */
2515                         while (*buf && *buf != '\n')
2516                                 buf++;
2517
2518                         continue;
2519                 }
2520
2521                 if (i == MAXARGS)
2522                 {
2523                         printf("Too many arguments in command file\n");
2524                         return -1;
2525                 }
2526
2527                 newargv[i] = buf;
2528
2529                 while (!strchr(",\t\n\r\14 ", *buf))
2530                 {
2531                         if (*buf == '\0' || *buf == 26)
2532                         {
2533                                 printf("Finished parsing %d args\n", i);
2534                                 return i;
2535                         }
2536
2537                         buf++;
2538                 }
2539
2540                 *buf++ = '\0';
2541
2542                 if (vflag)
2543                         printf("argv[%d] = \"%s\"\n", i, newargv[i]);
2544
2545                 i++;
2546         }
2547 }
2548
2549
2550 //
2551 // Process in a Link Command File
2552 //
2553 int docmdfile(char * fname)
2554 {
2555         int fd;                                     // File descriptor
2556         unsigned size;                              // Command file size
2557         char * ptr;                                 // Pointer
2558         int newargc;                                // New argument count
2559         char * (*newargv)[];                        // New argument value array
2560
2561         // Verbose information
2562         if (vflag > 1)
2563                 printf("docmdfile(%s)\n", fname);
2564
2565         // Allocate memory for new argument values
2566         newargv = malloc((long)(sizeof(char *) * MAXARGS));
2567
2568         if (!newargv)
2569         {
2570                 printf("Out of memory.\n");
2571                 return 1;
2572         }
2573
2574         // Attempt to open and read in the command file
2575         if (fname)
2576         {
2577                 if ((fd = open(fname, _OPEN_FLAGS)) < 0)
2578                 {
2579                         printf("Cannot open command file %s.\n", fname);
2580                         return 1;
2581                 }
2582
2583                 size = FileSize(fd);
2584
2585                 if ((ptr = malloc(size + 1)) == NULL)
2586                 {
2587                         printf("Out of memory.\n");
2588                         close(fd);
2589                         return 1;
2590                 }
2591
2592                 if (read(fd, ptr, size) != (int)size)
2593                 {
2594                         printf("Read error on command file %s.\n", fname);
2595                         close(fd);
2596                         return 1;
2597                 }
2598
2599                 *(ptr + size) = 0;                      // Null terminate the buffer
2600                 close(fd);
2601         }
2602         else
2603         {
2604                 printf("No command filename specified\n");
2605                 return 1;
2606         }
2607
2608         // Parse the command file
2609         if ((newargc = parse(ptr, *newargv)) == -1)
2610         {
2611                 return 1;
2612         }
2613
2614         // Process the inputted flags
2615         if (doargs(newargc, *newargv))
2616         {
2617                 printf("docmdfile: doargs returns TRUE\n");
2618                 return 1;
2619         }
2620
2621         free(ptr);
2622         free(newargv);
2623
2624         return 0;
2625 }
2626
2627
2628 //
2629 // Take an Argument List and Parse the Command Line
2630 //
2631 int doargs(int argc, char * argv[])
2632 {
2633         int i = 1;                                      // Iterator
2634         int c;                                          // Command line character
2635         char * ifile, * isym;           // File name and symbol name for -i
2636
2637         // Parse through option switches & files
2638         while (i < argc)
2639         {
2640                 // Process command line switches
2641                 if (argv[i][0] == '-')
2642                 {
2643                         if (!argv[i][1])
2644                         {
2645                                 printf("Illegal option argument: %s\n\n", argv[i]);
2646                                 display_help();
2647                                 return 1;
2648                         }
2649
2650                         c = argv[i++][1];                       // Get next character in command line
2651
2652                         // Process command line switch
2653                         switch (c)
2654                         {
2655                         case '?':                                       // Display usage information
2656                         case 'h':
2657                         case 'H':
2658                                 display_version();
2659                                 display_help();
2660                                 return 1;
2661                         case 'a':
2662                         case 'A':                                       // Set absolute linking on
2663                                 if (aflag)
2664                                         warn('a', 1);
2665
2666                                 if (i + 2 >= argc)
2667                                 {
2668                                         printf("Not enough arguments to -a\n");
2669                                         return 1;
2670                                 }
2671
2672                                 aflag = 1;                              // Set abs link flag
2673                                 // Segment order is TEXT, DATA, BSS
2674                                 // Text segment can be 'r', 'x' or a value
2675                                 ttype = 0;
2676
2677                                 if ((*argv[i] == 'r' || *argv[i] == 'R') && !argv[i][1])
2678                                 {
2679                                         ttype = -1;                     // TEXT segment is relocatable
2680                                 }
2681                                 else if ((*argv[i] == 'x' || *argv[i] == 'X'))
2682                                 {
2683                                         printf("Error in text-segment address: cannot be contiguous\n");
2684                                         return 1;
2685                                 }
2686                                 else if ((ttype = 0), getval(argv[i], &tval))
2687                                 {
2688                                         printf("Error in text-segment address: %s is not 'r', 'x' or an address.", argv[i]);
2689                                         return 1;
2690                                 }
2691
2692                                 i++;
2693                                 // Data segment can be 'r', 'x' or a value
2694                                 dtype = 0;
2695
2696                                 if ((*argv[i] == 'r' || *argv[i] == 'R') && !argv[i][1])
2697                                 {
2698                                         dtype = -1;                     // DATA segment is relocatable
2699                                 }
2700                                 else if ((*argv[i] == 'x' || *argv[i] == 'X'))
2701                                 {
2702                                         dtype = -2;                     // DATA follows TEXT
2703                                 }
2704                                 else if ((dtype = 0), getval(argv[i],&dval))
2705                                 {
2706                                         printf("Error in data-segment address: %s is not 'r', 'x' or an address.", argv[i]);
2707                                         return 1;
2708                                 }
2709
2710                                 i++;
2711                                 btype = 0;
2712
2713                                 // BSS segment can be 'r', 'x' or a value
2714                                 if ((*argv[i] == 'r' || *argv[i] == 'R') && !argv[i][1])
2715                                 {
2716                                         btype = -1;                     // BSS segment is relocatable
2717                                 }
2718                                 else if ((*argv[i] == 'x' || *argv[i] == 'X'))
2719                                 {
2720                                         btype = -3;                     // BSS follows DATA
2721                                 }
2722                                 else if ((btype = 0), getval(argv[i],&bval))
2723                                 {
2724                                         printf("Error in bss-segment address: %s is not 'r', 'x[td]', or an address.", argv[i]);
2725                                         return 1;
2726                                 }
2727
2728                                 i++;
2729                                 break;
2730                         case 'b':
2731                         case 'B':                                       // Don't remove muliply defined locals
2732                                 if (bflag)
2733                                         warn('b', 1);
2734
2735                                 bflag = 1;
2736                                 break;
2737                         case 'c':
2738                         case 'C':                                       // Process a command file
2739                                 if (i == argc)
2740                                 {
2741                                         printf("Not enough arguments to -c\n");
2742                                         return 1;
2743                                 }
2744
2745                                 if (docmdfile(argv[i++]))
2746                                 {
2747                                         return 1;
2748                                 }
2749
2750                                 break;
2751                         case 'd':
2752                         case 'D':                                       // Wait for "return" before exiting
2753                                 if (dflag)
2754                                         warn('d', 0);
2755
2756                                 dflag = 1;
2757                                 waitflag = 1;
2758                                 break;
2759                         case 'e':
2760                         case 'E':                                       // Output COFF (absolute only)
2761                                 cflag = 1;
2762                                 break;
2763                         case 'g':
2764                         case 'G':                                       // Output source level debugging
2765                                 printf("\'g\' flag not currently implemented\n");
2766                                 gflag = 0;
2767                                 /*
2768                                 if (gflag) warn('g', 1);
2769                                 gflag = 1;
2770                                 */
2771                                 break;
2772                         case 'i':
2773                         case 'I':                                       // Include binary file
2774                                 if (i + 2 > argc)
2775                                 {
2776                                         printf("Not enough arguments to -i\n");
2777                                         return 1;
2778                                 }
2779
2780                                 ifile = argv[i++];
2781                                 isym = argv[i++];
2782
2783                                 // handle -ii (No truncation)
2784                                 if ((argv[i-3][2] == 'i') || (argv[i-3][2] == 'I'))
2785                                 {
2786                                         if (!cflag)
2787                                                 printf("warning: (-ii) COFF format output not specified\n");
2788                                 }
2789                                 // handle -i (Truncation)
2790                                 else
2791                                 {
2792                                         if (strlen(isym) > 7)
2793                                                 isym[7] = '\0';
2794                                 }
2795
2796                                 // Place include files in the DATA segment only
2797                                 if (dofile(ifile, DSTSEG_D, isym))
2798                                         return 1;
2799
2800                                 break;
2801                         case 'l':
2802                         case 'L':                                       // Add local symbols
2803                                 if (lflag)
2804                                         warn('l', 1);
2805
2806                                 lflag = 1;
2807                                 break;
2808                         case 'm':
2809                         case 'M':                                       // Produce load symbol map
2810                                 if (mflag)
2811                                         warn('m', 1);
2812
2813                                 mflag = 1;
2814                                 break;
2815                         case 'n':
2816                         case 'N':                                       // Output no header to .abs file
2817                                 if (noheaderflag)
2818                                         warn('n', 1);
2819
2820                                 noheaderflag = 1;
2821                                 break;
2822                         case 'o':
2823                         case 'O':                                       // Specify an output file
2824                                 if (oflag)
2825                                         warn('o', 1);
2826
2827                                 oflag = 1;
2828
2829                                 if (i >= argc)
2830                                 {
2831                                         printf("No output filename following -o switch\n");
2832                                         return 1;
2833                                 }
2834
2835                                 if (strlen(argv[i]) > FARGSIZE - 5)
2836                                 {
2837                                         printf("Output file name too long (sorry!)\n");
2838                                         return 1;
2839                                 }
2840
2841                                 strcpy(ofile, argv[i++]);
2842                                 break;
2843                         case 'r':
2844                         case 'R':                                       // Section alignment size
2845                                 if (rflag)
2846                                         warn('r', 1);
2847
2848                                 rflag = 1;
2849
2850                                 switch (argv[i-1][2])
2851                                 {
2852                                         case 'w': case 'W': secalign = 1;  break; // Word alignment
2853                                         case 'l': case 'L': secalign = 3;  break; // Long alignment
2854                                         case 'p': case 'P': secalign = 7;  break; // Phrase alignment
2855                                         case 'd': case 'D': secalign = 15; break; // Double phrase alignment
2856                                         case 'q': case 'Q': secalign = 31; break; // Quad phrase alignment
2857                                         default:            secalign = 7;  break; // Default phrase alignment
2858                                 }
2859
2860                                 break;
2861                         case 's':
2862                         case 'S':                                       // Output only global symbols
2863                                 if (sflag)
2864                                         warn('s', 1);
2865
2866                                 sflag = 1;
2867                                 break;
2868                         case 'v':
2869                         case 'V':                                       // Verbose information
2870                                 if (!vflag && !versflag)
2871                                 {
2872                                         display_version();
2873                                 }
2874
2875                                 vflag++;
2876                                 break;
2877                         case 'w':
2878                         case 'W':                                       // Show warnings flag
2879                                 if (wflag)
2880                                         warn('w', 1);
2881
2882                                 wflag = 1;
2883                                 break;
2884                         case 'z':
2885                         case 'Z':                                       // Suppress banner flag
2886                                 if (zflag)
2887                                         warn('z', 1);
2888
2889                                 zflag = 1;
2890                                 break;
2891                         default:
2892                                 printf("unknown option argument `%c'\n", c);
2893                                 return 1;
2894                         }
2895                 }
2896                 else
2897                 {
2898                         // Not a switch, then process as a file
2899                         if (dofile(argv[i++], 0, NULL))
2900                                 return 1;
2901                 }
2902         }
2903
2904         if (!oflag && vflag)
2905         {
2906                 strcpy(ofile, "output");
2907                 printf("Output file is %s[.ext]\n", ofile);
2908         }
2909
2910         if (oflag && vflag)
2911                 printf("Output file is %s\n", ofile);
2912
2913         if (sflag)
2914                 lflag = 0;
2915
2916         // No problems encountered
2917         return 0;
2918 }
2919
2920
2921 //
2922 // Display Version Information
2923 //
2924 void display_version(void)
2925 {
2926         if (displaybanner)// && vflag)
2927         {
2928                 printf("\nReboot's Linker for Atari Jaguar\n");
2929                 printf("Copyright (c) 199x Allan K. Pratt, 2014 Reboot\n");
2930                 printf("V%i.%i.%i %s (%s)\n\n", MAJOR, MINOR, PATCH, __DATE__, PLATFORM);
2931         }
2932 }
2933
2934
2935 //
2936 // Display Command Line Help
2937 //
2938 void display_help(void)
2939 {
2940         printf("Usage:\n");
2941         printf("    %s [-options] file(s)\n", cmdlnexec);
2942         printf("\n");
2943         printf("Options:\n");
2944         printf("   -? or -h                display usage information\n");
2945         printf("   -a <text> <data> <bss>  output absolute file\n");
2946         printf("                           hex value: segment address\n");
2947         printf("                           r: relocatable segment\n");
2948         printf("                           x: contiguous segment\n");
2949         printf("   -b                      don't remove multiply defined local labels\n");
2950         printf("   -c <fname>              add contents of <fname> to command line\n");
2951         printf("   -d                      wait for key after link\n");
2952         printf("   -e                      output COF absolute file\n");
2953         printf("   -g                      output source-level debugging\n");
2954         printf("   -i <fname> <label>      incbin <fname> and set <label>\n");
2955         printf("   -l                      add local symbols\n");
2956         printf("   -m                      produce load symbols map\n");
2957         printf("   -n                      output no file header to .abs file\n");
2958         printf("   -o <fname>              set output name\n");
2959         printf("   -r<size>                section alignment size\n");
2960         printf("                           w: word (2 bytes)\n");
2961         printf("                           l: long (4 bytes)\n");
2962         printf("                           p: phrase (8 bytes, default alignment)\n");
2963         printf("                           d: double phrase (16 bytes)\n");
2964         printf("                           q: quad phrase (32 bytes)\n");
2965         printf("   -s                      output only global symbols\n");
2966         printf("   -v                      set verbose mode\n");
2967         printf("   -w                      show linker warnings\n");
2968         printf("   -z                      suppress banner\n");
2969         printf("\n");
2970 }
2971
2972
2973 //
2974 // Application Exit
2975 //
2976 void rln_exit(void)
2977 {
2978         char tempbuf[128];
2979
2980         // Display link status if verbose mode
2981         if (vflag)
2982                 printf("Link %s.\n", errflag ? "aborted" : "complete");
2983
2984         // Wait for return key if requested
2985         if (waitflag)
2986         {
2987                 printf("\nPress the [RETURN] key to continue. ");
2988                 fgets(tempbuf, 128, stdin);
2989         }
2990
2991         exit(errflag);
2992 }
2993
2994
2995 //
2996 // Determine Processor Endianess
2997 //
2998 int get_endianess(void)
2999 {
3000         int i = 1;
3001         char * p = (char *)&i;
3002
3003         if (p[0] == 1)
3004                 return ENDIANNESS_LITTLE;
3005
3006         return ENDIANNESS_BIG;
3007 }
3008
3009
3010 //
3011 // Application Code Starts Here
3012 //
3013 int main(int argc, char * argv[])
3014 {
3015         char * s = NULL;                                // String pointer for "getenv"
3016         struct HREC * utemp;                    // Temporary hash record pointer
3017         struct OHEADER * header;                // Pointer to output header structure
3018
3019         endian = get_endianess();               // Get processor endianess
3020         cmdlnexec = argv[0];                    // Obtain executable name
3021         s = getenv("RLNPATH");
3022
3023         if (s)                                                  // Attempt to obtain env variable
3024                 strcpy(libdir, s);                      // Store it if found
3025
3026         // Parse the command line
3027         if (doargs(argc, argv))
3028         {
3029                 errflag = 1;
3030                 rln_exit();
3031         }
3032
3033         if (!zflag && !vflag)
3034         {
3035                 display_version();                      // Display version information
3036                 versflag = 1;                           // We've dumped the version banner
3037         }
3038
3039         // Process in specified files/objects
3040         if (ProcessObjectFiles())
3041         {
3042                 errflag = 1;
3043                 rln_exit();
3044         }
3045
3046         // Remove elements from unresolved list
3047         if (dolist())
3048         {
3049                 errflag = 1;
3050                 rln_exit();
3051         }
3052
3053         // Check that there is something to link
3054         if (olist == NULL)
3055         {
3056                 display_help();
3057                 rln_exit();
3058         }
3059
3060         // Report unresolved externals
3061         if (unresolved != NULL)
3062         {
3063                 printf("UNRESOLVED SYMBOLS\n");
3064
3065                 // Don't list them if two -u's or more
3066                 if (uflag < 2)
3067                 {
3068                         utemp = unresolved;
3069
3070                         while (utemp != NULL)
3071                         {
3072                                 printf("\t%s (",utemp->h_sym);
3073                                 put_name(utemp->h_ofile);
3074                                 printf(")\n");
3075                                 utemp = utemp->h_next;
3076                         }
3077                 }
3078
3079                 if (!uflag)
3080                 {
3081                         errflag = 1;
3082                         rln_exit();
3083                 }
3084         }
3085
3086         // Make one output file from input objs
3087         if ((header = make_ofile()) == NULL)
3088         {
3089                 errflag = 1;
3090                 rln_exit();
3091         }
3092
3093         // Partial linking
3094         if (pflag)
3095         {
3096                 printf("TO DO:Partial linking\n");
3097                 errflag = 1;
3098         }
3099         // Relocatable linking
3100         else if (!aflag)
3101         {
3102                 printf("TO DO:Relocatable linking\n");
3103                 errflag = 1;
3104         }
3105         // Absolute linking
3106         else
3107         {
3108                 if (vflag)
3109                 {
3110                         printf("Absolute linking ");
3111
3112                         if (cflag)
3113                                 printf("(COF)\n"); 
3114                         else
3115                                 printf("(ABS)\n");
3116                 }
3117
3118                 if (vflag > 1)
3119                         printf("Header magic is 0x%04X\n", (unsigned int)header->magic);
3120
3121                 if (write_ofile(header))
3122                         errflag = 1;
3123         }
3124
3125         // Display the loaded symbols map
3126         if (mflag)
3127                 if (write_map(header))
3128                         errflag = 1;
3129
3130         // Display segment size summary
3131         if (vflag)
3132         {
3133                 printf("\n");
3134                 printf("+---------+----------+----------+----------+\n");
3135                 printf("| Segment |     TEXT |     DATA |      BSS |\n");
3136                 printf("| Sizes   |----------+----------+----------|\n");
3137                 printf("| (Hex)   | %8X | %8X | %8X |\n", (unsigned int)header->tsize, (unsigned int)header->dsize, (unsigned int)header->bsize);
3138                 printf("+---------+----------+----------+----------+\n\n");
3139         }
3140
3141 //printf("BIG_ENDIAN = %i, LITTLE_ENDIAN = %i\n", BIG_ENDIAN, LITTLE_ENDIAN);
3142
3143         free(header);
3144         rln_exit();
3145 }
3146