]> Shamusworld >> Repos - rmac/blob - rmac.c
Various code cleanups, mainly to do with RISC assembly.
[rmac] / rmac.c
1 //
2 // RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
3 // RMAC.C - Main Application Code
4 // Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends
5 // RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
6 // Source Utilised with the Kind Permission of Landon Dyer
7 //
8
9 #include "rmac.h"
10 #include "error.h"
11 #include "listing.h"
12 #include "procln.h"
13 #include "token.h"
14 #include "expr.h"
15 #include "sect.h"
16 #include "mark.h"
17 #include "macro.h"
18 #include "riscasm.h"
19 #include "direct.h"
20 #include "version.h"
21 #include "debug.h"
22 #include "symbol.h"
23 #include "object.h"
24
25 int perm_verb_flag;                                     // Permanently verbose, interactive mode
26 int list_flag;                                          // "-l" Listing flag on command line
27 int verb_flag;                                          // Be verbose about what's going on
28 int as68_flag;                                          // as68 kludge mode
29 int glob_flag;                                          // Assume undefined symbols are global
30 int lsym_flag;                                          // Include local symbols in object file
31 int sbra_flag;                                          // Warn about possible short branches
32 int obj_format;                                         // Object format flag
33 int debug;                                                      // [1..9] Enable debugging levels
34 int err_flag;                                           // '-e' specified
35 int err_fd;                                                     // File to write error messages to 
36 int rgpu, rdsp;                                         // Assembling Jaguar GPU or DSP code
37 int list_fd;                                            // File to write listing to
38 int regbank;                                            // RISC register bank
39 int segpadsize;                                         // Segment padding size
40 int endian;                                                     // Host processor endianess
41 char * objfname;                                        // Object filename pointer
42 char * firstfname;                                      // First source filename
43 char * cmdlnexec;                                       // Executable name, pointer to ARGV[0]
44 char * searchpath;                                      // Search path for include files 
45 char defname[] = "noname.o";            // Default output filename
46
47 // Under Windows and UNIX malloc() is an expensive call, so for small amounts
48 // of memory we allocate from a previously allocated buffer.
49
50 #define A_AMOUNT        4096                                // Amount to malloc() at a time
51 #define A_THRESH        64                                  // Use malloc() for amounts >= A_THRESH
52
53 static LONG a_amount;                                       // Amount left at a_ptr 
54 static char * a_ptr;                                        // Next free chunk
55 LONG amemtot;                                               // amem() total of requests
56
57 // Qsort; The THRESHold below is the insertion sort threshold, and has been adjusted
58 // for records of size 48 bytes.The MTHREShold is where we stop finding a better median.
59  
60 #define THRESH          4                                   // Threshold for insertion
61 #define MTHRESH         6                                   // Threshold for median
62
63 static int (*qcmp)();                                       // The comparison routine
64 static int qsz;                                             // Size of each record
65 static int thresh;                                          // THRESHold in chars 
66 static int mthresh;                                         // MTHRESHold in chars
67
68 // This is unused BOLLOCKS
69 #if 0
70 //
71 // qst: Do a quicksort. First, find the median element, and put that one in the
72 // first place as the discriminator. (This "median" is just the median of the
73 // first, last and middle elements). (Using this median instead of the first
74 // element is a big win). Then, the usual partitioning/swapping, followed by
75 // moving the discriminator into the right place. Then, figure out the sizes of
76 // the two partions, do the smaller one recursively and the larger one via a
77 // repeat of this code.  Stopping when there are less than THRESH elements in a
78 // partition and cleaning up with an insertion sort (in our caller) is a huge
79 // win. All data swaps are done in-line, which is space-losing but time-saving.
80 // (And there are only three places where this is done).
81 //
82 static int qst(char * base, char * max)
83 {
84    char c, * i, * j, * jj;
85    int ii;
86    char * mid, * tmp;
87    long lo, hi;
88
89    /*
90          * At the top here, lo is the number of characters of elements in the
91          * current partition. (Which should be max - base).
92          * Find the median of the first, last, and middle element and make
93          * that the middle element. Set j to largest of first and middle.
94          * If max is larger than that guy, then it's that guy, else compare
95          * max with loser of first and take larger. Things are set up to
96          * prefer the middle, then the first in case of ties.
97          */
98         lo = max - base;                /* number of elements as chars */
99
100         do
101         {
102                 mid = i = base + qsz * ((lo / qsz) >> 1);
103
104                 if (lo >= mthresh)
105                 {
106                         j = (qcmp((jj = base), i) > 0 ? jj : i);
107
108                         if (qcmp(j, (tmp = max - qsz)) > 0)
109                         {
110                                 /* switch to first loser */
111                                 j = (j == jj ? i : jj);
112
113                                 if (qcmp(j, tmp) < 0)
114                                         j = tmp;
115                         }
116
117                         if (j != i)
118                         {
119                                 ii = qsz;
120
121                                 do
122                                 {
123                                         c = *i;
124                                         *i++ = *j;
125                                         *j++ = c;
126                                 }
127                                 while (--ii);
128                         }
129                 }
130
131                 /*
132                  * Semi-standard quicksort partitioning/swapping
133                  */
134                 for(i=base, j=max-qsz; ;)
135                 {
136                         while (i < mid && qcmp(i, mid) <= 0)
137                                 i += qsz;
138
139                         while (j > mid)
140                         {
141                                 if (qcmp(mid, j) <= 0)
142                                 {
143                                         j -= qsz;
144                                         continue;
145                                 }
146
147                                 tmp = i + qsz;  /* value of i after swap */
148
149                                 if (i == mid)
150                                 {
151                                         /* j <-> mid, new mid is j */
152                                         mid = jj = j;
153                                 }
154                                 else
155                                 {
156                                         /* i <-> j */
157                                         jj = j;
158                                         j -= qsz;
159                                 }
160
161                                 goto swap;
162                         }
163
164                         if (i == mid)
165                         {
166                                 break;
167                         }
168                         else
169                         {
170                                 /* i <-> mid, new mid is i */
171                                 jj = mid;
172                                 tmp = mid = i;  /* value of i after swap */
173                                 j -= qsz;
174                         }
175 swap:
176                         ii = qsz;
177
178                         do
179                         {
180                                 c = *i;
181                                 *i++ = *jj;
182                                 *jj++ = c;
183                         }
184                         while (--ii);
185
186                         i = tmp;
187                 }
188
189                 /*
190                  * Look at sizes of the two partitions, do the smaller
191                  * one first by recursion, then do the larger one by
192                  * making sure lo is its size, base and max are update
193                  * correctly, and branching back.  But only repeat
194                  * (recursively or by branching) if the partition is
195                  * of at least size THRESH.
196                  */
197                 i = (j = mid) + qsz;
198
199                 if ((lo = j - base) <= (hi = max - i))
200                 {
201                         if (lo >= thresh)
202                                 qst(base, j);
203
204                         base = i;
205                         lo = hi;
206                 }
207                 else
208                 {
209                         if (hi >= thresh)
210                                 qst(i, max);
211
212                         max = j;
213                 }
214         }
215         while (lo >= thresh);
216
217         return 0;
218 }
219
220
221 /*
222  * qsort:
223  * First, set up some global parameters for qst to share.  Then, quicksort
224  * with qst(), and then a cleanup insertion sort ourselves.  Sound simple?
225  * It's not...
226  */
227 int rmac_qsort(char * base, int n, int size, int (*compar)())
228 {
229         register char c, * i, * j, * lo, * hi;
230         char * min, * max;
231
232         if (n <= 1)
233                 return 0;
234
235         qsz = size;
236         qcmp = compar;
237         thresh = qsz * THRESH;
238         mthresh = qsz * MTHRESH;
239         max = base + n * qsz;
240
241         if (n >= THRESH)
242         {
243                 qst(base, max);
244                 hi = base + thresh;
245         }
246         else
247         {
248                 hi = max;
249         }
250
251         /*
252          * First put smallest element, which must be in the first THRESH, in
253          * the first position as a sentinel.  This is done just by searching
254          * the first THRESH elements (or the first n if n < THRESH), finding
255          * the min, and swapping it into the first position.
256          */
257         for(j=lo=base; (lo+=qsz)<hi;)
258         {
259                 if (qcmp(j, lo) > 0)
260                         j = lo;
261         }
262
263         if (j != base)
264         {
265                 /* swap j into place */
266                 for(i=base, hi=base+qsz; i<hi;)
267                 {
268                         c = *j;
269                         *j++ = *i;
270                         *i++ = c;
271                 }
272         }
273
274         /*
275          * With our sentinel in place, we now run the following hyper-fast
276          * insertion sort.  For each remaining element, min, from [1] to [n-1],
277          * set hi to the index of the element AFTER which this one goes.
278          * Then, do the standard insertion sort shift on a character at a time
279          * basis for each element in the frob.
280          */
281         for(min=base; (hi=min+=qsz)<max;)
282         {
283                 while (qcmp(hi -= qsz, min) > 0)
284                         /* void */;
285
286                 if ((hi += qsz) != min)
287                 {
288                         for(lo=min+qsz; --lo>=min;)
289                         {
290                                 c = *lo;
291
292                                 for(i=j=lo; (j-=qsz)>=hi; i=j)
293                                         *i = *j;
294
295                                 *i = c;
296                         }
297                 }
298         }
299
300         return 0;
301 }
302 #endif
303
304 #if 0
305 //
306 // Allocate memory; Panic and Quit if we Run Out
307 //
308 char * amem(LONG amount)
309 {
310         char * p;
311
312 //      if (amount & 1)                                                         // Keep word alignment
313 //              amount++;
314         amount = (amount + 1) & ~(0x01);                        // Keep word alignment
315
316         // Honor *small* request (< 64 bytes)
317         if (amount < A_THRESH)
318         {
319                 if (a_amount < amount)
320                 {
321                         a_ptr = amem(A_AMOUNT);                         // Allocate 4K bytes
322                         a_amount = A_AMOUNT;
323                 }
324
325                 p = a_ptr;
326                 a_ptr += amount;
327                 a_amount -= amount;
328         }
329         else
330         {
331                 amemtot += amount;                                              // Bump total alloc
332                 p = (char *)malloc(amount);                             // Get memory from malloc
333
334                 if (p == NULL)
335                         fatal("Memory exhausted!");
336
337                 memset(p, 0, amount);
338         }
339
340         return p;
341 }
342 #endif
343
344
345 //
346 // Copy stuff around, return pointer to dest+count+1 (doesn't handle overlap)
347 //
348 char * copy(char * dest, char * src, LONG count)
349 {
350         while (count--)
351                 *dest++ = *src++;
352
353         return dest;
354 }
355
356
357 //
358 // Clear a region of memory
359 //
360 void clear(char * dest, LONG count)
361 {
362         while(count--)
363                 *dest++ = 0;
364 }
365
366
367 //
368 // Check to see if the string is a keyword. Returns -1, or a value from the
369 // 'accept[]' table
370 //
371 int kmatch(char * p, int * base, int * check, int * tab, int * accept)
372 {
373         int state;
374         int j;
375
376         for(state=0; state>=0;)
377         {
378                 j = base[state] + (int)tolowertab[*p];
379
380                 if (check[j] != state)
381                 {                               // Reject, character doesn't match
382                         state = -1;                                        // No match 
383                         break;
384                 }
385
386                 if (!*++p)
387                 {                                           // Must accept or reject at EOS
388                         state = accept[j];                                 // (-1 on no terminal match) 
389                         break;
390                 }
391
392                 state = tab[j];
393         }
394
395         return state;
396 }
397
398
399 //
400 // Auto-even a section
401 //
402 void autoeven(int sect)
403 {
404         switchsect(sect);
405         d_even();
406         savsect();
407 }
408
409
410 //
411 // Manipulate file extension.
412 // `name' must be large enough to hold any possible filename.
413 // If `stripp' is nonzero, any old extension is removed.
414 // Then, if the file does not already have an extension,
415 // `extension' is appended to the filename.
416 //
417 char * fext(char * name, char * extension, int stripp)
418 {
419         char * s, * beg;                                           // String pointers
420
421         // Find beginning of "real" name
422         beg = name + strlen(name) - 1;
423
424         for(; beg>name; --beg)
425         {
426                 if (*beg == SLASHCHAR)
427                 {
428                         ++beg;
429                         break;
430                 }
431         }
432
433         if (stripp)
434         {                                             // Clobber any old extension
435                 for(s=beg; *s && *s!='.'; ++s) 
436                         ;
437
438                 *s = '\0';
439         }
440
441         for(s=beg; *s!='.'; ++s)
442         {
443                 if (!*s)
444                 {                                             // Append the new extension
445                         strcat(beg, extension);
446                         break;
447                 }
448         }
449
450         return name;
451 }
452
453
454 //
455 // Return `item'nth element of semicolon-seperated pathnames specified in the
456 // enviroment string `s'. Copy the pathname to `buf'.  Return 0 if the `item'
457 // nth path doesn't exist.
458 // 
459 // [`item' ranges from 0 to N-1, where N = #elements in search path]
460 //
461 int nthpath(char * env_var, int itemno, char * buf)
462 {
463         char * s = searchpath;
464
465         if (s == NULL)
466                 s = getenv(env_var);
467
468         if (s == NULL)
469                 return 0;
470
471         while (itemno--)
472                 while (*s != EOS && *s++ != ';')
473                         ;
474
475         if (*s == EOS)
476                 return 0;
477
478         while (*s != EOS && *s != ';')
479                 *buf++ = *s++;
480
481         *buf++ = EOS;
482
483         return 1;
484 }
485
486
487 //
488 // Display Command Line Help
489 //
490 void display_help(void)
491 {
492         printf("Usage:\n");
493         printf("    %s [options] srcfile\n", cmdlnexec);
494         printf("\n");
495         printf("Options:\n");
496         printf("   -? or -h              display usage information\n");
497         printf("   -dsymbol[=value]      define symbol\n");
498         printf("   -e[errorfile]         send error messages to file, not stdout\n");
499         printf("   -f[format]            output object file format\n");
500         printf("                         b: BSD (use this for Jaguar)\n");
501         printf("   -i[path]              directory to search for include files\n");
502         printf("   -l[filename]          create an output listing file\n");
503         printf("   -o file               output file name\n");
504         printf("   -r[size]              pad segments to boundary size specified\n");
505         printf("                         w: word (2 bytes, default alignment)\n");
506         printf("                         l: long (4 bytes)\n");
507         printf("                         p: phrase (8 bytes)\n");
508         printf("                         d: double phrase (16 bytes)\n");
509         printf("                         q: quad phrase (32 bytes)\n");
510         printf("   -s                    warn about possible short branches\n");
511         printf("   -u                    force referenced and undefined symbols global\n");
512         printf("   -v                    set verbose mode\n");
513         printf("   -y[pagelen]           set page line length (default: 61)\n");
514         printf("\n");
515 }
516
517
518 //
519 // Display Version Information
520 //
521 void display_version(void)
522 {
523         printf("\nReboot's Macro Assembler for Atari Jaguar\n"); 
524         printf("Copyright (C) 199x Landon Dyer, 2011 Reboot\n"); 
525         printf("V%01i.%01i.%01i %s (%s)\n\n", MAJOR, MINOR, PATCH, __DATE__, PLATFORM);
526 }
527
528
529 // 
530 // Process Command Line Arguments and do an Assembly
531 //
532 int process(int argc, char ** argv)
533 {
534         int argno;                                              // Argument number
535         SYM * sy;                                               // Pointer to a symbol record
536         char * s;                                               // String pointer
537         int fd;                                                 // File descriptor
538         char fnbuf[FNSIZ];                              // Filename buffer 
539         int i;                                                  // Iterator
540
541         errcnt = 0;                                             // Initialise error count
542         listing = 0;                                    // Initialise listing level
543         list_flag = 0;                                  // Initialise listing flag
544         verb_flag = perm_verb_flag;             // Initialise verbose flag
545         as68_flag = 0;                                  // Initialise as68 kludge mode
546         glob_flag = 0;                                  // Initialise .globl flag
547         sbra_flag = 0;                                  // Initialise short branch flag
548         debug = 0;                                              // Initialise debug flag
549         searchpath = NULL;                              // Initialise search path
550         objfname = NULL;                                // Initialise object filename
551         list_fname = NULL;                              // Initialise listing filename
552         err_fname = NULL;                               // Initialise error filename
553         obj_format = BSD;                               // Initialise object format
554         firstfname = NULL;                              // Initialise first filename
555         err_fd = ERROUT;                                // Initialise error file descriptor
556         err_flag = 0;                                   // Initialise error flag
557         rgpu = 0;                                               // Initialise GPU assembly flag
558         rdsp = 0;                                               // Initialise DSP assembly flag
559         lsym_flag = 1;                                  // Include local symbols in object file
560         regbank = BANK_N;                               // No RISC register bank specified
561         orgactive = 0;                                  // Not in RISC org section
562         orgwarning = 0;                                 // No ORG warning issued
563         a_amount = 0;
564         segpadsize = 2;                                 // Initialise segment padding size
565
566         // Initialise modules
567         InitSymbolTable();                              // Symbol table
568         init_token();                                   // Tokenizer
569         init_procln();                                  // Line processor
570         init_expr();                                    // Expression analyzer
571         init_sect();                                    // Section manager / code generator
572         init_mark();                                    // Mark tape-recorder
573         InitMacro();                                    // Macro processor
574         init_list();                                    // Listing generator
575
576         // Process command line arguments and assemble source files
577         for(argno=0; argno<argc; ++argno)
578         {
579                 if (*argv[argno] == '-')
580                 {
581                         switch (argv[argno][1])
582                         {
583                         case 'd':                                       // Define symbol
584                         case 'D':
585                                 for(s=argv[argno]+2; *s!=EOS;)
586                                 {
587                                         if (*s++ == '=')
588                                         {
589                                                 s[-1] = EOS;
590                                                 break;
591                                         }
592                                 }
593
594                                 if (argv[argno][2] == EOS)
595                                 {
596                                         printf("-d: empty symbol\n");
597                                         ++errcnt;
598                                         return errcnt;
599                                 }
600
601                                 sy = lookup(argv[argno] + 2, 0, 0);
602
603                                 if (sy == NULL)
604                                 {
605                                         sy = NewSymbol(argv[argno] + 2, LABEL, 0);
606                                         sy->svalue = 0;
607                                 }
608
609                                 sy->sattr = DEFINED | EQUATED | ABS;
610
611                                 if (*s)
612                                         sy->svalue = (VALUE)atoi(s);
613                                 else
614                                         sy->svalue = 0;
615
616                                 break;
617                         case 'e':                                       // Redirect error message output
618                         case 'E':
619                                 err_fname = argv[argno] + 2;
620                                 break;
621                         case 'f':                                       // -f<format>
622                         case 'F':
623                                 switch (argv[argno][2])
624                                 {
625                                 case EOS:
626                                 case 'b':                                 // -fb = BSD (Jaguar Recommended)
627                                 case 'B':
628                                         obj_format = BSD;
629                                         break;
630                                 default:
631                                         printf("-f: unknown object format specified\n");
632                                         errcnt++;
633                                         return errcnt;
634                                 }
635                                 break;
636                         case 'g':                                       // Debugging flag
637                         case 'G':
638                                 printf("Debugging flag (-g) not yet implemented\n");
639                                 break;
640                         case 'i':                                       // Set directory search path
641                         case 'I':
642                                 searchpath = argv[argno] + 2;
643                                 break;
644                         case 'l':                                       // Produce listing file
645                         case 'L':
646                                 list_fname = argv[argno] + 2;
647                                 listing = 1;
648                                 list_flag = 1;
649                                 lnsave++;
650                                 break;
651                         case 'o':                                       // Direct object file output
652                         case 'O':
653                                 if (argv[argno][2] != EOS)
654                                         objfname = argv[argno] + 2;
655                                 else
656                                 {
657                                         if (++argno >= argc)
658                                         {
659                                                 printf("Missing argument to -o");
660                                                 errcnt++;
661                                                 return errcnt;
662                                         }
663                                         objfname = argv[argno];
664                                 }
665
666                                 break;
667                         case 'r':                                       // Pad seg to requested boundary size
668                         case 'R':
669                                 switch(argv[argno][2])
670                                 {
671                                 case 'w': case 'W': segpadsize = 2;  break;  
672                                 case 'l': case 'L': segpadsize = 4;  break;
673                                 case 'p': case 'P': segpadsize = 8;  break;
674                                 case 'd': case 'D': segpadsize = 16; break;
675                                 case 'q': case 'Q': segpadsize = 32; break;
676                                 default: segpadsize = 2; break;           // Effective autoeven();
677                                 }
678                                 break;
679                         case 's':                                       // Warn about possible short branches
680                         case 'S':
681                                 sbra_flag = 1;
682                                 break;
683                         case 'u':                                       // Make undefined symbols .globl
684                         case 'U':
685                                 glob_flag = 1;
686                                 break;
687                         case 'v':                                       // Verbose flag
688                         case 'V':
689                                 verb_flag++;
690
691                                 if (verb_flag > 1)
692                                         display_version();
693
694                                 break;
695                         case 'x':                                       // Turn on debugging
696                         case 'X':
697                                 debug = 1;
698                                 printf("~ Debugging ON\n");
699                                 break;
700                         case 'y':                                       // -y<pagelen>
701                         case 'Y':
702                                 pagelen = atoi(argv[argno] + 2);
703
704                                 if (pagelen < 10)
705                                 {
706                                         printf("-y: bad page length\n");
707                                         ++errcnt;
708                                         return errcnt;
709                                 }
710
711                                 break;
712                         case EOS:                                       // Input is stdin
713                                 if (firstfname == NULL)                       // Kludge first filename
714                                         firstfname = defname;
715
716                                 include(0, "(stdin)");
717                                 Assemble();
718                                 break;
719                         case 'h':                                       // Display command line usage
720                         case 'H':
721                         case '?':
722                                 display_version();
723                                 display_help();
724                                 errcnt++;
725                                 break;
726                         default:
727                                 display_version();
728                                 printf("Unknown switch: %s\n\n", argv[argno]);
729                                 display_help();
730                                 errcnt++;
731                                 break;
732                         }
733                 }
734                 else
735                 {
736                         // Record first filename.
737                         if (firstfname == NULL)
738                                 firstfname = argv[argno];
739
740                         strcpy(fnbuf, argv[argno]);
741                         fext(fnbuf, ".s", 0);
742                         fd = open(fnbuf, 0);
743
744                         if (fd < 0)
745                         {
746                                 printf("Cannot open: %s\n", fnbuf);
747                                 errcnt++;
748                                 continue;
749                         }
750
751                         include(fd, fnbuf);
752                         Assemble();
753                 }
754         }
755
756         // Wind-up processing;
757         // o  save current section (no more code generation)
758         // o  do auto-even of all sections (or boundary alignment as requested through '-r')
759         // o  determine name of object file:
760         //    -  "foo.o" for linkable output;
761         //    -  "foo.prg" for GEMDOS executable (-p flag).
762         savsect();
763
764         for(i=TEXT; i<=BSS; i<<=1)
765         {
766                 switchsect(i);
767
768                 switch(segpadsize)
769                 {
770                 case 2:  d_even();    break;
771                 case 4:  d_long();    break;
772                 case 8:  d_phrase();  break;
773                 case 16: d_dphrase(); break;
774                 case 32: d_qphrase(); break;
775                 }
776
777                 savsect();
778         }
779
780         if (objfname == NULL)
781         {
782                 if (firstfname == NULL)
783                         firstfname = defname;
784
785                 strcpy(fnbuf, firstfname);
786                 //fext(fnbuf, prg_flag ? ".prg" : ".o", 1);
787                 fext(fnbuf, ".o", 1);
788                 objfname = fnbuf;
789         }
790
791         // With one pass finished, go back and:
792         // (1)   run through all the fixups and resolve forward references;
793         // (1.5) ensure that remaining fixups can be handled by the linker
794         //       (`lo68' format, extended (postfix) format....)
795         // (2)   generate the output file image and symbol table;
796         // (3)   generate relocation information from left-over fixups.
797         ResolveAllFixups();                                             // Do all fixups
798         stopmark();                                                             // Stop mark tape-recorder
799
800         if (errcnt == 0)
801         {
802                 if ((fd = open(objfname, _OPEN_FLAGS, _PERM_MODE)) < 0)
803                         cantcreat(objfname);
804
805                 if (verb_flag)
806                 {
807                         s = "object";
808                         printf("[Writing %s file: %s]\n", s, objfname);
809                 }
810
811                 object((WORD)fd);
812                 close(fd);
813
814                 if (errcnt != 0)
815                         unlink(objfname);
816         }
817
818         if (list_flag)
819         {
820                 if (verb_flag)
821                         printf("[Wrapping-up listing file]\n");
822
823                 listing = 1;
824                 symtable();
825                 close(list_fd);
826         }
827
828         if (err_flag)
829                 close(err_fd);
830
831         DEBUG dump_everything();
832
833         return errcnt;
834 }
835
836
837 //
838 // Determine Processor Endianess
839 //
840 int get_endianess(void)
841 {
842         int i = 1;
843         char * p = (char *)&i;
844
845         if (p[0] == 1)
846                 return 0;
847
848         return 1;
849 }
850
851
852 //
853 // Application Entry Point; Handle the Command Line
854 //
855 int main(int argc, char ** argv)
856 {
857         perm_verb_flag = 0;                             // Clobber "permanent" verbose flag
858         cmdlnexec = argv[0];                    // Obtain executable name
859
860         endian = get_endianess();               // Get processor endianess
861
862         // If commands were passed in, process them
863         if (argc > 1)
864         {
865                 return process(argc - 1, argv + 1);              
866         }
867
868         display_version();
869         display_help();
870
871         return 0;
872 }