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