New Memory Allocation functions
[fw/sdcc] / as / mcs51 / asout.c
1 /* asout.c */
2
3 /*
4  * (C) Copyright 1989-1995
5  * All Rights Reserved
6  *
7  * Alan R. Baldwin
8  * 721 Berkeley St.
9  * Kent, Ohio  44240
10  *
11  * 28-Oct-97 JLH: 
12  *           - outsym: show s_id as string rather than array [NCPS]
13  *           - Added outr11 to support 8051's 11 bit destination address
14  */
15
16 #include <stdio.h>
17 #include <setjmp.h>
18 #include <string.h>
19 //#if !defined(_MSC_VER)
20 //#include <alloc.h>
21 //#endif
22 #include "asm.h"
23
24
25 /*)Module       asout.c
26  *
27  *      The module asout.c contains all the functions used to
28  *      generate the .REL assembler output file.
29  *
30  *
31  *      The  assemblers' output object file is an ascii file containing
32  *      the information needed by the linker  to  bind  multiple  object
33  *      modules into a complete loadable memory image.  
34  *
35  *      The object module contains the following designators:  
36  *
37  *              [XDQ][HL]
38  *                      X        Hexadecimal radix
39  *                      D        Decimal radix
40  *                      Q        Octal radix
41  *      
42  *                      H        Most significant byte first
43  *                      L        Least significant byte first
44  *      
45  *              H        Header 
46  *              M        Module
47  *              A        Area
48  *              S        Symbol
49  *              T        Object code
50  *              R        Relocation information
51  *              P        Paging information
52  *
53  *
54  *      (1)     Radix Line
55  *
56  *      The  first  line  of  an object module contains the [XDQ][HL]
57  *      format specifier (i.e.  XH indicates  a  hexadecimal  file  with
58  *      most significant byte first) for the following designators.  
59  *
60  *
61  *      (2)     Header Line
62  *
63  *              H aa areas gg global symbols 
64  *
65  *      The  header  line  specifies  the number of areas(aa) and the
66  *      number of global symbols(gg) defined or referenced in  this  ob-
67  *      ject module segment.  
68  *
69  *
70  *      (3)     Module Line 
71  *
72  *              M name 
73  *
74  *      The  module  line  specifies  the module name from which this
75  *      header segment was assembled.  The module line will  not  appear
76  *      if the .module directive was not used in the source program.  
77  *
78  *
79  *      (4)     Symbol Line 
80  *
81  *              S string Defnnnn 
82  *
83  *                      or 
84  *
85  *              S string Refnnnn 
86  *
87  *      The  symbol line defines (Def) or references (Ref) the symbol
88  *      'string' with the value nnnn.  The defined value is relative  to
89  *      the  current area base address.  References to constants and ex-
90  *      ternal global symbols will always appear before the  first  area
91  *      definition.  References to external symbols will have a value of
92  *      zero.  
93  *
94  *
95  *      (5)     Area Line 
96  *
97  *              A label size ss flags ff 
98  *
99  *      The  area  line  defines the area label, the size (ss) of the
100  *      area in bytes, and the area flags (ff).  The area flags  specify
101  *      the ABS, REL, CON, OVR, and PAG parameters:  
102  *
103  *              OVR/CON (0x04/0x00 i.e.  bit position 2) 
104  *
105  *              ABS/REL (0x08/0x00 i.e.  bit position 3) 
106  *
107  *              PAG (0x10 i.e.  bit position 4) 
108  *
109  *
110  *      (6)     T Line 
111  *
112  *              T xx xx nn nn nn nn nn ...  
113  *
114  *      The  T  line contains the assembled code output by the assem-
115  *      bler with xx xx being the offset address from the  current  area
116  *      base address and nn being the assembled instructions and data in
117  *      byte format.  
118  *
119  *
120  *      (7)     R Line 
121  *
122  *              R 0 0 nn nn n1 n2 xx xx ...  
123  *
124  *      The R line provides the relocation information to the linker.
125  *      The nn nn value is the current area index, i.e.  which area  the
126  *      current  values  were  assembled.  Relocation information is en-
127  *      coded in groups of 4 bytes:  
128  *
129  *      1.  n1 is the relocation mode and object format 
130  *              1.  bit 0 word(0x00)/byte(0x01) 
131  *              2.  bit 1 relocatable area(0x00)/symbol(0x02) 
132  *              3.  bit 2 normal(0x00)/PC relative(0x04) relocation 
133  *              4.  bit  3  1-byte(0x00)/2-byte(0x08) object format for
134  *                  byte data 
135  *              5.  bit 4 signed(0x00)/unsigned(0x10) byte data 
136  *              6.  bit 5 normal(0x00)/page '0'(0x20) reference 
137  *              7.  bit 6 normal(0x00)/page 'nnn'(0x40) reference 
138  *              8.  bit 7 normal(0x00)/MSB of value
139  *
140  *      2.  n2  is  a byte index into the corresponding (i.e.  pre-
141  *              ceeding) T line data (i.e.  a pointer to the data to be
142  *              updated  by  the  relocation).   The T line data may be
143  *              1-byte or  2-byte  byte  data  format  or  2-byte  word
144  *              format.  
145  *
146  *      3.  xx xx  is the area/symbol index for the area/symbol be-
147  *              ing referenced.  the corresponding area/symbol is found
148  *              in the header area/symbol lists.  
149  *
150  *
151  *      The groups of 4 bytes are repeated for each item requiring relo-
152  *      cation in the preceeding T line.  
153  *
154  *
155  *      (8)     P Line 
156  *
157  *              P 0 0 nn nn n1 n2 xx xx 
158  *
159  *      The  P  line provides the paging information to the linker as
160  *      specified by a .setdp directive.  The format of  the  relocation
161  *      information is identical to that of the R line.  The correspond-
162  *      ing T line has the following information:  
163  *              T xx xx aa aa bb bb 
164  *
165  *      Where  aa aa is the area reference number which specifies the
166  *      selected page area and bb bb is the base address  of  the  page.
167  *      bb bb will require relocation processing if the 'n1 n2 xx xx' is
168  *      specified in the P line.  The linker will verify that  the  base
169  *      address is on a 256 byte boundary and that the page length of an
170  *      area defined with the PAG type is not larger than 256 bytes.  
171  *
172  *      The  linker  defaults any direct page references to the first
173  *      area defined in the input REL file.  All ASxxxx assemblers  will
174  *      specify the _CODE area first, making this the default page area. 
175  *
176  *
177  *      asout.c contains the following functions:
178  *              int     lobyte()
179  *              int     hibyte()
180  *              VOID    out()
181  *              VOID    outab()
182  *              VOID    outall()
183  *              VOID    outarea()
184  *              VOID    outaw()
185  *              VOID    outbuf()
186  *              VOID    outchk()
187  *              VOID    outdot()
188  *              VOID    outdp()
189  *              VOID    outgsd()
190  *              VOID    outrb()
191  *              VOID    outrw()
192  *              VOID    outsym()
193  *              VOID    out_lb()
194  *              VOID    out_lw()
195  *              VOID    out_rw()
196  *              VOID    out_tw()
197  *
198  *      The module asout.c contains the following local variables:
199  *              int     rel[]           relocation data for code/data array
200  *              int *   relp            pointer to rel array
201  *              int     txt[]           assembled code/data array
202  *              int *   txtp            pointer to txt array
203  */
204
205 #define  NTXT   16
206 #define  NREL   16
207
208 char     txt[NTXT];
209 char     rel[NREL];
210
211 char    *txtp = { &txt[0] };
212 char    *relp = { &rel[0] };
213
214 /*)Function     VOID    outab(b)
215  *
216  *              int     b               assembler data word
217  *
218  *      The function outab() processes a single word of
219  *      assembled data in absolute format.
220  *
221  *      local variables:
222  *              int *   txtp            pointer to data word
223  *
224  *      global variables:
225  *              int     oflag           -o, generate relocatable output flag
226  *              int     pass            assembler pass number
227  *
228  *      functions called:
229  *              VOID    outchk()        asout.c
230  *              VOID    out_lb()        asout.c
231  *
232  *      side effects:
233  *              The current assembly address is incremented by 1.
234  */
235
236 VOID
237 outab(b)
238 {
239         if (pass == 2) {
240                 out_lb(b,0);
241                 if (oflag) {
242                         outchk(1, 0);
243                         *txtp++ = lobyte(b);
244                 }
245         }
246         ++dot.s_addr;
247 }
248
249 /*)Function     VOID    outaw(w)
250  *
251  *              int     w               assembler data word
252  *
253  *      The function outaw() processes a single word of
254  *      assembled data in absolute format.
255  *
256  *      local variables:
257  *              int *   txtp            pointer to data word
258  *
259  *      global variables:
260  *              int     oflag           -o, generate relocatable output flag
261  *              int     pass            assembler pass number
262  *
263  *      functions called:
264  *              VOID    outchk()        asout.c
265  *              VOID    out_lw()        asout.c
266  *
267  *      side effects:
268  *              The current assembly address is incremented by 2.
269  */
270
271 VOID
272 outaw(w)
273 {
274         if (pass == 2) {
275                 out_lw(w,0);
276                 if (oflag) {
277                         outchk(2, 0);
278                         out_tw(w);
279                 }
280         }
281         dot.s_addr += 2;
282 }
283
284 /*)Function     VOID    write_rmode(r)
285  *
286  *              int     r               relocation mode
287  *
288  *      write_rmode puts the passed relocation mode into the 
289  *      output relp buffer, escaping it if necessary.
290  *
291  *      global variables:
292  *              int *   relp            pointer to rel array
293  *
294  *      functions called:
295  *              VOID    rerr()          assubr.c
296  *
297  *      side effects:
298  *              relp is incremented appropriately.
299  */
300 VOID
301 write_rmode(int r)
302 {
303     /* We need to escape the relocation mode if it is greater
304      * than a byte, or if it happens to look like an escape.
305      * (I don't think that the latter case is legal, but
306      * better safe than sorry).
307      */
308     if ((r > 0xff) || ((r & R_ESCAPE_MASK) == R_ESCAPE_MASK))
309     {
310         /* Hack in up to an extra 4 bits of flags with escape. */
311         if (r > 0xfff)
312         {
313              /* uh-oh.. we have more than 4 extra bits. */
314              fprintf(stderr, 
315                      "Internal error: relocation mode 0x%X too big.\n", 
316                      r);
317              rerr();
318         }
319         /* printf("escaping relocation mode\n"); */
320         *relp++ = R_ESCAPE_MASK | (r >> 8);
321         *relp++ = r & 0xff;
322     }
323     else
324     {
325         *relp++ = r;
326     }
327 }
328
329 /*)Function     VOID    outrb(esp, r)
330  *
331  *              expr *  esp             pointer to expr structure
332  *              int     r               relocation mode
333  *
334  *      The function outrb() processes a byte of generated code
335  *      in either absolute or relocatable format dependent upon
336  *      the data contained in the expr structure esp.  If the
337  *      .REL output is enabled then the appropriate information
338  *      is loaded into the txt and rel buffers.
339  *
340  *      local variables:
341  *              int     n               symbol/area reference number
342  *              int *   relp            pointer to rel array
343  *              int *   txtp            pointer to txt array
344  *
345  *      global variables:
346  *              sym     dot             defined as sym[0]
347  *              int     oflag           -o, generate relocatable output flag
348  *              int     pass            assembler pass number
349  *              
350  *      functions called:
351  *              VOID    aerr()          assubr.c
352  *              VOID    outchk()        asout.c
353  *              VOID    out_lb()        asout.c
354  *              VOID    out_rb()        asout.c
355  *              VOID    out_tb()        asout.c
356  *
357  *      side effects:
358  *              The current assembly address is incremented by 1.
359  */
360
361 VOID
362 outrb(struct expr *esp, int r)
363 {
364         register int n;
365
366         if (pass == 2) {
367                 if (esp->e_flag==0 && esp->e_base.e_ap==NULL) {
368                         /* This is a constant; simply write the
369                          * const byte to the T line and don't
370                          * generate any relocation info.
371                          */
372                         out_lb(lobyte(esp->e_addr),0);
373                         if (oflag) {
374                                 outchk(1, 0);
375                                 *txtp++ = lobyte(esp->e_addr);
376                         }
377                 } else {
378                         /* We are generating a single byte of relocatable
379                          * info.
380                          *
381                          * In 8051 mode, we generate a 16 bit address. The 
382                          * linker will later select a single byte based on
383                          * whether R_MSB is set.
384                          *
385                          * In flat24 mode, we generate a 24 bit address. The
386                          * linker will select a single byte based on 
387                          * whether R_MSB or R_HIB is set.
388                          */
389                         if (!flat24Mode)
390                         { 
391                             r |= R_BYTE | R_BYT2 | esp->e_rlcf;
392                             if (r & R_MSB) {
393                                 out_lb(hibyte(esp->e_addr),r|R_RELOC|R_HIGH);
394                             } else {
395                                 out_lb(lobyte(esp->e_addr),r|R_RELOC);
396                             }
397                             if (oflag) {
398                                 outchk(2, 5);
399                                 out_tw(esp->e_addr);
400                                 if (esp->e_flag) {
401                                         n = esp->e_base.e_sp->s_ref;
402                                         r |= R_SYM;
403                                 } else {
404                                         n = esp->e_base.e_ap->a_ref;
405                                 }
406                                 write_rmode(r);
407                                 *relp++ = txtp - txt - 2;
408                                 out_rw(n);
409                             }
410                         }
411                         else
412                         {
413                             /* 24 bit mode. */
414                             r |= R_BYTE | R_BYT3 | esp->e_rlcf;
415                             if (r & R_HIB)
416                             {
417                                 /* Probably should mark this differently in the
418                                  * listing file.
419                                  */
420                                 out_lb(byte3(esp->e_addr),r|R_RELOC|R_HIGH);
421                             }
422                             else if (r & R_MSB) {
423                                 out_lb(hibyte(esp->e_addr),r|R_RELOC|R_HIGH);
424                             } else {
425                                 out_lb(lobyte(esp->e_addr),r|R_RELOC);
426                             }
427                             if (oflag) {
428                                 outchk(3, 5);
429                                 out_t24(esp->e_addr);
430                                 if (esp->e_flag) {
431                                         n = esp->e_base.e_sp->s_ref;
432                                         r |= R_SYM;
433                                 } else {
434                                         n = esp->e_base.e_ap->a_ref;
435                                 }
436                                 write_rmode(r);
437                                 *relp++ = txtp - txt - 3;
438                                 out_rw(n);                          
439                             }
440                         }
441                 }
442         }
443         ++dot.s_addr;
444 }
445
446 /*)Function     VOID    outrw(esp, r)
447  *
448  *              expr *  esp             pointer to expr structure
449  *              int     r               relocation mode
450  *
451  *      The function outrw() processes a word of generated code
452  *      in either absolute or relocatable format dependent upon
453  *      the data contained in the expr structure esp.  If the
454  *      .REL output is enabled then the appropriate information
455  *      is loaded into the txt and rel buffers.
456  *
457  *      local variables:
458  *              int     n               symbol/area reference number
459  *              int *   relp            pointer to rel array
460  *              int *   txtp            pointer to txt array
461  *
462  *      global variables:
463  *              sym     dot             defined as sym[0]
464  *              int     oflag           -o, generate relocatable output flag
465  *              int     pass            assembler pass number
466  *              
467  *      functions called:
468  *              VOID    aerr()          assubr.c
469  *              VOID    outchk()        asout.c
470  *              VOID    out_lw()        asout.c
471  *              VOID    out_rw()        asout.c
472  *              VOID    out_tw()        asout.c
473  *
474  *      side effects:
475  *              The current assembly address is incremented by 2.
476  */
477
478 VOID
479 outrw(struct expr *esp, int r)
480 {
481         register int n;
482
483         if (pass == 2) {
484         
485                 if (esp->e_addr > 0xffff)
486                 {
487                     warnBanner();
488                     fprintf(stderr,
489                             "large constant 0x%x truncated to 16 bits\n",
490                             esp->e_addr);
491                 }
492                 if (esp->e_flag==0 && esp->e_base.e_ap==NULL) {
493                         out_lw(esp->e_addr,0);
494                         if (oflag) {
495                                 outchk(2, 0);
496                                 out_tw(esp->e_addr);
497                         }
498                 } else {
499                         r |= R_WORD | esp->e_rlcf;
500                         if (r & R_BYT2) {
501                                 rerr();
502                                 if (r & R_MSB) {
503                                         out_lw(hibyte(esp->e_addr),r|R_RELOC);
504                                 } else {
505                                         out_lw(lobyte(esp->e_addr),r|R_RELOC);
506                                 }
507                         } else {
508                                 out_lw(esp->e_addr,r|R_RELOC);
509                         }
510                         if (oflag) {
511                                 outchk(2, 5);
512                                 out_tw(esp->e_addr);
513                                 if (esp->e_flag) {
514                                         n = esp->e_base.e_sp->s_ref;
515                                         r |= R_SYM;
516                                 } else {
517                                         n = esp->e_base.e_ap->a_ref;
518                                 }
519                                 
520                                 if (IS_C24(r))
521                                 {
522                                     /* If this happens, the linker will
523                                      * attempt to process this 16 bit field
524                                      * as 24 bits. That would be bad.
525                                      */
526                                     fprintf(stderr,
527                                             "***Internal error: C24 out in "
528                                             "outrw()\n");
529                                     rerr();
530                                 }
531                                 write_rmode(r);
532                                 *relp++ = txtp - txt - 2;
533                                 out_rw(n);
534                         }
535                 }
536         }
537         dot.s_addr += 2;
538 }
539
540 /*)Function     VOID    outr24(esp, r)
541  *
542  *              expr *  esp             pointer to expr structure
543  *              int     r               relocation mode
544  *
545  *      The function outr24() processes 24 bits of generated code
546  *      in either absolute or relocatable format dependent upon
547  *      the data contained in the expr structure esp.  If the
548  *      .REL output is enabled then the appropriate information
549  *      is loaded into the txt and rel buffers.
550  *
551  *      local variables:
552  *              int     n               symbol/area reference number
553  *              int *   relp            pointer to rel array
554  *              int *   txtp            pointer to txt array
555  *
556  *      global variables:
557  *              sym     dot             defined as sym[0]
558  *              int     oflag           -o, generate relocatable output flag
559  *              int     pass            assembler pass number
560  *              
561  *      functions called:
562  *              VOID    aerr()          assubr.c
563  *              VOID    outchk()        asout.c
564  *              VOID    out_l24()       asout.c
565  *              VOID    out_rw()        asout.c
566  *              VOID    out_t24()       asout.c
567  *
568  *      side effects:
569  *              The current assembly address is incremented by 3.
570  */
571
572 VOID
573 outr24(struct expr *esp, int r)
574 {
575         register int n;
576
577         if (pass == 2) {
578                 if (esp->e_flag==0 && esp->e_base.e_ap==NULL) {
579                         /* This is a constant expression. */
580                         out_l24(esp->e_addr,0);
581                         if (oflag) {
582                                 outchk(3, 0);
583                                 out_t24(esp->e_addr);
584                         }
585                 } else {
586                         /* This is a symbol. */
587                         r |= R_WORD | esp->e_rlcf;
588                         if (r & R_BYT2) {
589                                 /* I have no idea what this case is. */
590                                 rerr();
591                                 if (r & R_MSB) {
592                                         out_lw(hibyte(esp->e_addr),r|R_RELOC);
593                                 } else {
594                                         out_lw(lobyte(esp->e_addr),r|R_RELOC);
595                                 }
596                         } else {
597                                 out_l24(esp->e_addr,r|R_RELOC);
598                         }
599                         if (oflag) {
600                                 outchk(3, 5);
601                                 out_t24(esp->e_addr);
602                                 if (esp->e_flag) {
603                                         n = esp->e_base.e_sp->s_ref;
604                                         r |= R_SYM;
605                                 } else {
606                                         n = esp->e_base.e_ap->a_ref;
607                                 }
608                                 
609                                 if (r & R_BYTE)
610                                 {
611                                     /* If this occurs, we cannot properly
612                                      * code the relocation data with the
613                                      * R_C24 flag. This means the linker
614                                      * will fail to do the 24 bit relocation.
615                                      * Which will suck.
616                                      */
617                                     fprintf(stderr,
618                                             "***Internal error: BYTE out in 24 "
619                                             "bit flat mode unexpected.\n");
620                                     rerr();
621                                 }
622                                 
623                                 write_rmode(r | R_C24);
624                                 *relp++ = txtp - txt - 3;
625                                 out_rw(n);
626                         }
627                 }
628         }
629         dot.s_addr += 3;
630 }
631
632 /*)Function     VOID    outdp(carea, esp)
633  *
634  *              area *  carea           pointer to current area strcuture
635  *              expr *  esp             pointer to expr structure
636  *
637  *      The function outdp() flushes the output buffer and
638  *      outputs paging information to the .REL file.
639  *
640  *      local variables:
641  *              int     n               symbol/area reference number
642  *              int     r               relocation mode
643  *              int *   relp            pointer to rel array
644  *              int *   txtp            pointer to txt array
645  *
646  *      global variables:
647  *              int     oflag           -o, generate relocatable output flag
648  *              int     pass            assembler pass number
649  *              
650  *      functions called:
651  *              VOID    outbuf()        asout.c
652  *              VOID    outchk()        asout.c
653  *              VOID    out_rw()        asout.c
654  *              VOID    out_tw()        asout.c
655  *
656  *      side effects:
657  *              Output buffer flushed to .REL fiel.
658  *              Paging information dumped to .REL file.
659  */
660
661 VOID
662 outdp(carea, esp)
663 register struct area *carea;
664 register struct expr *esp;
665 {
666         register int n, r;
667
668         if (oflag && pass==2) {
669                 outchk(HUGE,HUGE);
670                 out_tw(carea->a_ref);
671                 out_tw(esp->e_addr);
672                 if (esp->e_flag || esp->e_base.e_ap!=NULL) {
673                         r = R_WORD;
674                         if (esp->e_flag) {
675                                 n = esp->e_base.e_sp->s_ref;
676                                 r |= R_SYM;
677                         } else {
678                                 n = esp->e_base.e_ap->a_ref;
679                         }
680                         write_rmode(r);
681                         *relp++ = txtp - txt - 2;
682                         out_rw(n);
683                 }
684                 outbuf("P");
685         }
686 }
687
688 /*)Function     VOID    outall()
689  *
690  *      The function outall() will output any bufferred assembled
691  *      data and relocation information (during pass 2 if the .REL
692  *      output has been enabled).
693  *
694  *      local variables:
695  *              none
696  *
697  *      global variables:
698  *              int     oflag           -o, generate relocatable output flag
699  *              int     pass            assembler pass number
700  *
701  *      functions called:
702  *              VOID    outbuf()        asout.c
703  *
704  *      side effects:
705  *              assembled data and relocation buffers will be cleared.
706  */
707
708 VOID
709 outall()
710 {
711         if (oflag && pass==2)
712                 outbuf("R");
713 }
714
715 /*)Function     VOID    outdot()
716  *
717  *      The function outdot() outputs information about the
718  *      current program counter value (during pass 2 if the .REL
719  *      output has been enabled).
720  *
721  *      local variables:
722  *              none
723  *
724  *      global variables:
725  *              int     oflag           -o, generate relocatable output flag
726  *              int     pass            assembler pass number
727  *
728  *      functions called:
729  *              int     fprintf()       c_library
730  *              VOID    out()           asout.c
731  *
732  *      side effects:
733  *              assembled data and relocation buffers will be cleared.
734  */
735
736 VOID
737 outdot()
738 {
739         if (oflag && pass==2) {
740                 fprintf(ofp, "T");
741                 out(txt,(int) (txtp-txt));
742                 fprintf(ofp, "\n");
743                 fprintf(ofp, "R");
744                 out(rel,(int) (relp-rel));
745                 fprintf(ofp, "\n");
746                 txtp = txt;
747                 relp = rel;
748         }
749 }
750
751 /*)Function     outchk(nt, nr)
752  *
753  *              int     nr              number of additional relocation words
754  *              int     nt              number of additional data words
755  *
756  *      The function outchk() checks the data and relocation buffers
757  *      for space to insert the nt data words and nr relocation words.
758  *      If space is not available then output the current data and
759  *      initialize the data buffers to receive the new data.
760  *
761  *      local variables:
762  *              area *  ap              pointer to an area structure
763  *              int *   relp            pointer to rel array
764  *              int *   txtp            pointer to txt array
765  *
766  *      global variables:
767  *              sym     dot             defined as sym[0]
768  *
769  *      functions called:
770  *              VOID    outbuf()        asout.c
771  *
772  *      side effects:
773  *              Data and relocation buffers may be emptied and initialized.
774  */
775
776 VOID
777 outchk(nt, nr)
778 {
779         register struct area *ap;
780
781         if (txtp+nt > &txt[NTXT] || relp+nr > &rel[NREL]) {
782                 outbuf("R");
783         }
784         if (txtp == txt) {
785                 out_tw(dot.s_addr);
786                 if ((ap = dot.s_area) != NULL) {
787                         write_rmode(R_WORD|R_AREA);
788                         *relp++ = 0;
789                         out_rw(ap->a_ref);
790                 }
791         }
792 }
793
794 /*)Function     VOID    outbuf()
795  *
796  *      The function outbuf() will output any bufferred data
797  *      and relocation information to the .REL file.  The output
798  *      buffer pointers and counters are initialized.
799  *
800  *      local variables:
801  *              int     rel[]           relocation data for code/data array
802  *              int *   relp            pointer to rel array
803  *              int     txt[]           assembled code/data array
804  *              int *   txtp            pointer to txt array
805  *
806  *      global variables:
807  *              FILE *  ofp             relocation output file handle
808  *
809  *      functions called:
810  *              VOID    out()           asout.c
811  *
812  *      side effects:
813  *              All bufferred data written to .REL file and
814  *              buffer pointers and counters initialized.
815  */
816
817 VOID
818 outbuf(s)
819 char *s;
820 {
821         if (txtp > &txt[2]) {
822                 fprintf(ofp, "T");
823                 out(txt,(int) (txtp-txt));
824                 fprintf(ofp, "\n");
825                 fprintf(ofp, "%s", s);
826                 out(rel,(int) (relp-rel));
827                 fprintf(ofp, "\n");
828         }
829         txtp = txt;
830         relp = rel;
831 }
832
833 /*)Function     VOID    outgsd()
834  *
835  *      The function outgsd() performs the following:
836  *      (1)     outputs the .REL file radix
837  *      (2)     outputs the header specifying the number
838  *              of areas and global symbols
839  *      (3)     outputs the module name
840  *      (4)     set the reference number and output a symbol line
841  *              for all external global variables and absolutes
842  *      (5)     output an area name, set reference number and output
843  *              a symbol line for all global relocatables in the area.
844  *              Repeat this proceedure for all areas.
845  *
846  *      local variables:
847  *              area *  ap              pointer to an area structure
848  *              sym *   sp              pointer to a sym structure
849  *              int     i               loop counter
850  *              int     j               loop counter
851  *              int     c               string character value
852  *              int     narea           number of code areas
853  *              char *  ptr             string pointer
854  *              int     nglob           number of global symbols
855  *              int     rn              symbol reference number
856  *
857  *      global variables:
858  *              area *  areap           pointer to an area structure
859  *              char    module[]        module name string
860  *              sym * symhash[]         array of pointers to NHASH
861  *                                      linked symbol lists
862  *              int     xflag           -x, listing radix flag
863  *
864  *      functions called:
865  *              int     fprintf()       c_library
866  *              VOID    outarea()       asout.c
867  *              VOID    outsym()        asout.c
868  *              int     putc()          c_library
869  *
870  *      side effects:
871  *              All symbols are given reference numbers, all symbol
872  *              and area information is output to the .REL file.
873  */
874
875 VOID
876 outgsd()
877 {
878         register struct area *ap;
879         register struct sym  *sp;
880         register int i, j;
881         char *ptr;
882         int c, narea, nglob, rn;
883
884         /*
885          * Number of areas
886          */
887         narea = areap->a_ref + 1;
888
889         /*
890          * Number of global references/absolutes
891          */
892         nglob = 0;
893         for (i = 0; i < NHASH; ++i) {
894                 sp = symhash[i];
895                 while (sp) {
896                         if (sp->s_flag&S_GBL)
897                                 ++nglob;
898                         sp = sp->s_sp;
899                 }
900         }
901
902         /*
903          * Output Radix and number of areas and symbols
904          */
905         if (xflag == 0) {
906                 fprintf(ofp, "X%c\n", hilo ? 'H' : 'L');
907                 fprintf(ofp, "H %X areas %X global symbols\n", narea, nglob);
908         } else
909         if (xflag == 1) {
910                 fprintf(ofp, "Q%c\n", hilo ? 'H' : 'L');
911                 fprintf(ofp, "H %o areas %o global symbols\n", narea, nglob);
912         } else
913         if (xflag == 2) {
914                 fprintf(ofp, "D%c\n", hilo ? 'H' : 'L');
915                 fprintf(ofp, "H %u areas %u global symbols\n", narea, nglob);
916         }               
917
918         /*
919          * Module name
920          */
921         if (module[0]) {
922                 fprintf(ofp, "M ");
923                 ptr = &module[0];
924                 while (ptr < &module[NCPS]) {
925                         if ((c = *ptr++) != 0)
926                                 putc(c, ofp);
927                 }
928                 putc('\n', ofp);
929         }
930
931         /*
932          * Global references and absolutes.
933          */
934         rn = 0;
935         for (i=0; i<NHASH; ++i) {
936                 sp = symhash[i];
937                 while (sp) {
938                         if (sp->s_area==NULL && sp->s_flag&S_GBL) {
939                                 sp->s_ref = rn++;
940                                 outsym(sp);
941                         }
942                         sp = sp->s_sp;
943                 }
944         }
945
946         /*
947          * Global relocatables.
948          */
949         for (i=0; i<narea; ++i) {
950                 ap = areap;
951                 while (ap->a_ref != i)
952                         ap = ap->a_ap;
953                 outarea(ap);
954                 for (j=0; j<NHASH; ++j) {
955                         sp = symhash[j];
956                         while (sp) {
957                                 if (sp->s_area==ap && sp->s_flag&S_GBL) {
958                                         sp->s_ref = rn++;
959                                         outsym(sp);
960                                 }
961                                 sp = sp->s_sp;
962                         }
963                 }
964         }
965 }
966
967 /*)Function     VOID    outarea(ap)
968  *
969  *              area *  ap              pointer to an area structure
970  *
971  *      The function outarea()  outputs the A line to the .REL
972  *      file.  The A line contains the area's name, size, and
973  *      attributes.
974  *
975  *      local variables:
976  *              char *  ptr             pointer to area id string
977  *              int     c               character value
978  *
979  *      global variables:
980  *              FILE *  ofp             relocation output file handle
981  *              int     xflag           -x, listing radix flag
982  *
983  *      functions called:
984  *              int     fprintf()       c_library
985  *              int     putc()          c_library
986  *
987  *      side effects:
988  *              The A line is sent to the .REL file.
989  */
990
991 VOID
992 outarea(ap)
993 register struct area *ap;
994 {
995         register char *ptr;
996         register int c;
997
998         fprintf(ofp, "A ");
999         ptr = &ap->a_id[0];
1000         while (ptr < &ap->a_id[NCPS]) {
1001                 if ((c = *ptr++) != 0)
1002                         putc(c, ofp);
1003         }
1004         if (xflag == 0) {
1005                 fprintf(ofp, " size %X flags %X\n", ap->a_size, ap->a_flag);
1006         } else
1007         if (xflag == 1) {
1008                 fprintf(ofp, " size %o flags %o\n", ap->a_size, ap->a_flag);
1009         } else
1010         if (xflag == 2) {
1011                 fprintf(ofp, " size %u flags %u\n", ap->a_size, ap->a_flag);
1012         }
1013 }
1014
1015 /*)Function     VOID    outsym(sp)
1016  *
1017  *              sym *   sp              pointer to a sym structure
1018  *
1019  *      The function outsym() outputs the S line to the .REL
1020  *      file.  The S line contains the symbols name and whether the
1021  *      the symbol is defined or referenced.
1022  *
1023  *      local variables:
1024  *              char *  ptr             pointer to symbol id string
1025  *              int     c               character value
1026  *
1027  *      global variables:
1028  *              FILE *  ofp             relocation output file handle
1029  *              int     xflag           -x, listing radix flag
1030  *
1031  *      functions called:
1032  *              int     fprintf()       c_library
1033  *              int     putc()          c_library
1034  *
1035  *      side effects:
1036  *              The S line is sent to the .REL file.
1037  */
1038
1039 VOID
1040 outsym(sp)
1041 register struct sym *sp;
1042 {
1043         register char *ptr;       
1044
1045         fprintf(ofp, "S ");
1046         ptr = &sp->s_id[0];
1047         fprintf(ofp, "%s", ptr );
1048         fprintf(ofp, " %s", sp->s_type==S_NEW ? "Ref" : "Def");
1049         if (xflag == 0) {
1050                 fprintf(ofp, "%04X\n", sp->s_addr);
1051         } else
1052         if (xflag == 1) {
1053                 fprintf(ofp, "%06o\n", sp->s_addr);
1054         } else
1055         if (xflag == 2) {
1056                 fprintf(ofp, "%05u\n", sp->s_addr);
1057         }
1058 }
1059
1060 /*)Function     VOID    out(p, n)
1061  *
1062  *              int     n               number of words to output
1063  *              int *   p               pointer to data words
1064  *
1065  *      The function out() outputs the data words to the .REL file
1066  *      int the specified radix.
1067  *
1068  *      local variables:
1069  *              none
1070  *
1071  *      global variables:
1072  *              FILE *  ofp             relocation output file handle
1073  *              int     xflag           -x, listing radix flag
1074  *
1075  *      functions called:
1076  *              int     fprintf()       c_library
1077  *
1078  *      side effects:
1079  *              Data is sent to the .REL file.
1080  */
1081
1082 VOID
1083 out(char *p, int n)
1084 {
1085         while (n--) {
1086                 if (xflag == 0) {
1087                         fprintf(ofp, " %02X", (*p++)&0xff);
1088                 } else
1089                 if (xflag == 1) {
1090                         fprintf(ofp, " %03o", (*p++)&0xff);
1091                 } else
1092                 if (xflag == 2) {
1093                         fprintf(ofp, " %03u", (*p++)&0xff);
1094                 }
1095         }
1096 }
1097
1098 /*)Function     VOID    out_lb(b, t)
1099  *
1100  *              int     b               assembled data
1101  *              int     t               relocation type
1102  *
1103  *      The function out_lb() copies the assembled data and
1104  *      its relocation type to the list data buffers.
1105  *
1106  *      local variables:
1107  *              none
1108  *
1109  *      global variables:
1110  *              int *   cp              pointer to assembler output array cb[]
1111  *              int *   cpt             pointer to assembler relocation type
1112  *                                      output array cbt[]
1113  *
1114  *      functions called:
1115  *              none
1116  *
1117  *      side effects:
1118  *              Pointers to data and relocation buffers incremented by 1.
1119  */
1120
1121 VOID
1122 out_lb(b,t)
1123 register int b,t;
1124 {
1125         if (cp < &cb[NCODE]) {
1126                 *cp++ = b;
1127                 *cpt++ = t;
1128         }
1129 }
1130
1131 /*)Function     VOID    out_lw(n, t)
1132  *
1133  *              int     n               assembled data
1134  *              int     t               relocation type
1135  *
1136  *      The function out_lw() copies the assembled data and
1137  *      its relocation type to the list data buffers.
1138  *
1139  *      local variables:
1140  *              none
1141  *
1142  *      global variables:
1143  *              int *   cp              pointer to assembler output array cb[]
1144  *              int *   cpt             pointer to assembler relocation type
1145  *                                      output array cbt[]
1146  *
1147  *      functions called:
1148  *              none
1149  *
1150  *      side effects:
1151  *              Pointers to data and relocation buffers incremented by 2.
1152  */
1153
1154 VOID
1155 out_lw(n,t)
1156 register int n,t;
1157 {
1158         if (hilo) {
1159                 out_lb(hibyte(n),t ? t|R_HIGH : 0);
1160                 out_lb(lobyte(n),t);
1161         } else {
1162                 out_lb(lobyte(n),t);
1163                 out_lb(hibyte(n),t ? t|R_HIGH : 0);
1164         }
1165 }
1166
1167 /*)Function     VOID    out_l24(n, t)
1168  *
1169  *              int     n               assembled data
1170  *              int     t               relocation type
1171  *
1172  *      The function out_l24() copies the assembled data and
1173  *      its relocation type to the list data buffers.
1174  *
1175  *      local variables:
1176  *              none
1177  *
1178  *      global variables:
1179  *              int *   cp              pointer to assembler output array cb[]
1180  *              int *   cpt             pointer to assembler relocation type
1181  *                                      output array cbt[]
1182  *
1183  *      functions called:
1184  *              none
1185  *
1186  *      side effects:
1187  *              Pointers to data and relocation buffers incremented by 3.
1188  */
1189
1190 VOID
1191 out_l24(int n, int t)
1192 {
1193         if (hilo) {
1194                 out_lb(byte3(n),t ? t|R_HIGH : 0);
1195                 out_lb(hibyte(n),t);
1196                 out_lb(lobyte(n),t);
1197         } else {
1198                 out_lb(lobyte(n),t);
1199                 out_lb(hibyte(n),t);
1200                 out_lb(byte3(n),t ? t|R_HIGH : 0);
1201         }
1202 }
1203
1204 /*)Function     VOID    out_rw(n)
1205  *
1206  *              int     n               data word
1207  *
1208  *      The function out_rw() outputs the relocation (R)
1209  *      data word as two bytes ordered according to hilo.
1210  *
1211  *      local variables:
1212  *              int *   relp            pointer to rel array
1213  *
1214  *      global variables:
1215  *              none
1216  *
1217  *      functions called:
1218  *              int     lobyte()        asout.c
1219  *              int     hibyte()        asout.c
1220  *
1221  *      side effects:
1222  *              Pointer to relocation buffer incremented by 2.
1223  */
1224
1225 VOID
1226 out_rw(n)
1227 register int n;
1228 {
1229         if (hilo) {
1230                 *relp++ = hibyte(n);
1231                 *relp++ = lobyte(n);
1232         } else {
1233                 *relp++ = lobyte(n);
1234                 *relp++ = hibyte(n);
1235         }
1236 }
1237
1238 /*)Function     VOID    out_tw(n)
1239  *
1240  *              int     n               data word
1241  *
1242  *      The function out_tw() outputs the text (T)
1243  *      data word as two bytes ordered according to hilo.
1244  *
1245  *      local variables:
1246  *              int *   txtp            pointer to txt array
1247  *
1248  *      global variables:
1249  *              none
1250  *
1251  *      functions called:
1252  *              int     lobyte()        asout.c
1253  *              int     hibyte()        asout.c
1254  *
1255  *      side effects:
1256  *              Pointer to relocation buffer incremented by 2.
1257  */
1258
1259 VOID
1260 out_tw(n)
1261 register int n;
1262 {
1263         if (hilo) {
1264                 *txtp++ = hibyte(n);
1265                 *txtp++ = lobyte(n);
1266         } else {
1267                 *txtp++ = lobyte(n);
1268                 *txtp++ = hibyte(n);
1269         }
1270 }
1271
1272 /*)Function     VOID    out_t24(n)
1273  *
1274  *              int     n               data word
1275  *
1276  *      The function out_t24() outputs the text (T)
1277  *      data word as three bytes ordered according to hilo.
1278  *
1279  *      local variables:
1280  *              int *   txtp            pointer to txt array
1281  *
1282  *      global variables:
1283  *              none
1284  *
1285  *      functions called:
1286  *              int     lobyte()        asout.c
1287  *              int     hibyte()        asout.c
1288  *
1289  *      side effects:
1290  *              Pointer to relocation buffer incremented by 3.
1291  */
1292
1293 VOID
1294 out_t24(int n)
1295 {
1296         if (hilo) {
1297                 *txtp++ = byte3(n);
1298                 *txtp++ = hibyte(n);
1299                 *txtp++ = lobyte(n);
1300         } else {
1301                 *txtp++ = lobyte(n);
1302                 *txtp++ = hibyte(n);
1303                 *txtp++ = byte3(n);
1304         }
1305 }
1306
1307 /*)Function     int     lobyte(n)
1308  *
1309  *              int     n               data word
1310  *
1311  *      The function lobyte() returns the lower byte of
1312  *      integer n.
1313  *
1314  *      local variables:
1315  *              none
1316  *
1317  *      global variables:
1318  *              none
1319  *
1320  *      functions called:
1321  *              none
1322  *
1323  *      side effects:
1324  *              none
1325  */
1326
1327 int
1328 lobyte(n)
1329 {
1330         return (n&0377);
1331 }
1332
1333 /*)Function     int     hibyte(n)
1334  *
1335  *              int     n               data word
1336  *
1337  *      The function hibyte() returns the higher byte of
1338  *      integer n.
1339  *
1340  *      local variables:
1341  *              none
1342  *
1343  *      global variables:
1344  *              none
1345  *
1346  *      functions called:
1347  *              none
1348  *
1349  *      side effects:
1350  *              none
1351  */
1352
1353 int
1354 hibyte(n)
1355 {
1356         return ((n>>8)&0377);
1357 }
1358
1359 /*)Function     int     byte3(n)
1360  *
1361  *              int     n               24 bit data
1362  *
1363  *      The function byte3() returns the MSB of the
1364  *      24 bit integer n.
1365  *
1366  *      local variables:
1367  *              none
1368  *
1369  *      global variables:
1370  *              none
1371  *
1372  *      functions called:
1373  *              none
1374  *
1375  *      side effects:
1376  *              none
1377  */
1378 int
1379 byte3(int n)
1380 {
1381         return ((n >> 16) & 0xff);
1382 }
1383
1384 /*
1385  * JLH: Output relocatable 11 bit jump/call
1386  *
1387  * This function is derived from outrw(), adding the parameter for the
1388  * 11 bit address.  This form of address is used only on the 8051 and 8048.
1389  */
1390 VOID
1391 outr11(esp, op, r)
1392 register struct expr *esp;
1393 int op;
1394 int r;
1395 {
1396         register int n;
1397
1398         if (pass == 2) {
1399                 if (esp->e_flag==0 && esp->e_base.e_ap==NULL) {
1400                         /* equated absolute destination.  Assume value
1401                          * relative to current area */
1402                         esp->e_base.e_ap = dot.s_area;
1403                 }
1404
1405                 /* Relocatable destination.  Build THREE
1406                  * byte output: relocatable word, followed
1407                  * by op-code.  Linker will combine them.
1408                  * Listing shows only the address.
1409                  */
1410                 r |= R_WORD | esp->e_rlcf;
1411                 out_lw(esp->e_addr,r|R_RELOC);
1412                 if (oflag) {
1413                         outchk(3, 5);
1414                         out_tw(esp->e_addr);
1415                         *txtp++ = op;
1416
1417                         if (esp->e_flag) {
1418                                 n = esp->e_base.e_sp->s_ref;
1419                                 r |= R_SYM;
1420                         } else {
1421                                 n = esp->e_base.e_ap->a_ref;
1422                         }
1423                         write_rmode(r);
1424                         *relp++ = txtp - txt - 3;
1425                         out_rw(n);
1426                 }
1427         }
1428         dot.s_addr += 2;
1429 }
1430
1431 /*
1432  * Output relocatable 19 bit jump/call
1433  *
1434  * This function is derived from outrw(), adding the parameter for the
1435  * 19 bit address.  This form of address is used only in the DS80C390
1436  * Flat24 mode.
1437  */
1438 VOID
1439 outr19(struct expr * esp, int op, int r)
1440 {
1441         register int n;
1442
1443         if (pass == 2) {
1444                 if (esp->e_flag==0 && esp->e_base.e_ap==NULL) {
1445                         /* equated absolute destination.  Assume value
1446                          * relative to current area */
1447                         esp->e_base.e_ap = dot.s_area;
1448                 }
1449
1450                 /* Relocatable destination.  Build FOUR
1451                  * byte output: relocatable 24-bit entity, followed
1452                  * by op-code.  Linker will combine them.
1453                  * Listing shows only the address.
1454                  */
1455                 r |= R_WORD | esp->e_rlcf;
1456                 out_l24(esp->e_addr,r|R_RELOC);
1457                 if (oflag) {
1458                         outchk(4, 5);
1459                         out_t24(esp->e_addr);
1460                         *txtp++ = op;
1461                         
1462                         if (esp->e_flag) {
1463                                 n = esp->e_base.e_sp->s_ref;
1464                                 r |= R_SYM;
1465                         } else {
1466                                 n = esp->e_base.e_ap->a_ref;
1467                         }
1468                         write_rmode(r);
1469                         *relp++ = txtp - txt - 4;
1470                         out_rw(n);
1471                 }
1472         }
1473         dot.s_addr += 3;
1474 }