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