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