]> Shamusworld >> Repos - rmac/blob - rmac.c
eab212522bc526d46346baa01c2c4de910fb607d
[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 "risca.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 in_main;                                            // In main memory flag for GPUMAIN
41 int endian;                                                     // Host processor endianess
42 char * objfname;                                        // Object filename pointer
43 char * firstfname;                                      // First source filename
44 char * cmdlnexec;                                       // Executable name, pointer to ARGV[0]
45 char * searchpath;                                      // Search path for include files 
46 char defname[] = "noname.o";            // Default output filename
47
48 // Under Windows and UNIX malloc() is an expensive call, so for small amounts
49 // of memory we allocate from a previously allocated buffer.
50
51 #define A_AMOUNT        4096                                // Amount to malloc() at a time
52 #define A_THRESH        64                                  // Use malloc() for amounts >= A_THRESH
53
54 static LONG a_amount;                                       // Amount left at a_ptr 
55 static char * a_ptr;                                        // Next free chunk
56 LONG amemtot;                                               // amem() total of requests
57
58 // Qsort; The THRESHold below is the insertion sort threshold, and has been adjusted
59 // for records of size 48 bytes.The MTHREShold is where we stop finding a better median.
60  
61 #define THRESH          4                                   // Threshold for insertion
62 #define MTHRESH         6                                   // Threshold for median
63
64 static int (*qcmp)();                                       // The comparison routine
65 static int qsz;                                             // Size of each record
66 static int thresh;                                          // THRESHold in chars 
67 static int mthresh;                                         // MTHRESHold in chars
68
69
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
303
304 //
305 // Allocate memory; Panic and Quit if we Run Out
306 //
307 char * amem(LONG amount)
308 {
309         char * p;
310
311 //      if (amount & 1)                                                         // Keep word alignment
312 //              amount++;
313         amount = (amount + 1) & ~(0x01);                        // Keep word alignment
314
315         // Honor *small* request (< 64 bytes)
316         if (amount < A_THRESH)
317         {
318                 if (a_amount < amount)
319                 {
320                         a_ptr = amem(A_AMOUNT);                         // Allocate 4K bytes
321                         a_amount = A_AMOUNT;
322                 }
323
324                 p = a_ptr;
325                 a_ptr += amount;
326                 a_amount -= amount;
327         }
328         else
329         {
330                 amemtot += amount;                                              // Bump total alloc
331                 p = (char *)malloc(amount);                             // Get memory from malloc
332
333                 if (p == NULL)
334                         fatal("Memory exhausted!");
335
336                 memset(p, 0, amount);
337         }
338
339         return p;
340 }
341
342
343 //
344 // Copy stuff around, return pointer to dest+count+1 (doesn't handle overlap)
345 //
346 char * copy(char * dest, char * src, LONG count)
347 {
348         while (count--)
349                 *dest++ = *src++;
350
351         return dest;
352 }
353
354
355 //
356 // Clear a region of memory
357 //
358 void clear(char * dest, LONG count)
359 {
360         while(count--)
361                 *dest++ = 0;
362 }
363
364
365 //
366 // Check to see if the string is a keyword. Returns -1, or a value from the
367 // 'accept[]' table
368 //
369 int kmatch(char * p, int * base, int * check, int * tab, int * accept)
370 {
371         int state;
372         int j;
373
374         for(state=0; state>=0;)
375         {
376                 j = base[state] + (int)tolowertab[*p];
377
378                 if (check[j] != state)
379                 {                               // Reject, character doesn't match
380                         state = -1;                                        // No match 
381                         break;
382                 }
383
384                 if (!*++p)
385                 {                                           // Must accept or reject at EOS
386                         state = accept[j];                                 // (-1 on no terminal match) 
387                         break;
388                 }
389
390                 state = tab[j];
391         }
392
393         return state;
394 }
395
396
397 //
398 // Auto-even a section
399 //
400 void autoeven(int sect)
401 {
402         switchsect(sect);
403         d_even();
404         savsect();
405 }
406
407
408 //
409 // Manipulate file extension.
410 // `name' must be large enough to hold any possible filename.
411 // If `stripp' is nonzero, any old extension is removed.
412 // Then, if the file does not already have an extension,
413 // `extension' is appended to the filename.
414 //
415 char * fext(char * name, char * extension, int stripp)
416 {
417         char * s, * beg;                                           // String pointers
418
419         // Find beginning of "real" name
420         beg = name + strlen(name) - 1;
421
422         for(; beg>name; --beg)
423         {
424                 if (*beg == SLASHCHAR)
425                 {
426                         ++beg;
427                         break;
428                 }
429         }
430
431         if (stripp)
432         {                                             // Clobber any old extension
433                 for(s=beg; *s && *s!='.'; ++s) 
434                         ;
435
436                 *s = '\0';
437         }
438
439         for(s=beg; *s!='.'; ++s)
440         {
441                 if (!*s)
442                 {                                             // Append the new extension
443                         strcat(beg, extension);
444                         break;
445                 }
446         }
447
448         return name;
449 }
450
451
452 //
453 // Return `item'nth element of semicolon-seperated pathnames specified in the
454 // enviroment string `s'. Copy the pathname to `buf'.  Return 0 if the `item'
455 // nth path doesn't exist.
456 // 
457 // [`item' ranges from 0 to N-1, where N = #elements in search path]
458 //
459 int nthpath(char * env_var, int itemno, char * buf)
460 {
461         char * s = searchpath;
462
463         if (s == NULL)
464                 s = getenv(env_var);
465
466         if (s == NULL)
467                 return 0;
468
469         while (itemno--)
470                 while (*s != EOS && *s++ != ';')
471                         ;
472
473         if (*s == EOS)
474                 return 0;
475
476         while (*s != EOS && *s != ';')
477                 *buf++ = *s++;
478
479         *buf++ = EOS;
480
481         return 1;
482 }
483
484
485 //
486 // Display Command Line Help
487 //
488 void display_help(void)
489 {
490         printf("Usage:\n");
491         printf("    %s [options] srcfile\n", cmdlnexec);
492         printf("\n");
493         printf("Options:\n");
494         printf("   -? or -h              display usage information\n");
495         printf("   -dsymbol[=value]      define symbol\n");
496         printf("   -e[errorfile]         send error messages to file, not stdout\n");
497         printf("   -f[format]            output object file format\n");
498         printf("                         b: BSD (use this for Jaguar)\n");
499         printf("   -i[path]              directory to search for include files\n");
500         printf("   -l[filename]          create an output listing file\n");
501         printf("   -o file               output file name\n");
502         printf("   -r[size]              pad segments to boundary size specified\n");
503         printf("                         w: word (2 bytes, default alignment)\n");
504         printf("                         l: long (4 bytes)\n");
505         printf("                         p: phrase (8 bytes)\n");
506         printf("                         d: double phrase (16 bytes)\n");
507         printf("                         q: quad phrase (32 bytes)\n");
508         printf("   -s                    warn about possible short branches\n");
509         printf("   -u                    force referenced and undefined symbols global\n");
510         printf("   -v                    set verbose mode\n");
511         printf("   -y[pagelen]           set page line length (default: 61)\n");
512         printf("\n");
513 }
514
515
516 //
517 // Display Version Information
518 //
519 void display_version(void)
520 {
521         printf("\nReboot's Macro Assembler for Atari Jaguar\n"); 
522         printf("Copyright (C) 199x Landon Dyer, 2011 Reboot\n"); 
523         printf("V%01i.%01i.%01i %s (%s)\n\n", MAJOR, MINOR, PATCH, __DATE__, PLATFORM);
524 }
525
526
527 // 
528 // Process Command Line Arguments and do an Assembly
529 //
530 int process(int argc, char ** argv)
531 {
532         int argno;                                              // Argument number
533         SYM * sy;                                               // Pointer to a symbol record
534         char * s;                                               // String pointer
535         int fd;                                                 // File descriptor
536         char fnbuf[FNSIZ];                              // Filename buffer 
537         int i;                                                  // Iterator
538
539         errcnt = 0;                                             // Initialise error count
540         listing = 0;                                    // Initialise listing level
541         list_flag = 0;                                  // Initialise listing flag
542         verb_flag = perm_verb_flag;             // Initialise verbose flag
543         as68_flag = 0;                                  // Initialise as68 kludge mode
544         glob_flag = 0;                                  // Initialise .globl flag
545         sbra_flag = 0;                                  // Initialise short branch flag
546         debug = 0;                                              // Initialise debug flag
547         searchpath = NULL;                              // Initialise search path
548         objfname = NULL;                                // Initialise object filename
549         list_fname = NULL;                              // Initialise listing filename
550         err_fname = NULL;                               // Initialise error filename
551         obj_format = BSD;                               // Initialise object format
552         firstfname = NULL;                              // Initialise first filename
553         err_fd = ERROUT;                                // Initialise error file descriptor
554         err_flag = 0;                                   // Initialise error flag
555         rgpu = 0;                                               // Initialise GPU assembly flag
556         rdsp = 0;                                               // Initialise DSP assembly flag
557         lsym_flag = 1;                                  // Include local symbols in object file
558         regbank = BANK_N;                               // No RISC register bank specified
559         orgactive = 0;                                  // Not in RISC org section
560         orgwarning = 0;                                 // No ORG warning issued
561         a_amount = 0;
562         segpadsize = 2;                                 // Initialise segment padding size
563         in_main = 0;
564
565         // Initialise modules
566         InitSymbolTable();                              // Symbol table
567         init_token();                                   // Tokenizer
568         init_procln();                                  // Line processor
569         init_expr();                                    // Expression analyzer
570         init_sect();                                    // Section manager / code generator
571         init_mark();                                    // Mark tape-recorder
572         init_macro();                                   // Macro processor
573         init_list();                                    // Listing generator
574
575         // Process command line arguments and assemble source files
576         for(argno = 0; argno < argc; ++argno)
577         {
578                 if (*argv[argno] == '-')
579                 {
580                         switch (argv[argno][1])
581                         {
582                         case 'd':                                       // Define symbol
583                         case 'D':
584                                 for(s=argv[argno]+2; *s!=EOS;)
585                                 {
586                                         if (*s++ == '=')
587                                         {
588                                                 s[-1] = EOS;
589                                                 break;
590                                         }
591                                 }
592
593                                 if (argv[argno][2] == EOS)
594                                 {
595                                         printf("-d: empty symbol\n");
596                                         ++errcnt;
597                                         return errcnt;
598                                 }
599
600                                 sy = lookup(argv[argno] + 2, 0, 0);
601
602                                 if (sy == NULL)
603                                 {
604                                         sy = NewSymbol(argv[argno] + 2, LABEL, 0);
605                                         sy->svalue = 0;
606                                 }
607
608                                 sy->sattr = DEFINED | EQUATED | ABS;
609
610                                 if (*s)
611                                         sy->svalue = (VALUE)atoi(s);
612                                 else
613                                         sy->svalue = 0;
614
615                                 break;
616                         case 'e':                                       // Redirect error message output
617                         case 'E':
618                                 err_fname = argv[argno] + 2;
619                                 break;
620                         case 'f':                                       // -f<format>
621                         case 'F':
622                                 switch (argv[argno][2])
623                                 {
624                                 case EOS:
625                                 case 'b':                                 // -fb = BSD (Jaguar Recommended)
626                                 case 'B':
627                                         obj_format = BSD;
628                                         break;
629                                 default:
630                                         printf("-f: unknown object format specified\n");
631                                         ++errcnt;
632                                         return errcnt;
633                                 }
634                                 break;
635                         case 'g':                                       // Debugging flag
636                         case 'G':
637                                 printf("Debugging flag (-g) not yet implemented\n");
638                                 break;
639                         case 'i':                                       // Set directory search path
640                         case 'I':
641                                 searchpath = argv[argno] + 2;
642                                 break;
643                         case 'l':                                       // Produce listing file
644                         case 'L':
645                                 list_fname = argv[argno] + 2;
646                                 listing = 1;
647                                 list_flag = 1;
648                                 ++lnsave;
649                                 break;
650                         case 'o':                                       // Direct object file output
651                         case 'O':
652                                 if (argv[argno][2] != EOS)
653                                         objfname = argv[argno] + 2;
654                                 else
655                                 {
656                                         if (++argno >= argc)
657                                         {
658                                                 printf("Missing argument to -o");
659                                                 ++errcnt;
660                                                 return errcnt;
661                                         }
662                                         objfname = argv[argno];
663                                 }
664
665                                 break;
666                         case 'r':                                       // Pad seg to requested boundary size
667                         case 'R':
668                                 switch(argv[argno][2])
669                                 {
670                                 case 'w': case 'W': segpadsize = 2;  break;  
671                                 case 'l': case 'L': segpadsize = 4;  break;
672                                 case 'p': case 'P': segpadsize = 8;  break;
673                                 case 'd': case 'D': segpadsize = 16; break;
674                                 case 'q': case 'Q': segpadsize = 32; break;
675                                 default: segpadsize = 2; break;           // Effective autoeven();
676                                 }
677                                 break;
678                         case 's':                                       // Warn about possible short branches
679                         case 'S':
680                                 sbra_flag = 1;
681                                 break;
682                         case 'u':                                       // Make undefined symbols .globl
683                         case 'U':
684                                 glob_flag = 1;
685                                 break;
686                         case 'v':                                       // Verbose flag
687                         case 'V':
688                                 verb_flag++;
689
690                                 if (verb_flag > 1)
691                                         display_version();
692
693                                 break;
694                         case 'x':                                       // Turn on debugging
695                         case 'X':
696                                 debug = 1;
697                                 printf("~ Debugging ON\n");
698                                 break;
699                         case 'y':                                       // -y<pagelen>
700                         case 'Y':
701                                 pagelen = atoi(argv[argno] + 2);
702
703                                 if (pagelen < 10)
704                                 {
705                                         printf("-y: bad page length\n");
706                                         ++errcnt;
707                                         return errcnt;
708                                 }
709
710                                 break;
711                         case EOS:                                       // Input is stdin
712                                 if (firstfname == NULL)                       // Kludge first filename
713                                         firstfname = defname;
714
715                                 include(0, "(stdin)");
716                                 assemble();
717                                 break;
718                         case 'h':                                       // Display command line usage
719                         case 'H':
720                         case '?':
721                                 display_version();
722                                 display_help();
723                                 ++errcnt;
724                                 break;
725                         default:
726                                 display_version();
727                                 printf("Unknown switch: %s\n\n", argv[argno]);
728                                 display_help();
729                                 ++errcnt;
730                                 break;
731                         }
732                 }
733                 else
734                 {
735                         // Record first filename.
736                         if (firstfname == NULL)
737                                 firstfname = argv[argno];
738
739                         strcpy(fnbuf, argv[argno]);
740                         fext(fnbuf, ".s", 0);
741                         fd = open(fnbuf, 0);
742
743                         if (fd < 0)
744                         {
745                                 printf("Cannot open: %s\n", fnbuf);
746                                 ++errcnt;
747                                 continue;
748                         }
749
750                         include(fd, fnbuf);
751                         assemble();
752                 }
753         }
754
755         // Wind-up processing;
756         // o  save current section (no more code generation)
757         // o  do auto-even of all sections (or boundary alignment as requested through '-r')
758         // o  determine name of object file:
759         //    -  "foo.o" for linkable output;
760         //    -  "foo.prg" for GEMDOS executable (-p flag).
761         savsect();
762
763         for(i=TEXT; i<=BSS; i<<=1)
764         {
765                 switchsect(i);
766
767                 switch(segpadsize)
768                 {
769                 case 2:  d_even();    break;
770                 case 4:  d_long();    break;
771                 case 8:  d_phrase();  break;
772                 case 16: d_dphrase(); break;
773                 case 32: d_qphrase(); break;
774                 }
775
776                 savsect();
777         }
778
779         if (objfname == NULL)
780         {
781                 if (firstfname == NULL)
782                         firstfname = defname;
783
784                 strcpy(fnbuf, firstfname);
785                 //fext(fnbuf, prg_flag ? ".prg" : ".o", 1);
786                 fext(fnbuf, ".o", 1);
787                 objfname = fnbuf;
788         }
789
790         // With one pass finished, go back and:
791         // (1)   run through all the fixups and resolve forward references;
792         // (1.5) ensure that remaining fixups can be handled by the linker
793         //       (`lo68' format, extended (postfix) format....)
794         // (2)   generate the output file image and symbol table;
795         // (3)   generate relocation information from left-over fixups.
796         ResolveAllFixups();                                             // Do all fixups
797         stopmark();                                                             // Stop mark tape-recorder
798
799         if (errcnt == 0)
800         {
801                 if ((fd = open(objfname, _OPEN_FLAGS, _PERM_MODE)) < 0)
802                         cantcreat(objfname);
803
804                 if (verb_flag)
805                 {
806                         s = "object";
807                         printf("[Writing %s file: %s]\n", s, objfname);
808                 }
809
810                 object((WORD)fd);
811                 close(fd);
812
813                 if (errcnt != 0)
814                         unlink(objfname);
815         }
816
817         if (list_flag)
818         {
819                 if (verb_flag)
820                         printf("[Wrapping-up listing file]\n");
821
822                 listing = 1;
823                 symtable();
824                 close(list_fd);
825         }
826
827         if (err_flag)
828                 close(err_fd);
829
830         DEBUG dump_everything();
831
832         return errcnt;
833 }
834
835
836 //
837 // Determine Processor Endianess
838 //
839 int get_endianess(void)
840 {
841         int i = 1;
842         char * p = (char *)&i;
843
844         if (p[0] == 1)
845                 return 0;
846
847         return 1;
848 }
849
850
851 //
852 // Application Entry Point; Handle the Command Line
853 //
854 int main(int argc, char ** argv)
855 {
856         int status;
857         int i;
858
859         perm_verb_flag = 0;                             // Clobber "permanent" verbose flag
860         cmdlnexec = argv[0];                    // Obtain executable name
861
862         endian = get_endianess();               // Get processor endianess
863
864         for(i=0; i<MAXFWDJUMPS; i++)
865                 fwdjump[i] = 0;
866
867         // Full command line passed
868         if (argc > 1)
869         {
870                 status = process(argc - 1, argv + 1);              
871         }
872         else
873         {
874                 display_version();
875                 display_help();
876         }
877
878         return status;
879 }