* device/lib/libfloat.lib, device/lib/libint.lib,
[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(int 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(int 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(register struct area *carea, register struct expr *esp)
633 {
634         register int n, r;
635
636         if (oflag && pass==2) {
637                 outchk(HUGE,HUGE);
638                 out_tw(carea->a_ref);
639                 out_tw(esp->e_addr);
640                 if (esp->e_flag || esp->e_base.e_ap!=NULL) {
641                         r = R_WORD;
642                         if (esp->e_flag) {
643                                 n = esp->e_base.e_sp->s_ref;
644                                 r |= R_SYM;
645                         } else {
646                                 n = esp->e_base.e_ap->a_ref;
647                         }
648                         write_rmode(r);
649                         *relp++ = txtp - txt - 2;
650                         out_rw(n);
651                 }
652                 outbuf("P");
653         }
654 }
655
656 /*)Function     VOID    outall()
657  *
658  *      The function outall() will output any bufferred assembled
659  *      data and relocation information (during pass 2 if the .REL
660  *      output has been enabled).
661  *
662  *      local variables:
663  *              none
664  *
665  *      global variables:
666  *              int     oflag           -o, generate relocatable output flag
667  *              int     pass            assembler pass number
668  *
669  *      functions called:
670  *              VOID    outbuf()        asout.c
671  *
672  *      side effects:
673  *              assembled data and relocation buffers will be cleared.
674  */
675
676 VOID
677 outall(void)
678 {
679         if (oflag && pass==2)
680                 outbuf("R");
681 }
682
683 /*)Function     VOID    outdot()
684  *
685  *      The function outdot() outputs information about the
686  *      current program counter value (during pass 2 if the .REL
687  *      output has been enabled).
688  *
689  *      local variables:
690  *              none
691  *
692  *      global variables:
693  *              int     oflag           -o, generate relocatable output flag
694  *              int     pass            assembler pass number
695  *
696  *      functions called:
697  *              int     fprintf()       c_library
698  *              VOID    out()           asout.c
699  *
700  *      side effects:
701  *              assembled data and relocation buffers will be cleared.
702  */
703
704 VOID
705 outdot(void)
706 {
707         if (oflag && pass==2) {
708                 fprintf(ofp, "T");
709                 out(txt,(int) (txtp-txt));
710                 fprintf(ofp, "\n");
711                 fprintf(ofp, "R");
712                 out(rel,(int) (relp-rel));
713                 fprintf(ofp, "\n");
714                 txtp = txt;
715                 relp = rel;
716         }
717 }
718
719 /*)Function     outchk(nt, nr)
720  *
721  *              int     nr              number of additional relocation words
722  *              int     nt              number of additional data words
723  *
724  *      The function outchk() checks the data and relocation buffers
725  *      for space to insert the nt data words and nr relocation words.
726  *      If space is not available then output the current data and
727  *      initialize the data buffers to receive the new data.
728  *
729  *      local variables:
730  *              area *  ap              pointer to an area structure
731  *              int *   relp            pointer to rel array
732  *              int *   txtp            pointer to txt array
733  *
734  *      global variables:
735  *              sym     dot             defined as sym[0]
736  *
737  *      functions called:
738  *              VOID    outbuf()        asout.c
739  *
740  *      side effects:
741  *              Data and relocation buffers may be emptied and initialized.
742  */
743
744 VOID
745 outchk(int nt, int nr)
746 {
747         register struct area *ap;
748
749         if (txtp+nt > &txt[NTXT] || relp+nr > &rel[NREL]) {
750                 outbuf("R");
751         }
752         if (txtp == txt) {
753                 out_tw(dot.s_addr);
754                 if ((ap = dot.s_area) != NULL) {
755                         write_rmode(R_WORD|R_AREA);
756                         *relp++ = 0;
757                         out_rw(ap->a_ref);
758                 }
759         }
760 }
761
762 /*)Function     VOID    outbuf()
763  *
764  *      The function outbuf() will output any bufferred data
765  *      and relocation information to the .REL file.  The output
766  *      buffer pointers and counters are initialized.
767  *
768  *      local variables:
769  *              int     rel[]           relocation data for code/data array
770  *              int *   relp            pointer to rel array
771  *              int     txt[]           assembled code/data array
772  *              int *   txtp            pointer to txt array
773  *
774  *      global variables:
775  *              FILE *  ofp             relocation output file handle
776  *
777  *      functions called:
778  *              VOID    out()           asout.c
779  *
780  *      side effects:
781  *              All bufferred data written to .REL file and
782  *              buffer pointers and counters initialized.
783  */
784
785 VOID
786 outbuf(char *s)
787 {
788         if (txtp > &txt[2]) {
789                 fprintf(ofp, "T");
790                 out(txt,(int) (txtp-txt));
791                 fprintf(ofp, "\n");
792                 fprintf(ofp, "%s", s);
793                 out(rel,(int) (relp-rel));
794                 fprintf(ofp, "\n");
795         }
796         txtp = txt;
797         relp = rel;
798 }
799
800 /*)Function     VOID    outgsd()
801  *
802  *      The function outgsd() performs the following:
803  *      (1)     outputs the .REL file radix
804  *      (2)     outputs the header specifying the number
805  *              of areas and global symbols
806  *      (3)     outputs the module name
807  *      (4)     set the reference number and output a symbol line
808  *              for all external global variables and absolutes
809  *      (5)     output an area name, set reference number and output
810  *              a symbol line for all global relocatables in the area.
811  *              Repeat this proceedure for all areas.
812  *
813  *      local variables:
814  *              area *  ap              pointer to an area structure
815  *              sym *   sp              pointer to a sym structure
816  *              int     i               loop counter
817  *              int     j               loop counter
818  *              int     c               string character value
819  *              int     narea           number of code areas
820  *              char *  ptr             string pointer
821  *              int     nglob           number of global symbols
822  *              int     rn              symbol reference number
823  *
824  *      global variables:
825  *              area *  areap           pointer to an area structure
826  *              char    module[]        module name string
827  *              sym * symhash[]         array of pointers to NHASH
828  *                                      linked symbol lists
829  *              int     xflag           -x, listing radix flag
830  *
831  *      functions called:
832  *              int     fprintf()       c_library
833  *              VOID    outarea()       asout.c
834  *              VOID    outsym()        asout.c
835  *              int     putc()          c_library
836  *
837  *      side effects:
838  *              All symbols are given reference numbers, all symbol
839  *              and area information is output to the .REL file.
840  */
841
842 VOID
843 outgsd(void)
844 {
845         register struct area *ap;
846         register struct sym  *sp;
847         register int i, j;
848         char *ptr;
849         int c, narea, nglob, rn;
850
851         /*
852          * Number of areas
853          */
854         narea = areap->a_ref + 1;
855
856         /*
857          * Number of global references/absolutes
858          */
859         nglob = 0;
860         for (i = 0; i < NHASH; ++i) {
861                 sp = symhash[i];
862                 while (sp) {
863                         if (sp->s_flag&S_GBL)
864                                 ++nglob;
865                         sp = sp->s_sp;
866                 }
867         }
868
869         /*
870          * Output Radix and number of areas and symbols
871          */
872         if (xflag == 0) {
873                 fprintf(ofp, "X%c\n", hilo ? 'H' : 'L');
874                 fprintf(ofp, "H %X areas %X global symbols\n", narea, nglob);
875         } else
876         if (xflag == 1) {
877                 fprintf(ofp, "Q%c\n", hilo ? 'H' : 'L');
878                 fprintf(ofp, "H %o areas %o global symbols\n", narea, nglob);
879         } else
880         if (xflag == 2) {
881                 fprintf(ofp, "D%c\n", hilo ? 'H' : 'L');
882                 fprintf(ofp, "H %u areas %u global symbols\n", narea, nglob);
883         }
884
885         /*
886          * Module name
887          */
888         if (module[0]) {
889                 fprintf(ofp, "M ");
890                 ptr = &module[0];
891                 while (ptr < &module[NCPS]) {
892                         if ((c = *ptr++) != 0)
893                                 putc(c, ofp);
894                 }
895                 putc('\n', ofp);
896         }
897
898     /*
899      * Sdcc compile options
900      */
901         if (strlen(optsdcc)) fprintf(ofp, "O %s\n", optsdcc);
902
903         /*
904          * Global references and absolutes.
905          */
906         rn = 0;
907         for (i=0; i<NHASH; ++i) {
908                 sp = symhash[i];
909                 while (sp) {
910                         if (sp->s_area==NULL && sp->s_flag&S_GBL) {
911                                 sp->s_ref = rn++;
912                                 outsym(sp);
913                         }
914                         sp = sp->s_sp;
915                 }
916         }
917
918         /*
919          * Global relocatables.
920          */
921         for (i=0; i<narea; ++i) {
922                 ap = areap;
923                 while (ap->a_ref != i)
924                         ap = ap->a_ap;
925                 outarea(ap);
926                 for (j=0; j<NHASH; ++j) {
927                         sp = symhash[j];
928                         while (sp) {
929                                 if (sp->s_area==ap && sp->s_flag&S_GBL) {
930                                         sp->s_ref = rn++;
931                                         outsym(sp);
932                                 }
933                                 sp = sp->s_sp;
934                         }
935                 }
936         }
937 }
938
939 /*)Function     VOID    outarea(ap)
940  *
941  *              area *  ap              pointer to an area structure
942  *
943  *      The function outarea()  outputs the A line to the .REL
944  *      file.  The A line contains the area's name, size, and
945  *      attributes.
946  *
947  *      local variables:
948  *              char *  ptr             pointer to area id string
949  *              int     c               character value
950  *
951  *      global variables:
952  *              FILE *  ofp             relocation output file handle
953  *              int     xflag           -x, listing radix flag
954  *
955  *      functions called:
956  *              int     fprintf()       c_library
957  *              int     putc()          c_library
958  *
959  *      side effects:
960  *              The A line is sent to the .REL file.
961  */
962
963 VOID
964 outarea(register struct area *ap)
965 {
966         register char *ptr;
967         register int c;
968
969         fprintf(ofp, "A ");
970         ptr = &ap->a_id[0];
971         while (ptr < &ap->a_id[NCPS]) {
972                 if ((c = *ptr++) != 0)
973                         putc(c, ofp);
974         }
975         if (xflag == 0) {
976                 fprintf(ofp, " size %X flags %X addr %X\n", ap->a_size, ap->a_flag, ap->a_addr);
977         } else
978         if (xflag == 1) {
979                 fprintf(ofp, " size %o flags %o\n", ap->a_size, ap->a_flag);
980         } else
981         if (xflag == 2) {
982                 fprintf(ofp, " size %u flags %u\n", ap->a_size, ap->a_flag);
983         }
984 }
985
986 /*)Function     VOID    outsym(sp)
987  *
988  *              sym *   sp              pointer to a sym structure
989  *
990  *      The function outsym() outputs the S line to the .REL
991  *      file.  The S line contains the symbols name and whether the
992  *      the symbol is defined or referenced.
993  *
994  *      local variables:
995  *              char *  ptr             pointer to symbol id string
996  *              int     c               character value
997  *
998  *      global variables:
999  *              FILE *  ofp             relocation output file handle
1000  *              int     xflag           -x, listing radix flag
1001  *
1002  *      functions called:
1003  *              int     fprintf()       c_library
1004  *              int     putc()          c_library
1005  *
1006  *      side effects:
1007  *              The S line is sent to the .REL file.
1008  */
1009
1010 VOID
1011 outsym(register struct sym *sp)
1012 {
1013         register char *ptr;
1014
1015         fprintf(ofp, "S ");
1016         ptr = &sp->s_id[0];
1017         fprintf(ofp, "%s", ptr );
1018         fprintf(ofp, " %s", sp->s_type==S_NEW ? "Ref" : "Def");
1019         if (xflag == 0) {
1020                 fprintf(ofp, "%04X\n", sp->s_addr);
1021         } else
1022         if (xflag == 1) {
1023                 fprintf(ofp, "%06o\n", sp->s_addr);
1024         } else
1025         if (xflag == 2) {
1026                 fprintf(ofp, "%05u\n", sp->s_addr);
1027         }
1028 }
1029
1030 /*)Function     VOID    out(p, n)
1031  *
1032  *              int     n               number of words to output
1033  *              int *   p               pointer to data words
1034  *
1035  *      The function out() outputs the data words to the .REL file
1036  *      int the specified radix.
1037  *
1038  *      local variables:
1039  *              none
1040  *
1041  *      global variables:
1042  *              FILE *  ofp             relocation output file handle
1043  *              int     xflag           -x, listing radix flag
1044  *
1045  *      functions called:
1046  *              int     fprintf()       c_library
1047  *
1048  *      side effects:
1049  *              Data is sent to the .REL file.
1050  */
1051
1052 VOID
1053 out(char *p, int n)
1054 {
1055         while (n--) {
1056                 if (xflag == 0) {
1057                         fprintf(ofp, " %02X", (*p++)&0xff);
1058                 } else
1059                 if (xflag == 1) {
1060                         fprintf(ofp, " %03o", (*p++)&0xff);
1061                 } else
1062                 if (xflag == 2) {
1063                         fprintf(ofp, " %03u", (*p++)&0xff);
1064                 }
1065         }
1066 }
1067
1068 /*)Function     VOID    out_lb(b, t)
1069  *
1070  *              int     b               assembled data
1071  *              int     t               relocation type
1072  *
1073  *      The function out_lb() copies the assembled data and
1074  *      its relocation type to the list data buffers.
1075  *
1076  *      local variables:
1077  *              none
1078  *
1079  *      global variables:
1080  *              int *   cp              pointer to assembler output array cb[]
1081  *              int *   cpt             pointer to assembler relocation type
1082  *                                      output array cbt[]
1083  *
1084  *      functions called:
1085  *              none
1086  *
1087  *      side effects:
1088  *              Pointers to data and relocation buffers incremented by 1.
1089  */
1090
1091 VOID
1092 out_lb(register int b, register int t)
1093 {
1094         if (cp < &cb[NCODE]) {
1095                 *cp++ = b;
1096                 *cpt++ = t;
1097         }
1098 }
1099
1100 /*)Function     VOID    out_lw(n, t)
1101  *
1102  *              int     n               assembled data
1103  *              int     t               relocation type
1104  *
1105  *      The function out_lw() copies the assembled data and
1106  *      its relocation type to the list data buffers.
1107  *
1108  *      local variables:
1109  *              none
1110  *
1111  *      global variables:
1112  *              int *   cp              pointer to assembler output array cb[]
1113  *              int *   cpt             pointer to assembler relocation type
1114  *                                      output array cbt[]
1115  *
1116  *      functions called:
1117  *              none
1118  *
1119  *      side effects:
1120  *              Pointers to data and relocation buffers incremented by 2.
1121  */
1122
1123 VOID
1124 out_lw(register int n, register int t)
1125 {
1126         if (hilo) {
1127                 out_lb(hibyte(n),t ? t|R_HIGH : 0);
1128                 out_lb(lobyte(n),t);
1129         } else {
1130                 out_lb(lobyte(n),t);
1131                 out_lb(hibyte(n),t ? t|R_HIGH : 0);
1132         }
1133 }
1134
1135 /*)Function     VOID    out_l24(n, t)
1136  *
1137  *              int     n               assembled data
1138  *              int     t               relocation type
1139  *
1140  *      The function out_l24() copies the assembled data and
1141  *      its relocation type to the list data buffers.
1142  *
1143  *      local variables:
1144  *              none
1145  *
1146  *      global variables:
1147  *              int *   cp              pointer to assembler output array cb[]
1148  *              int *   cpt             pointer to assembler relocation type
1149  *                                      output array cbt[]
1150  *
1151  *      functions called:
1152  *              none
1153  *
1154  *      side effects:
1155  *              Pointers to data and relocation buffers incremented by 3.
1156  */
1157
1158 VOID
1159 out_l24(int n, int t)
1160 {
1161         if (hilo) {
1162                 out_lb(byte3(n),t ? t|R_HIGH : 0);
1163                 out_lb(hibyte(n),t);
1164                 out_lb(lobyte(n),t);
1165         } else {
1166                 out_lb(lobyte(n),t);
1167                 out_lb(hibyte(n),t);
1168                 out_lb(byte3(n),t ? t|R_HIGH : 0);
1169         }
1170 }
1171
1172 /*)Function     VOID    out_rw(n)
1173  *
1174  *              int     n               data word
1175  *
1176  *      The function out_rw() outputs the relocation (R)
1177  *      data word as two bytes ordered according to hilo.
1178  *
1179  *      local variables:
1180  *              int *   relp            pointer to rel array
1181  *
1182  *      global variables:
1183  *              none
1184  *
1185  *      functions called:
1186  *              int     lobyte()        asout.c
1187  *              int     hibyte()        asout.c
1188  *
1189  *      side effects:
1190  *              Pointer to relocation buffer incremented by 2.
1191  */
1192
1193 VOID
1194 out_rw(register int n)
1195 {
1196         if (hilo) {
1197                 *relp++ = hibyte(n);
1198                 *relp++ = lobyte(n);
1199         } else {
1200                 *relp++ = lobyte(n);
1201                 *relp++ = hibyte(n);
1202         }
1203 }
1204
1205 /*)Function     VOID    out_tw(n)
1206  *
1207  *              int     n               data word
1208  *
1209  *      The function out_tw() outputs the text (T)
1210  *      data word as two bytes ordered according to hilo.
1211  *
1212  *      local variables:
1213  *              int *   txtp            pointer to txt array
1214  *
1215  *      global variables:
1216  *              none
1217  *
1218  *      functions called:
1219  *              int     lobyte()        asout.c
1220  *              int     hibyte()        asout.c
1221  *
1222  *      side effects:
1223  *              Pointer to relocation buffer incremented by 2.
1224  */
1225
1226 VOID
1227 out_tw(register int n)
1228 {
1229         if (hilo) {
1230                 *txtp++ = hibyte(n);
1231                 *txtp++ = lobyte(n);
1232         } else {
1233                 *txtp++ = lobyte(n);
1234                 *txtp++ = hibyte(n);
1235         }
1236 }
1237
1238 /*)Function     VOID    out_t24(n)
1239  *
1240  *              int     n               data word
1241  *
1242  *      The function out_t24() outputs the text (T)
1243  *      data word as three bytes ordered according to hilo.
1244  *
1245  *      local variables:
1246  *              int *   txtp            pointer to txt array
1247  *
1248  *      global variables:
1249  *              none
1250  *
1251  *      functions called:
1252  *              int     lobyte()        asout.c
1253  *              int     hibyte()        asout.c
1254  *
1255  *      side effects:
1256  *              Pointer to relocation buffer incremented by 3.
1257  */
1258
1259 VOID
1260 out_t24(int n)
1261 {
1262         if (hilo) {
1263                 *txtp++ = byte3(n);
1264                 *txtp++ = hibyte(n);
1265                 *txtp++ = lobyte(n);
1266         } else {
1267                 *txtp++ = lobyte(n);
1268                 *txtp++ = hibyte(n);
1269                 *txtp++ = byte3(n);
1270         }
1271 }
1272
1273 /*)Function     int     lobyte(n)
1274  *
1275  *              int     n               data word
1276  *
1277  *      The function lobyte() returns the lower byte of
1278  *      integer n.
1279  *
1280  *      local variables:
1281  *              none
1282  *
1283  *      global variables:
1284  *              none
1285  *
1286  *      functions called:
1287  *              none
1288  *
1289  *      side effects:
1290  *              none
1291  */
1292
1293 int
1294 lobyte(int n)
1295 {
1296         return (n&0377);
1297 }
1298
1299 /*)Function     int     hibyte(n)
1300  *
1301  *              int     n               data word
1302  *
1303  *      The function hibyte() returns the higher byte of
1304  *      integer n.
1305  *
1306  *      local variables:
1307  *              none
1308  *
1309  *      global variables:
1310  *              none
1311  *
1312  *      functions called:
1313  *              none
1314  *
1315  *      side effects:
1316  *              none
1317  */
1318
1319 int
1320 hibyte(int n)
1321 {
1322         return ((n>>8)&0377);
1323 }
1324
1325 /*)Function     int     byte3(n)
1326  *
1327  *              int     n               24 bit data
1328  *
1329  *      The function byte3() returns the MSB of the
1330  *      24 bit integer n.
1331  *
1332  *      local variables:
1333  *              none
1334  *
1335  *      global variables:
1336  *              none
1337  *
1338  *      functions called:
1339  *              none
1340  *
1341  *      side effects:
1342  *              none
1343  */
1344 int
1345 byte3(int n)
1346 {
1347         return ((n >> 16) & 0xff);
1348 }
1349
1350 /*
1351  * JLH: Output relocatable 11 bit jump/call
1352  *
1353  * This function is derived from outrw(), adding the parameter for the
1354  * 11 bit address.  This form of address is used only on the 8051 and 8048.
1355  */
1356 VOID
1357 outr11(register struct expr *esp, int op, int r)
1358 {
1359         register int n;
1360
1361         if (pass == 2) {
1362                 if (esp->e_flag==0 && esp->e_base.e_ap==NULL) {
1363                         /* Absolute destination.
1364                          * Listing shows only the address.
1365                          */
1366                         out_lw(esp->e_addr,0);
1367                         if (oflag) {
1368                                 outchk(3, 0);
1369                                 out_tw(esp->e_addr);
1370                                 *txtp++ = op;
1371
1372                                 write_rmode(r);
1373                                 *relp++ = txtp - txt - 3;
1374                                 out_rw(0xFFFF);
1375                         }
1376                 } else {
1377                         /* Relocatable destination.  Build THREE
1378                          * byte output: relocatable word, followed
1379                          * by op-code.  Linker will combine them.
1380                          * Listing shows only the address.
1381                          */
1382                         r |= R_WORD | esp->e_rlcf;
1383                         out_lw(esp->e_addr,r|R_RELOC);
1384                         if (oflag) {
1385                                 outchk(3, 5);
1386                                 out_tw(esp->e_addr);
1387                                 *txtp++ = op;
1388
1389                                 if (esp->e_flag) {
1390                                         n = esp->e_base.e_sp->s_ref;
1391                                         r |= R_SYM;
1392                                 } else {
1393                                         n = esp->e_base.e_ap->a_ref;
1394                                 }
1395                                 write_rmode(r);
1396                                 *relp++ = txtp - txt - 3;
1397                                 out_rw(n);
1398                         }
1399                 }
1400         }
1401         dot.s_addr += 2;
1402 }
1403
1404 /*
1405  * Output relocatable 19 bit jump/call
1406  *
1407  * This function is derived from outrw(), adding the parameter for the
1408  * 19 bit address.  This form of address is used only in the DS80C390
1409  * Flat24 mode.
1410  */
1411 VOID
1412 outr19(struct expr * esp, int op, int r)
1413 {
1414         register int n;
1415
1416         if (pass == 2) {
1417                 if (esp->e_flag==0 && esp->e_base.e_ap==NULL) {
1418                         /* Absolute destination.
1419                          * Listing shows only the address.
1420                          */
1421                         out_lw(esp->e_addr,0);
1422                         if (oflag) {
1423                                 outchk(4, 0);
1424                                 out_t24(esp->e_addr);
1425                                 *txtp++ = op;
1426
1427                                 write_rmode(r);
1428                                 *relp++ = txtp - txt - 4;
1429                                 out_rw(0xFFFF);
1430                         }
1431                 } else {
1432                         /* Relocatable destination.  Build FOUR
1433                          * byte output: relocatable 24-bit entity, followed
1434                          * by op-code.  Linker will combine them.
1435                          * Listing shows only the address.
1436                          */
1437                         r |= R_WORD | esp->e_rlcf;
1438                         out_l24(esp->e_addr,r|R_RELOC);
1439                         if (oflag) {
1440                                 outchk(4, 5);
1441                                 out_t24(esp->e_addr);
1442                                 *txtp++ = op;
1443
1444                                 if (esp->e_flag) {
1445                                         n = esp->e_base.e_sp->s_ref;
1446                                         r |= R_SYM;
1447                                 } else {
1448                                         n = esp->e_base.e_ap->a_ref;
1449                                 }
1450                                 write_rmode(r);
1451                                 *relp++ = txtp - txt - 4;
1452                                 out_rw(n);
1453                         }
1454                 }
1455         }
1456         dot.s_addr += 3;
1457 }