/* asout.c */ /* * (C) Copyright 1989-1995 * All Rights Reserved * * Alan R. Baldwin * 721 Berkeley St. * Kent, Ohio 44240 */ #include #include #include #include "asm.h" /*)Module asout.c * * The module asout.c contains all the functions used to * generate the .REL assembler output file. * * * The assemblers' output object file is an ascii file containing * the information needed by the linker to bind multiple object * modules into a complete loadable memory image. * * The object module contains the following designators: * * [XDQ][HL] * X Hexidecimal radix * D Decimal radix * Q Octal radix * * H Most significant byte first * L Least significant byte first * * H Header * M Module * A Area * S Symbol * T Object code * R Relocation information * P Paging information * * * (1) Radix Line * * The first line of an object module contains the [XDQ][HL] * format specifier (i.e. XH indicates a hexidecimal file with * most significant byte first) for the following designators. * * * (2) Header Line * * H aa areas gg global symbols * * The header line specifies the number of areas(aa) and the * number of global symbols(gg) defined or referenced in this ob- * ject module segment. * * * (3) Module Line * * M name * * The module line specifies the module name from which this * header segment was assembled. The module line will not appear * if the .module directive was not used in the source program. * * * (4) Symbol Line * * S string Defnnnn * * or * * S string Refnnnn * * The symbol line defines (Def) or references (Ref) the symbol * 'string' with the value nnnn. The defined value is relative to * the current area base address. References to constants and ex- * ternal global symbols will always appear before the first area * definition. References to external symbols will have a value of * zero. * * * (5) Area Line * * A label size ss flags ff * * The area line defines the area label, the size (ss) of the * area in bytes, and the area flags (ff). The area flags specify * the ABS, REL, CON, OVR, and PAG parameters: * * OVR/CON (0x04/0x00 i.e. bit position 2) * * ABS/REL (0x08/0x00 i.e. bit position 3) * * PAG (0x10 i.e. bit position 4) * * * (6) T Line * * T xx xx nn nn nn nn nn ... * * The T line contains the assembled code output by the assem- * bler with xx xx being the offset address from the current area * base address and nn being the assembled instructions and data in * byte format. * * * (7) R Line * * R 0 0 nn nn n1 n2 xx xx ... * * The R line provides the relocation information to the linker. * The nn nn value is the current area index, i.e. which area the * current values were assembled. Relocation information is en- * coded in groups of 4 bytes: * * 1. n1 is the relocation mode and object format * 1. bit 0 word(0x00)/byte(0x01) * 2. bit 1 relocatable area(0x00)/symbol(0x02) * 3. bit 2 normal(0x00)/PC relative(0x04) relocation * 4. bit 3 1-byte(0x00)/2-byte(0x08) object format for * byte data * 5. bit 4 signed(0x00)/unsigned(0x10) byte data * 6. bit 5 normal(0x00)/page '0'(0x20) reference * 7. bit 6 normal(0x00)/page 'nnn'(0x40) reference * 8. bit 7 normal(0x00)/MSB of value * * 2. n2 is a byte index into the corresponding (i.e. pre- * ceeding) T line data (i.e. a pointer to the data to be * updated by the relocation). The T line data may be * 1-byte or 2-byte byte data format or 2-byte word * format. * * 3. xx xx is the area/symbol index for the area/symbol be- * ing referenced. the corresponding area/symbol is found * in the header area/symbol lists. * * * The groups of 4 bytes are repeated for each item requiring relo- * cation in the preceeding T line. * * * (8) P Line * * P 0 0 nn nn n1 n2 xx xx * * The P line provides the paging information to the linker as * specified by a .setdp directive. The format of the relocation * information is identical to that of the R line. The correspond- * ing T line has the following information: * T xx xx aa aa bb bb * * Where aa aa is the area reference number which specifies the * selected page area and bb bb is the base address of the page. * bb bb will require relocation processing if the 'n1 n2 xx xx' is * specified in the P line. The linker will verify that the base * address is on a 256 byte boundary and that the page length of an * area defined with the PAG type is not larger than 256 bytes. * * The linker defaults any direct page references to the first * area defined in the input REL file. All ASxxxx assemblers will * specify the _CODE area first, making this the default page area. * * * asout.c contains the following functions: * int lobyte() * int hibyte() * VOID out() * VOID outab() * VOID outall() * VOID outarea() * VOID outaw() * VOID outbuf() * VOID outchk() * VOID outdot() * VOID outdp() * VOID outgsd() * VOID outrb() * VOID outrw() * VOID outsym() * VOID out_lb() * VOID out_lw() * VOID out_rw() * VOID out_tw() * * The module asout.c contains the following local variables: * int rel[] relocation data for code/data array * int * relp pointer to rel array * int txt[] assembled code/data array * int * txtp pointer to txt array */ #define NTXT 16 #define NREL 16 char txt[NTXT]; char rel[NREL]; char *txtp = { &txt[0] }; char *relp = { &rel[0] }; /*)Function VOID outab(b) * * int b assembler data word * * The function outab() processes a single word of * assembled data in absolute format. * * local variables: * int * txtp pointer to data word * * global variables: * int oflag -o, generate relocatable output flag * int pass assembler pass number * * functions called: * VOID outchk() asout.c * VOID out_lb() asout.c * * side effects: * The current assembly address is incremented by 1. */ VOID outab(b) { if (pass == 2) { out_lb(b,0); if (oflag) { outchk(1, 0); *txtp++ = lobyte(b); } } ++dot.s_addr; } /*)Function VOID outaw(w) * * int w assembler data word * * The function outaw() processes a single word of * assembled data in absolute format. * * local variables: * int * txtp pointer to data word * * global variables: * int oflag -o, generate relocatable output flag * int pass assembler pass number * * functions called: * VOID outchk() asout.c * VOID out_lw() asout.c * * side effects: * The current assembly address is incremented by 2. */ VOID outaw(w) { if (pass == 2) { out_lw(w,0); if (oflag) { outchk(2, 0); out_tw(w); } } dot.s_addr += 2; } /*)Function VOID outrb(esp, r) * * expr * esp pointer to expr structure * int r relocation mode * * The function outrb() processes a byte of generated code * in either absolute or relocatable format dependent upon * the data contained in the expr structure esp. If the * .REL output is enabled then the appropriate information * is loaded into the txt and rel buffers. * * local variables: * int n symbol/area reference number * int * relp pointer to rel array * int * txtp pointer to txt array * * global variables: * sym dot defined as sym[0] * int oflag -o, generate relocatable output flag * int pass assembler pass number * * functions called: * VOID aerr() assubr.c * VOID outchk() asout.c * VOID out_lb() asout.c * VOID out_rb() asout.c * VOID out_tb() asout.c * * side effects: * The current assembly address is incremented by 1. */ VOID outrb(esp, r) register struct expr *esp; int r; { register int n; if (pass == 2) { if (esp->e_flag==0 && esp->e_base.e_ap==NULL) { out_lb(lobyte(esp->e_addr),0); if (oflag) { outchk(1, 0); *txtp++ = lobyte(esp->e_addr); } } else { r |= R_BYTE | R_BYT2 | esp->e_rlcf; if (r & R_MSB) { out_lb(hibyte(esp->e_addr),r|R_RELOC|R_HIGH); } else { out_lb(lobyte(esp->e_addr),r|R_RELOC); } if (oflag) { outchk(2, 4); out_tw(esp->e_addr); if (esp->e_flag) { n = esp->e_base.e_sp->s_ref; r |= R_SYM; } else { n = esp->e_base.e_ap->a_ref; } *relp++ = r; *relp++ = txtp - txt - 2; out_rw(n); } } } ++dot.s_addr; } /*)Function VOID outrw(esp, r) * * expr * esp pointer to expr structure * int r relocation mode * * The function outrw() processes a word of generated code * in either absolute or relocatable format dependent upon * the data contained in the expr structure esp. If the * .REL output is enabled then the appropriate information * is loaded into the txt and rel buffers. * * local variables: * int n symbol/area reference number * int * relp pointer to rel array * int * txtp pointer to txt array * * global variables: * sym dot defined as sym[0] * int oflag -o, generate relocatable output flag * int pass assembler pass number * * functions called: * VOID aerr() assubr.c * VOID outchk() asout.c * VOID out_lw() asout.c * VOID out_rw() asout.c * VOID out_tw() asout.c * * side effects: * The current assembly address is incremented by 2. */ VOID outrw(esp, r) register struct expr *esp; int r; { register int n; if (pass == 2) { if (esp->e_flag==0 && esp->e_base.e_ap==NULL) { out_lw(esp->e_addr,0); if (oflag) { outchk(2, 0); out_tw(esp->e_addr); } } else { r |= R_WORD | esp->e_rlcf; if (r & R_BYT2) { rerr(); if (r & R_MSB) { out_lw(hibyte(esp->e_addr),r|R_RELOC); } else { out_lw(lobyte(esp->e_addr),r|R_RELOC); } } else { out_lw(esp->e_addr,r|R_RELOC); } if (oflag) { outchk(2, 4); out_tw(esp->e_addr); if (esp->e_flag) { n = esp->e_base.e_sp->s_ref; r |= R_SYM; } else { n = esp->e_base.e_ap->a_ref; } *relp++ = r; *relp++ = txtp - txt - 2; out_rw(n); } } } dot.s_addr += 2; } /*)Function VOID outdp(carea, esp) * * area * carea pointer to current area strcuture * expr * esp pointer to expr structure * * The function outdp() flushes the output buffer and * outputs paging information to the .REL file. * * local variables: * int n symbol/area reference number * int r relocation mode * int * relp pointer to rel array * int * txtp pointer to txt array * * global variables: * int oflag -o, generate relocatable output flag * int pass assembler pass number * * functions called: * VOID outbuf() asout.c * VOID outchk() asout.c * VOID out_rw() asout.c * VOID out_tw() asout.c * * side effects: * Output buffer flushed to .REL fiel. * Paging information dumped to .REL file. */ VOID outdp(carea, esp) register struct area *carea; register struct expr *esp; { register int n, r; if (oflag && pass==2) { outchk(HUGE,HUGE); out_tw(carea->a_ref); out_tw(esp->e_addr); if (esp->e_flag || esp->e_base.e_ap!=NULL) { r = R_WORD; if (esp->e_flag) { n = esp->e_base.e_sp->s_ref; r |= R_SYM; } else { n = esp->e_base.e_ap->a_ref; } *relp++ = r; *relp++ = txtp - txt - 2; out_rw(n); } outbuf("P"); } } /*)Function VOID outall() * * The function outall() will output any bufferred assembled * data and relocation information (during pass 2 if the .REL * output has been enabled). * * local variables: * none * * global variables: * int oflag -o, generate relocatable output flag * int pass assembler pass number * * functions called: * VOID outbuf() asout.c * * side effects: * assembled data and relocation buffers will be cleared. */ VOID outall() { if (oflag && pass==2) outbuf("R"); } /*)Function VOID outdot() * * The function outdot() outputs information about the * current program counter value (during pass 2 if the .REL * output has been enabled). * * local variables: * none * * global variables: * int oflag -o, generate relocatable output flag * int pass assembler pass number * * functions called: * int fprintf() c_library * VOID out() asout.c * * side effects: * assembled data and relocation buffers will be cleared. */ VOID outdot() { if (oflag && pass==2) { fprintf(ofp, "T"); out(txt,(int) (txtp-txt)); fprintf(ofp, "\n"); fprintf(ofp, "R"); out(rel,(int) (relp-rel)); fprintf(ofp, "\n"); txtp = txt; relp = rel; } } /*)Function outchk(nt, nr) * * int nr number of additional relocation words * int nt number of additional data words * * The function outchk() checks the data and relocation buffers * for space to insert the nt data words and nr relocation words. * If space is not available then output the current data and * initialize the data buffers to receive the new data. * * local variables: * area * ap pointer to an area structure * int * relp pointer to rel array * int * txtp pointer to txt array * * global variables: * sym dot defined as sym[0] * * functions called: * VOID outbuf() asout.c * * side effects: * Data and relocation buffers may be emptied and initialized. */ VOID outchk(nt, nr) { register struct area *ap; if (txtp+nt > &txt[NTXT] || relp+nr > &rel[NREL]) { outbuf("R"); } if (txtp == txt) { out_tw(dot.s_addr); if ((ap = dot.s_area) != NULL) { *relp++ = R_WORD|R_AREA; *relp++ = 0; out_rw(ap->a_ref); } } } /*)Function VOID outbuf() * * The function outbuf() will output any bufferred data * and relocation information to the .REL file. The output * buffer pointers and counters are initialized. * * local variables: * int rel[] relocation data for code/data array * int * relp pointer to rel array * int txt[] assembled code/data array * int * txtp pointer to txt array * * global variables: * FILE * ofp relocation output file handle * * functions called: * VOID out() asout.c * * side effects: * All bufferred data written to .REL file and * buffer pointers and counters initialized. */ VOID outbuf(s) char *s; { if (txtp > &txt[2]) { fprintf(ofp, "T"); out(txt,(int) (txtp-txt)); fprintf(ofp, "\n"); fprintf(ofp, s); out(rel,(int) (relp-rel)); fprintf(ofp, "\n"); } txtp = txt; relp = rel; } /*)Function VOID outgsd() * * The function outgsd() performs the following: * (1) outputs the .REL file radix * (2) outputs the header specifying the number * of areas and global symbols * (3) outputs the module name * (4) set the reference number and output a symbol line * for all external global variables and absolutes * (5) output an area name, set reference number and output * a symbol line for all global relocatables in the area. * Repeat this proceedure for all areas. * * local variables: * area * ap pointer to an area structure * sym * sp pointer to a sym structure * int i loop counter * int j loop counter * int c string character value * int narea number of code areas * char * ptr string pointer * int nglob number of global symbols * int rn symbol reference number * * global variables: * area * areap pointer to an area structure * char module[] module name string * sym * symhash[] array of pointers to NHASH * linked symbol lists * int xflag -x, listing radix flag * * functions called: * int fprintf() c_library * VOID outarea() asout.c * VOID outsym() asout.c * int putc() c_library * * side effects: * All symbols are given reference numbers, all symbol * and area information is output to the .REL file. */ VOID outgsd() { register struct area *ap; register struct sym *sp; register int i, j; char *ptr; int c, narea, nglob, rn; /* * Number of areas */ narea = areap->a_ref + 1; /* * Number of global references/absolutes */ nglob = 0; for (i = 0; i < NHASH; ++i) { sp = symhash[i]; while (sp) { if (sp->s_flag&S_GBL) ++nglob; sp = sp->s_sp; } } /* * Output Radix and number of areas and symbols */ if (xflag == 0) { fprintf(ofp, "X%c\n", hilo ? 'H' : 'L'); fprintf(ofp, "H %X areas %X global symbols\n", narea, nglob); } else if (xflag == 1) { fprintf(ofp, "Q%c\n", hilo ? 'H' : 'L'); fprintf(ofp, "H %o areas %o global symbols\n", narea, nglob); } else if (xflag == 2) { fprintf(ofp, "D%c\n", hilo ? 'H' : 'L'); fprintf(ofp, "H %u areas %u global symbols\n", narea, nglob); } /* * Module name */ if (module[0]) { fprintf(ofp, "M "); ptr = &module[0]; while (ptr < &module[NCPS]) { if ((c = *ptr++) != 0) putc(c, ofp); } putc('\n', ofp); } /* * Global references and absolutes. */ rn = 0; for (i=0; is_area==NULL && sp->s_flag&S_GBL) { sp->s_ref = rn++; outsym(sp); } sp = sp->s_sp; } } /* * Global relocatables. */ for (i=0; ia_ref != i) ap = ap->a_ap; outarea(ap); for (j=0; js_area==ap && sp->s_flag&S_GBL) { sp->s_ref = rn++; outsym(sp); } sp = sp->s_sp; } } } } /*)Function VOID outarea(ap) * * area * ap pointer to an area structure * * The function outarea() outputs the A line to the .REL * file. The A line contains the area's name, size, and * attributes. * * local variables: * char * ptr pointer to area id string * int c character value * * global variables: * FILE * ofp relocation output file handle * int xflag -x, listing radix flag * * functions called: * int fprintf() c_library * int putc() c_library * * side effects: * The A line is sent to the .REL file. */ VOID outarea(ap) register struct area *ap; { register char *ptr; register int c; fprintf(ofp, "A "); ptr = &ap->a_id[0]; while (ptr < &ap->a_id[NCPS]) { if ((c = *ptr++) != 0) putc(c, ofp); } if (xflag == 0) { fprintf(ofp, " size %X flags %X\n", ap->a_size, ap->a_flag); } else if (xflag == 1) { fprintf(ofp, " size %o flags %o\n", ap->a_size, ap->a_flag); } else if (xflag == 2) { fprintf(ofp, " size %u flags %u\n", ap->a_size, ap->a_flag); } } /*)Function VOID outsym(sp) * * sym * sp pointer to a sym structure * * The function outsym() outputs the S line to the .REL * file. The S line contains the symbols name and whether the * the symbol is defined or referenced. * * local variables: * char * ptr pointer to symbol id string * int c character value * * global variables: * FILE * ofp relocation output file handle * int xflag -x, listing radix flag * * functions called: * int fprintf() c_library * int putc() c_library * * side effects: * The S line is sent to the .REL file. */ VOID outsym(sp) register struct sym *sp; { register char *ptr; register int c; fprintf(ofp, "S "); ptr = &sp->s_id[0]; while (ptr < &sp->s_id[NCPS]) { if ((c = *ptr++) != 0) putc(c, ofp); } fprintf(ofp, " %s", sp->s_type==S_NEW ? "Ref" : "Def"); if (xflag == 0) { fprintf(ofp, "%04X\n", sp->s_addr); } else if (xflag == 1) { fprintf(ofp, "%06o\n", sp->s_addr); } else if (xflag == 2) { fprintf(ofp, "%05u\n", sp->s_addr); } } /*)Function VOID out(p, n) * * int n number of words to output * int * p pointer to data words * * The function out() outputs the data words to the .REL file * int the specified radix. * * local variables: * none * * global variables: * FILE * ofp relocation output file handle * int xflag -x, listing radix flag * * functions called: * int fprintf() c_library * * side effects: * Data is sent to the .REL file. */ VOID out(p, n) register char *p; register int n; { while (n--) { if (xflag == 0) { fprintf(ofp, " %02X", (*p++)&0377); } else if (xflag == 1) { fprintf(ofp, " %03o", (*p++)&0377); } else if (xflag == 2) { fprintf(ofp, " %03u", (*p++)&0377); } } } /*)Function VOID out_lb(b, t) * * int b assembled data * int t relocation type * * The function out_lb() copies the assembled data and * its relocation type to the list data buffers. * * local variables: * none * * global variables: * int * cp pointer to assembler output array cb[] * int * cpt pointer to assembler relocation type * output array cbt[] * * functions called: * none * * side effects: * Pointers to data and relocation buffers incremented by 1. */ VOID out_lb(b,t) register int b,t; { if (cp < &cb[NCODE]) { *cp++ = b; *cpt++ = t; } } /*)Function VOID out_lw(n, t) * * int n assembled data * int t relocation type * * The function out_lw() copies the assembled data and * its relocation type to the list data buffers. * * local variables: * none * * global variables: * int * cp pointer to assembler output array cb[] * int * cpt pointer to assembler relocation type * output array cbt[] * * functions called: * none * * side effects: * Pointers to data and relocation buffers incremented by 2. */ VOID out_lw(n,t) register int n,t; { if (hilo) { out_lb(hibyte(n),t ? t|R_HIGH : 0); out_lb(lobyte(n),t); } else { out_lb(lobyte(n),t); out_lb(hibyte(n),t ? t|R_HIGH : 0); } } /*)Function VOID out_rw(n) * * int n data word * * The function out_rw() outputs the relocation (R) * data word as two bytes ordered according to hilo. * * local variables: * int * relp pointer to rel array * * global variables: * none * * functions called: * int lobyte() asout.c * int hibyte() asout.c * * side effects: * Pointer to relocation buffer incremented by 2. */ VOID out_rw(n) register int n; { if (hilo) { *relp++ = hibyte(n); *relp++ = lobyte(n); } else { *relp++ = lobyte(n); *relp++ = hibyte(n); } } /*)Function VOID out_tw(n) * * int n data word * * The function out_tw() outputs the text (T) * data word as two bytes ordered according to hilo. * * local variables: * int * txtp pointer to txt array * * global variables: * none * * functions called: * int lobyte() asout.c * int hibyte() asout.c * * side effects: * Pointer to relocation buffer incremented by 2. */ VOID out_tw(n) register int n; { if (hilo) { *txtp++ = hibyte(n); *txtp++ = lobyte(n); } else { *txtp++ = lobyte(n); *txtp++ = hibyte(n); } } /*)Function int lobyte(n) * * int n data word * * The function lobyte() returns the lower byte of * integer n. * * local variables: * none * * global variables: * none * * functions called: * none * * side effects: * none */ int lobyte(n) { return (n&0377); } /*)Function int hibyte(n) * * int n data word * * The function hibyte() returns the higher byte of * integer n. * * local variables: * none * * global variables: * none * * functions called: * none * * side effects: * none */ int hibyte(n) { return ((n>>8)&0377); }