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