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