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