d107854dbfb95c1576fba60cdc916ae836112c9a
[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    outrb(esp, r)
283  *
284  *              expr *  esp             pointer to expr structure
285  *              int     r               relocation mode
286  *
287  *      The function outrb() processes a byte of generated code
288  *      in either absolute or relocatable format dependent upon
289  *      the data contained in the expr structure esp.  If the
290  *      .REL output is enabled then the appropriate information
291  *      is loaded into the txt and rel buffers.
292  *
293  *      local variables:
294  *              int     n               symbol/area reference number
295  *              int *   relp            pointer to rel array
296  *              int *   txtp            pointer to txt array
297  *
298  *      global variables:
299  *              sym     dot             defined as sym[0]
300  *              int     oflag           -o, generate relocatable output flag
301  *              int     pass            assembler pass number
302  *              
303  *      functions called:
304  *              VOID    aerr()          assubr.c
305  *              VOID    outchk()        asout.c
306  *              VOID    out_lb()        asout.c
307  *              VOID    out_rb()        asout.c
308  *              VOID    out_tb()        asout.c
309  *
310  *      side effects:
311  *              The current assembly address is incremented by 1.
312  */
313
314 VOID
315 outrb(esp, r)
316 register struct expr *esp;
317 int r;
318 {
319         register int n;
320
321         if (pass == 2) {
322                 if (esp->e_flag==0 && esp->e_base.e_ap==NULL) {
323                         out_lb(lobyte(esp->e_addr),0);
324                         if (oflag) {
325                                 outchk(1, 0);
326                                 *txtp++ = lobyte(esp->e_addr);
327                         }
328                 } else {
329                         r |= R_BYTE | R_BYT2 | esp->e_rlcf;
330                         if (r & R_MSB) {
331                                 out_lb(hibyte(esp->e_addr),r|R_RELOC|R_HIGH);
332                         } else {
333                                 out_lb(lobyte(esp->e_addr),r|R_RELOC);
334                         }
335                         if (oflag) {
336                                 outchk(2, 4);
337                                 out_tw(esp->e_addr);
338                                 if (esp->e_flag) {
339                                         n = esp->e_base.e_sp->s_ref;
340                                         r |= R_SYM;
341                                 } else {
342                                         n = esp->e_base.e_ap->a_ref;
343                                 }
344                                 *relp++ = r;
345                                 *relp++ = txtp - txt - 2;
346                                 out_rw(n);
347                         }
348                 }
349         }
350         ++dot.s_addr;
351 }
352
353 /*)Function     VOID    outrw(esp, r)
354  *
355  *              expr *  esp             pointer to expr structure
356  *              int     r               relocation mode
357  *
358  *      The function outrw() processes a word of generated code
359  *      in either absolute or relocatable format dependent upon
360  *      the data contained in the expr structure esp.  If the
361  *      .REL output is enabled then the appropriate information
362  *      is loaded into the txt and rel buffers.
363  *
364  *      local variables:
365  *              int     n               symbol/area reference number
366  *              int *   relp            pointer to rel array
367  *              int *   txtp            pointer to txt array
368  *
369  *      global variables:
370  *              sym     dot             defined as sym[0]
371  *              int     oflag           -o, generate relocatable output flag
372  *              int     pass            assembler pass number
373  *              
374  *      functions called:
375  *              VOID    aerr()          assubr.c
376  *              VOID    outchk()        asout.c
377  *              VOID    out_lw()        asout.c
378  *              VOID    out_rw()        asout.c
379  *              VOID    out_tw()        asout.c
380  *
381  *      side effects:
382  *              The current assembly address is incremented by 2.
383  */
384
385 VOID
386 outrw(esp, r)
387 register struct expr *esp;
388 int r;
389 {
390         register int n;
391
392         if (pass == 2) {
393         
394                 if (esp->e_addr > 0xffff)
395                 {
396                     warnBanner();
397                     fprintf(stderr,
398                             "large constant 0x%x truncated to 16 bits\n",
399                             esp->e_addr);
400                 }
401                 if (esp->e_flag==0 && esp->e_base.e_ap==NULL) {
402                         out_lw(esp->e_addr,0);
403                         if (oflag) {
404                                 outchk(2, 0);
405                                 out_tw(esp->e_addr);
406                         }
407                 } else {
408                         r |= R_WORD | esp->e_rlcf;
409                         if (r & R_BYT2) {
410                                 rerr();
411                                 if (r & R_MSB) {
412                                         out_lw(hibyte(esp->e_addr),r|R_RELOC);
413                                 } else {
414                                         out_lw(lobyte(esp->e_addr),r|R_RELOC);
415                                 }
416                         } else {
417                                 out_lw(esp->e_addr,r|R_RELOC);
418                         }
419                         if (oflag) {
420                                 outchk(2, 4);
421                                 out_tw(esp->e_addr);
422                                 if (esp->e_flag) {
423                                         n = esp->e_base.e_sp->s_ref;
424                                         r |= R_SYM;
425                                 } else {
426                                         n = esp->e_base.e_ap->a_ref;
427                                 }
428                                 
429                                 if (IS_C24(r))
430                                 {
431                                     /* If this happens, the linker will
432                                      * attempt to process this 16 bit field
433                                      * as 24 bits. That would be bad.
434                                      */
435                                     fprintf(stderr,
436                                             "***Internal error: C24 out in "
437                                             "outrw()\n");
438                                     rerr();
439                                 }
440                                 *relp++ = r;
441                                 *relp++ = txtp - txt - 2;
442                                 out_rw(n);
443                         }
444                 }
445         }
446         dot.s_addr += 2;
447 }
448
449 /*)Function     VOID    outr24(esp, r)
450  *
451  *              expr *  esp             pointer to expr structure
452  *              int     r               relocation mode
453  *
454  *      The function outr24() processes 24 bits of generated code
455  *      in either absolute or relocatable format dependent upon
456  *      the data contained in the expr structure esp.  If the
457  *      .REL output is enabled then the appropriate information
458  *      is loaded into the txt and rel buffers.
459  *
460  *      local variables:
461  *              int     n               symbol/area reference number
462  *              int *   relp            pointer to rel array
463  *              int *   txtp            pointer to txt array
464  *
465  *      global variables:
466  *              sym     dot             defined as sym[0]
467  *              int     oflag           -o, generate relocatable output flag
468  *              int     pass            assembler pass number
469  *              
470  *      functions called:
471  *              VOID    aerr()          assubr.c
472  *              VOID    outchk()        asout.c
473  *              VOID    out_l24()       asout.c
474  *              VOID    out_rw()        asout.c
475  *              VOID    out_t24()       asout.c
476  *
477  *      side effects:
478  *              The current assembly address is incremented by 3.
479  */
480
481 VOID
482 outr24(struct expr *esp, int r)
483 {
484         register int n;
485
486         if (pass == 2) {
487                 if (esp->e_flag==0 && esp->e_base.e_ap==NULL) {
488                         /* This is a constant expression. */
489                         out_l24(esp->e_addr,0);
490                         if (oflag) {
491                                 outchk(3, 0);
492                                 out_t24(esp->e_addr);
493                         }
494                 } else {
495                         /* This is a symbol. */
496                         r |= R_WORD | esp->e_rlcf;
497                         if (r & R_BYT2) {
498                                 /* I have no idea what this case is. */
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_l24(esp->e_addr,r|R_RELOC);
507                         }
508                         if (oflag) {
509                                 outchk(3, 4);
510                                 out_t24(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 (r & R_BYTE)
519                                 {
520                                     /* If this occurs, we cannot properly
521                                      * code the relocation data with the
522                                      * R_C24 flag. This means the linker
523                                      * will fail to do the 24 bit relocation.
524                                      * Which will suck.
525                                      */
526                                     fprintf(stderr,
527                                             "***Internal error: BYTE out in 24 "
528                                             "bit flat mode unexpected.\n");
529                                     rerr();
530                                 }
531                                 
532                                 *relp++ = r | R_C24;
533                                 *relp++ = txtp - txt - 3;
534                                 out_rw(n);
535                         }
536                 }
537         }
538         dot.s_addr += 3;
539 }
540
541 /*)Function     VOID    outdp(carea, esp)
542  *
543  *              area *  carea           pointer to current area strcuture
544  *              expr *  esp             pointer to expr structure
545  *
546  *      The function outdp() flushes the output buffer and
547  *      outputs paging information to the .REL file.
548  *
549  *      local variables:
550  *              int     n               symbol/area reference number
551  *              int     r               relocation mode
552  *              int *   relp            pointer to rel array
553  *              int *   txtp            pointer to txt array
554  *
555  *      global variables:
556  *              int     oflag           -o, generate relocatable output flag
557  *              int     pass            assembler pass number
558  *              
559  *      functions called:
560  *              VOID    outbuf()        asout.c
561  *              VOID    outchk()        asout.c
562  *              VOID    out_rw()        asout.c
563  *              VOID    out_tw()        asout.c
564  *
565  *      side effects:
566  *              Output buffer flushed to .REL fiel.
567  *              Paging information dumped to .REL file.
568  */
569
570 VOID
571 outdp(carea, esp)
572 register struct area *carea;
573 register struct expr *esp;
574 {
575         register int n, r;
576
577         if (oflag && pass==2) {
578                 outchk(HUGE,HUGE);
579                 out_tw(carea->a_ref);
580                 out_tw(esp->e_addr);
581                 if (esp->e_flag || esp->e_base.e_ap!=NULL) {
582                         r = R_WORD;
583                         if (esp->e_flag) {
584                                 n = esp->e_base.e_sp->s_ref;
585                                 r |= R_SYM;
586                         } else {
587                                 n = esp->e_base.e_ap->a_ref;
588                         }
589                         *relp++ = r;
590                         *relp++ = txtp - txt - 2;
591                         out_rw(n);
592                 }
593                 outbuf("P");
594         }
595 }
596
597 /*)Function     VOID    outall()
598  *
599  *      The function outall() will output any bufferred assembled
600  *      data and relocation information (during pass 2 if the .REL
601  *      output has been enabled).
602  *
603  *      local variables:
604  *              none
605  *
606  *      global variables:
607  *              int     oflag           -o, generate relocatable output flag
608  *              int     pass            assembler pass number
609  *
610  *      functions called:
611  *              VOID    outbuf()        asout.c
612  *
613  *      side effects:
614  *              assembled data and relocation buffers will be cleared.
615  */
616
617 VOID
618 outall()
619 {
620         if (oflag && pass==2)
621                 outbuf("R");
622 }
623
624 /*)Function     VOID    outdot()
625  *
626  *      The function outdot() outputs information about the
627  *      current program counter value (during pass 2 if the .REL
628  *      output has been enabled).
629  *
630  *      local variables:
631  *              none
632  *
633  *      global variables:
634  *              int     oflag           -o, generate relocatable output flag
635  *              int     pass            assembler pass number
636  *
637  *      functions called:
638  *              int     fprintf()       c_library
639  *              VOID    out()           asout.c
640  *
641  *      side effects:
642  *              assembled data and relocation buffers will be cleared.
643  */
644
645 VOID
646 outdot()
647 {
648         if (oflag && pass==2) {
649                 fprintf(ofp, "T");
650                 out(txt,(int) (txtp-txt));
651                 fprintf(ofp, "\n");
652                 fprintf(ofp, "R");
653                 out(rel,(int) (relp-rel));
654                 fprintf(ofp, "\n");
655                 txtp = txt;
656                 relp = rel;
657         }
658 }
659
660 /*)Function     outchk(nt, nr)
661  *
662  *              int     nr              number of additional relocation words
663  *              int     nt              number of additional data words
664  *
665  *      The function outchk() checks the data and relocation buffers
666  *      for space to insert the nt data words and nr relocation words.
667  *      If space is not available then output the current data and
668  *      initialize the data buffers to receive the new data.
669  *
670  *      local variables:
671  *              area *  ap              pointer to an area structure
672  *              int *   relp            pointer to rel array
673  *              int *   txtp            pointer to txt array
674  *
675  *      global variables:
676  *              sym     dot             defined as sym[0]
677  *
678  *      functions called:
679  *              VOID    outbuf()        asout.c
680  *
681  *      side effects:
682  *              Data and relocation buffers may be emptied and initialized.
683  */
684
685 VOID
686 outchk(nt, nr)
687 {
688         register struct area *ap;
689
690         if (txtp+nt > &txt[NTXT] || relp+nr > &rel[NREL]) {
691                 outbuf("R");
692         }
693         if (txtp == txt) {
694                 out_tw(dot.s_addr);
695                 if ((ap = dot.s_area) != NULL) {
696                         *relp++ = R_WORD|R_AREA;
697                         *relp++ = 0;
698                         out_rw(ap->a_ref);
699                 }
700         }
701 }
702
703 /*)Function     VOID    outbuf()
704  *
705  *      The function outbuf() will output any bufferred data
706  *      and relocation information to the .REL file.  The output
707  *      buffer pointers and counters are initialized.
708  *
709  *      local variables:
710  *              int     rel[]           relocation data for code/data array
711  *              int *   relp            pointer to rel array
712  *              int     txt[]           assembled code/data array
713  *              int *   txtp            pointer to txt array
714  *
715  *      global variables:
716  *              FILE *  ofp             relocation output file handle
717  *
718  *      functions called:
719  *              VOID    out()           asout.c
720  *
721  *      side effects:
722  *              All bufferred data written to .REL file and
723  *              buffer pointers and counters initialized.
724  */
725
726 VOID
727 outbuf(s)
728 char *s;
729 {
730         if (txtp > &txt[2]) {
731                 fprintf(ofp, "T");
732                 out(txt,(int) (txtp-txt));
733                 fprintf(ofp, "\n");
734                 fprintf(ofp, "%s", s);
735                 out(rel,(int) (relp-rel));
736                 fprintf(ofp, "\n");
737         }
738         txtp = txt;
739         relp = rel;
740 }
741
742 /*)Function     VOID    outgsd()
743  *
744  *      The function outgsd() performs the following:
745  *      (1)     outputs the .REL file radix
746  *      (2)     outputs the header specifying the number
747  *              of areas and global symbols
748  *      (3)     outputs the module name
749  *      (4)     set the reference number and output a symbol line
750  *              for all external global variables and absolutes
751  *      (5)     output an area name, set reference number and output
752  *              a symbol line for all global relocatables in the area.
753  *              Repeat this proceedure for all areas.
754  *
755  *      local variables:
756  *              area *  ap              pointer to an area structure
757  *              sym *   sp              pointer to a sym structure
758  *              int     i               loop counter
759  *              int     j               loop counter
760  *              int     c               string character value
761  *              int     narea           number of code areas
762  *              char *  ptr             string pointer
763  *              int     nglob           number of global symbols
764  *              int     rn              symbol reference number
765  *
766  *      global variables:
767  *              area *  areap           pointer to an area structure
768  *              char    module[]        module name string
769  *              sym * symhash[]         array of pointers to NHASH
770  *                                      linked symbol lists
771  *              int     xflag           -x, listing radix flag
772  *
773  *      functions called:
774  *              int     fprintf()       c_library
775  *              VOID    outarea()       asout.c
776  *              VOID    outsym()        asout.c
777  *              int     putc()          c_library
778  *
779  *      side effects:
780  *              All symbols are given reference numbers, all symbol
781  *              and area information is output to the .REL file.
782  */
783
784 VOID
785 outgsd()
786 {
787         register struct area *ap;
788         register struct sym  *sp;
789         register int i, j;
790         char *ptr;
791         int c, narea, nglob, rn;
792
793         /*
794          * Number of areas
795          */
796         narea = areap->a_ref + 1;
797
798         /*
799          * Number of global references/absolutes
800          */
801         nglob = 0;
802         for (i = 0; i < NHASH; ++i) {
803                 sp = symhash[i];
804                 while (sp) {
805                         if (sp->s_flag&S_GBL)
806                                 ++nglob;
807                         sp = sp->s_sp;
808                 }
809         }
810
811         /*
812          * Output Radix and number of areas and symbols
813          */
814         if (xflag == 0) {
815                 fprintf(ofp, "X%c\n", hilo ? 'H' : 'L');
816                 fprintf(ofp, "H %X areas %X global symbols\n", narea, nglob);
817         } else
818         if (xflag == 1) {
819                 fprintf(ofp, "Q%c\n", hilo ? 'H' : 'L');
820                 fprintf(ofp, "H %o areas %o global symbols\n", narea, nglob);
821         } else
822         if (xflag == 2) {
823                 fprintf(ofp, "D%c\n", hilo ? 'H' : 'L');
824                 fprintf(ofp, "H %u areas %u global symbols\n", narea, nglob);
825         }               
826
827         /*
828          * Module name
829          */
830         if (module[0]) {
831                 fprintf(ofp, "M ");
832                 ptr = &module[0];
833                 while (ptr < &module[NCPS]) {
834                         if ((c = *ptr++) != 0)
835                                 putc(c, ofp);
836                 }
837                 putc('\n', ofp);
838         }
839
840         /*
841          * Global references and absolutes.
842          */
843         rn = 0;
844         for (i=0; i<NHASH; ++i) {
845                 sp = symhash[i];
846                 while (sp) {
847                         if (sp->s_area==NULL && sp->s_flag&S_GBL) {
848                                 sp->s_ref = rn++;
849                                 outsym(sp);
850                         }
851                         sp = sp->s_sp;
852                 }
853         }
854
855         /*
856          * Global relocatables.
857          */
858         for (i=0; i<narea; ++i) {
859                 ap = areap;
860                 while (ap->a_ref != i)
861                         ap = ap->a_ap;
862                 outarea(ap);
863                 for (j=0; j<NHASH; ++j) {
864                         sp = symhash[j];
865                         while (sp) {
866                                 if (sp->s_area==ap && sp->s_flag&S_GBL) {
867                                         sp->s_ref = rn++;
868                                         outsym(sp);
869                                 }
870                                 sp = sp->s_sp;
871                         }
872                 }
873         }
874 }
875
876 /*)Function     VOID    outarea(ap)
877  *
878  *              area *  ap              pointer to an area structure
879  *
880  *      The function outarea()  outputs the A line to the .REL
881  *      file.  The A line contains the area's name, size, and
882  *      attributes.
883  *
884  *      local variables:
885  *              char *  ptr             pointer to area id string
886  *              int     c               character value
887  *
888  *      global variables:
889  *              FILE *  ofp             relocation output file handle
890  *              int     xflag           -x, listing radix flag
891  *
892  *      functions called:
893  *              int     fprintf()       c_library
894  *              int     putc()          c_library
895  *
896  *      side effects:
897  *              The A line is sent to the .REL file.
898  */
899
900 VOID
901 outarea(ap)
902 register struct area *ap;
903 {
904         register char *ptr;
905         register int c;
906
907         fprintf(ofp, "A ");
908         ptr = &ap->a_id[0];
909         while (ptr < &ap->a_id[NCPS]) {
910                 if ((c = *ptr++) != 0)
911                         putc(c, ofp);
912         }
913         if (xflag == 0) {
914                 fprintf(ofp, " size %X flags %X\n", ap->a_size, ap->a_flag);
915         } else
916         if (xflag == 1) {
917                 fprintf(ofp, " size %o flags %o\n", ap->a_size, ap->a_flag);
918         } else
919         if (xflag == 2) {
920                 fprintf(ofp, " size %u flags %u\n", ap->a_size, ap->a_flag);
921         }
922 }
923
924 /*)Function     VOID    outsym(sp)
925  *
926  *              sym *   sp              pointer to a sym structure
927  *
928  *      The function outsym() outputs the S line to the .REL
929  *      file.  The S line contains the symbols name and whether the
930  *      the symbol is defined or referenced.
931  *
932  *      local variables:
933  *              char *  ptr             pointer to symbol id string
934  *              int     c               character value
935  *
936  *      global variables:
937  *              FILE *  ofp             relocation output file handle
938  *              int     xflag           -x, listing radix flag
939  *
940  *      functions called:
941  *              int     fprintf()       c_library
942  *              int     putc()          c_library
943  *
944  *      side effects:
945  *              The S line is sent to the .REL file.
946  */
947
948 VOID
949 outsym(sp)
950 register struct sym *sp;
951 {
952         register char *ptr;       
953
954         fprintf(ofp, "S ");
955         ptr = &sp->s_id[0];
956         fprintf(ofp, "%s", ptr );
957         fprintf(ofp, " %s", sp->s_type==S_NEW ? "Ref" : "Def");
958         if (xflag == 0) {
959                 fprintf(ofp, "%04X\n", sp->s_addr);
960         } else
961         if (xflag == 1) {
962                 fprintf(ofp, "%06o\n", sp->s_addr);
963         } else
964         if (xflag == 2) {
965                 fprintf(ofp, "%05u\n", sp->s_addr);
966         }
967 }
968
969 /*)Function     VOID    out(p, n)
970  *
971  *              int     n               number of words to output
972  *              int *   p               pointer to data words
973  *
974  *      The function out() outputs the data words to the .REL file
975  *      int the specified radix.
976  *
977  *      local variables:
978  *              none
979  *
980  *      global variables:
981  *              FILE *  ofp             relocation output file handle
982  *              int     xflag           -x, listing radix flag
983  *
984  *      functions called:
985  *              int     fprintf()       c_library
986  *
987  *      side effects:
988  *              Data is sent to the .REL file.
989  */
990
991 VOID
992 out(p, n)
993 register char *p;
994 register int n;
995 {
996         while (n--) {
997                 if (xflag == 0) {
998                         fprintf(ofp, " %02X", (*p++)&0377);
999                 } else
1000                 if (xflag == 1) {
1001                         fprintf(ofp, " %03o", (*p++)&0377);
1002                 } else
1003                 if (xflag == 2) {
1004                         fprintf(ofp, " %03u", (*p++)&0377);
1005                 }
1006         }
1007 }
1008
1009 /*)Function     VOID    out_lb(b, t)
1010  *
1011  *              int     b               assembled data
1012  *              int     t               relocation type
1013  *
1014  *      The function out_lb() copies the assembled data and
1015  *      its relocation type to the list data buffers.
1016  *
1017  *      local variables:
1018  *              none
1019  *
1020  *      global variables:
1021  *              int *   cp              pointer to assembler output array cb[]
1022  *              int *   cpt             pointer to assembler relocation type
1023  *                                      output array cbt[]
1024  *
1025  *      functions called:
1026  *              none
1027  *
1028  *      side effects:
1029  *              Pointers to data and relocation buffers incremented by 1.
1030  */
1031
1032 VOID
1033 out_lb(b,t)
1034 register int b,t;
1035 {
1036         if (cp < &cb[NCODE]) {
1037                 *cp++ = b;
1038                 *cpt++ = t;
1039         }
1040 }
1041
1042 /*)Function     VOID    out_lw(n, t)
1043  *
1044  *              int     n               assembled data
1045  *              int     t               relocation type
1046  *
1047  *      The function out_lw() copies the assembled data and
1048  *      its relocation type to the list data buffers.
1049  *
1050  *      local variables:
1051  *              none
1052  *
1053  *      global variables:
1054  *              int *   cp              pointer to assembler output array cb[]
1055  *              int *   cpt             pointer to assembler relocation type
1056  *                                      output array cbt[]
1057  *
1058  *      functions called:
1059  *              none
1060  *
1061  *      side effects:
1062  *              Pointers to data and relocation buffers incremented by 2.
1063  */
1064
1065 VOID
1066 out_lw(n,t)
1067 register int n,t;
1068 {
1069         if (hilo) {
1070                 out_lb(hibyte(n),t ? t|R_HIGH : 0);
1071                 out_lb(lobyte(n),t);
1072         } else {
1073                 out_lb(lobyte(n),t);
1074                 out_lb(hibyte(n),t ? t|R_HIGH : 0);
1075         }
1076 }
1077
1078 /*)Function     VOID    out_l24(n, t)
1079  *
1080  *              int     n               assembled data
1081  *              int     t               relocation type
1082  *
1083  *      The function out_l24() copies the assembled data and
1084  *      its relocation type to the list data buffers.
1085  *
1086  *      local variables:
1087  *              none
1088  *
1089  *      global variables:
1090  *              int *   cp              pointer to assembler output array cb[]
1091  *              int *   cpt             pointer to assembler relocation type
1092  *                                      output array cbt[]
1093  *
1094  *      functions called:
1095  *              none
1096  *
1097  *      side effects:
1098  *              Pointers to data and relocation buffers incremented by 3.
1099  */
1100
1101 VOID
1102 out_l24(int n, int t)
1103 {
1104         if (hilo) {
1105                 out_lb(byte3(n),t ? t|R_HIGH : 0);
1106                 out_lb(hibyte(n),t);
1107                 out_lb(lobyte(n),t);
1108         } else {
1109                 out_lb(lobyte(n),t);
1110                 out_lb(hibyte(n),t);
1111                 out_lb(byte3(n),t ? t|R_HIGH : 0);
1112         }
1113 }
1114
1115 /*)Function     VOID    out_rw(n)
1116  *
1117  *              int     n               data word
1118  *
1119  *      The function out_rw() outputs the relocation (R)
1120  *      data word as two bytes ordered according to hilo.
1121  *
1122  *      local variables:
1123  *              int *   relp            pointer to rel array
1124  *
1125  *      global variables:
1126  *              none
1127  *
1128  *      functions called:
1129  *              int     lobyte()        asout.c
1130  *              int     hibyte()        asout.c
1131  *
1132  *      side effects:
1133  *              Pointer to relocation buffer incremented by 2.
1134  */
1135
1136 VOID
1137 out_rw(n)
1138 register int n;
1139 {
1140         if (hilo) {
1141                 *relp++ = hibyte(n);
1142                 *relp++ = lobyte(n);
1143         } else {
1144                 *relp++ = lobyte(n);
1145                 *relp++ = hibyte(n);
1146         }
1147 }
1148
1149 /*)Function     VOID    out_tw(n)
1150  *
1151  *              int     n               data word
1152  *
1153  *      The function out_tw() outputs the text (T)
1154  *      data word as two bytes ordered according to hilo.
1155  *
1156  *      local variables:
1157  *              int *   txtp            pointer to txt array
1158  *
1159  *      global variables:
1160  *              none
1161  *
1162  *      functions called:
1163  *              int     lobyte()        asout.c
1164  *              int     hibyte()        asout.c
1165  *
1166  *      side effects:
1167  *              Pointer to relocation buffer incremented by 2.
1168  */
1169
1170 VOID
1171 out_tw(n)
1172 register int n;
1173 {
1174         if (hilo) {
1175                 *txtp++ = hibyte(n);
1176                 *txtp++ = lobyte(n);
1177         } else {
1178                 *txtp++ = lobyte(n);
1179                 *txtp++ = hibyte(n);
1180         }
1181 }
1182
1183 /*)Function     VOID    out_t24(n)
1184  *
1185  *              int     n               data word
1186  *
1187  *      The function out_t24() outputs the text (T)
1188  *      data word as three bytes ordered according to hilo.
1189  *
1190  *      local variables:
1191  *              int *   txtp            pointer to txt array
1192  *
1193  *      global variables:
1194  *              none
1195  *
1196  *      functions called:
1197  *              int     lobyte()        asout.c
1198  *              int     hibyte()        asout.c
1199  *
1200  *      side effects:
1201  *              Pointer to relocation buffer incremented by 3.
1202  */
1203
1204 VOID
1205 out_t24(int n)
1206 {
1207         if (hilo) {
1208                 *txtp++ = byte3(n);
1209                 *txtp++ = hibyte(n);
1210                 *txtp++ = lobyte(n);
1211         } else {
1212                 *txtp++ = lobyte(n);
1213                 *txtp++ = hibyte(n);
1214                 *txtp++ = byte3(n);
1215         }
1216 }
1217
1218 /*)Function     int     lobyte(n)
1219  *
1220  *              int     n               data word
1221  *
1222  *      The function lobyte() returns the lower byte of
1223  *      integer n.
1224  *
1225  *      local variables:
1226  *              none
1227  *
1228  *      global variables:
1229  *              none
1230  *
1231  *      functions called:
1232  *              none
1233  *
1234  *      side effects:
1235  *              none
1236  */
1237
1238 int
1239 lobyte(n)
1240 {
1241         return (n&0377);
1242 }
1243
1244 /*)Function     int     hibyte(n)
1245  *
1246  *              int     n               data word
1247  *
1248  *      The function hibyte() returns the higher byte of
1249  *      integer n.
1250  *
1251  *      local variables:
1252  *              none
1253  *
1254  *      global variables:
1255  *              none
1256  *
1257  *      functions called:
1258  *              none
1259  *
1260  *      side effects:
1261  *              none
1262  */
1263
1264 int
1265 hibyte(n)
1266 {
1267         return ((n>>8)&0377);
1268 }
1269
1270 /*)Function     int     byte3(n)
1271  *
1272  *              int     n               24 bit data
1273  *
1274  *      The function byte3() returns the MSB of the
1275  *      24 bit integer n.
1276  *
1277  *      local variables:
1278  *              none
1279  *
1280  *      global variables:
1281  *              none
1282  *
1283  *      functions called:
1284  *              none
1285  *
1286  *      side effects:
1287  *              none
1288  */
1289 int
1290 byte3(int n)
1291 {
1292         return ((n >> 16) & 0xff);
1293 }
1294
1295 /*
1296  * JLH: Output relocatable 11 bit jump/call
1297  *
1298  * This function is derived from outrw(), adding the parameter for the
1299  * 11 bit address.  This form of address is used only on the 8051 and 8048.
1300  */
1301 VOID
1302 outr11(esp, op, r)
1303 register struct expr *esp;
1304 int op;
1305 int r;
1306 {
1307         register int n;
1308
1309         if (pass == 2) {
1310                 if (esp->e_flag==0 && esp->e_base.e_ap==NULL) {
1311                         /* equated absolute destination.  Assume value
1312                          * relative to current area */
1313                         esp->e_base.e_ap = dot.s_area;
1314                 }
1315
1316                 /* Relocatable destination.  Build THREE
1317                  * byte output: relocatable word, followed
1318                  * by op-code.  Linker will combine them.
1319                  * Listing shows only the address.
1320                  */
1321                 r |= R_WORD | esp->e_rlcf;
1322                 out_lw(esp->e_addr,r|R_RELOC);
1323                 if (oflag) {
1324                         outchk(3, 4);
1325                         out_tw(esp->e_addr);
1326                         *txtp++ = op;
1327
1328                         if (esp->e_flag) {
1329                                 n = esp->e_base.e_sp->s_ref;
1330                                 r |= R_SYM;
1331                         } else {
1332                                 n = esp->e_base.e_ap->a_ref;
1333                         }
1334                         *relp++ = r;
1335                         *relp++ = txtp - txt - 3;
1336                         out_rw(n);
1337                 }
1338         }
1339         dot.s_addr += 2;
1340 }
1341
1342 /*
1343  * Output relocatable 19 bit jump/call
1344  *
1345  * This function is derived from outrw(), adding the parameter for the
1346  * 19 bit address.  This form of address is used only in the DS80C390
1347  * Flat24 mode.
1348  */
1349 VOID
1350 outr19(struct expr * esp, int op, int r)
1351 {
1352         register int n;
1353
1354         if (pass == 2) {
1355                 if (esp->e_flag==0 && esp->e_base.e_ap==NULL) {
1356                         /* equated absolute destination.  Assume value
1357                          * relative to current area */
1358                         esp->e_base.e_ap = dot.s_area;
1359                 }
1360
1361                 /* Relocatable destination.  Build FOUR
1362                  * byte output: relocatable 24-bit entity, followed
1363                  * by op-code.  Linker will combine them.
1364                  * Listing shows only the address.
1365                  */
1366                 r |= R_WORD | esp->e_rlcf;
1367                 out_l24(esp->e_addr,r|R_RELOC);
1368                 if (oflag) {
1369                         outchk(4, 4);
1370                         out_t24(esp->e_addr);
1371                         *txtp++ = op;
1372                         
1373                         if (esp->e_flag) {
1374                                 n = esp->e_base.e_sp->s_ref;
1375                                 r |= R_SYM;
1376                         } else {
1377                                 n = esp->e_base.e_ap->a_ref;
1378                         }
1379                         *relp++ = r;
1380                         *relp++ = txtp - txt - 4;
1381                         out_rw(n);
1382                 }
1383         }
1384         dot.s_addr += 3;
1385 }