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