2.5.7 R Line
- R 0 0 nn nn n1 n2 xx xx ...
+ R 0 0 nn nn n1 [n1x] 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:
+ coded in groups of 4 (possibly 5) bytes:
- 1. n1 is the relocation mode and object format
+ 1. n1 (and optionally n1x) 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
+ 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 LSB byte(0x00)/MSB byte(0x80) with 2-byte
- mode
+ 8. bit 7 LSB byte(0x00)/MSB byte(0x80) with 2-byte
+ mode
+ 9. bit 8 1 or 2 (0x00)/3-byte (0x100) object format
+ for byte data.
+ 10. bit 9 LSB or MSB (middle byte) (0x00) or byte 3
+ (real MSB) (0x200) for 3-byte mode.
+
+ If the upper four bits of n1 are set (i.e.
+ (n1 & 0xf0) == 0xf0), it is taken as an escape character,
+ and the relocation mode will consist of the lower four bits
+ of n1 left shifted 8 bits or'ed with the value of n1x. If
+ the upper four bits of n1 are not all set, then it is not an
+ escape character, and the n1x byte is not present.
+
+ This escape mechanism allows a 12-bit relocation mode value.
+
+ Note that in byte mode, when 3-byte mode is used (bits 0
+ and 8 are both set), the MSB bit (bit 7) really refers to
+ the 16 bit MSB (the middle byte of the 24-bit value) while
+ the "byte 3" bit (bit 9) refers to the 24-bit MSB.
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
esp->e_rlcf |= R_MSB ;
break;
}
+ else if (esp->e_base.e_ap && re.e_addr == 16)
+ {
+ if (flat24Mode)
+ {
+ esp->e_rlcf |= R_HIB;
+ }
+ else
+ {
+ warnBanner();
+ fprintf(stderr,
+ "(expr >> 16) is only meaningful in "
+ ".flat24 mode.\n");
+ qerr();
+ }
+
+ break;
+ }
/* else continue with the normal processing */
abscheck(esp);
esp->e_addr >>= re.e_addr;
* +-----+-----+-----+-----+-----+-----+-----+-----+
*/
-#define R_WORD 0000 /* 16 bit */
-#define R_BYTE 0001 /* 8 bit */
+#define R_WORD 0x00 /* 16 bit */
+#define R_BYTE 0x01 /* 8 bit */
-#define R_AREA 0000 /* Base type */
-#define R_SYM 0002
+#define R_AREA 0x00 /* Base type */
+#define R_SYM 0x02
-#define R_NORM 0000 /* PC adjust */
-#define R_PCR 0004
+#define R_NORM 0x00 /* PC adjust */
+#define R_PCR 0x04
-#define R_BYT1 0000 /* Byte count for R_BYTE = 1 */
-#define R_BYT2 0010 /* Byte count for R_BYTE = 2 */
+#define R_BYT1 0x00 /* Byte count for R_BYTE = 1 */
+#define R_BYT2 0x08 /* Byte count for R_BYTE = 2 */
-#define R_SGND 0000 /* Signed value */
-#define R_USGN 0020 /* Unsigned value */
+#define R_SGND 0x00 /* Signed Byte */
+#define R_USGN 0x10 /* Unsigned Byte */
-#define R_NOPAG 0000 /* Page Mode */
-#define R_PAG0 0040 /* Page '0' */
-#define R_PAG 0100 /* Page 'nnn' */
+#define R_NOPAG 0x00 /* Page Mode */
+#define R_PAG0 0x20 /* Page '0' */
+#define R_PAG 0x40 /* Page 'nnn' */
-/*
- * Valid for R_BYT2:
- */
-#define R_LSB 0000 /* output low byte */
-#define R_MSB 0200 /* output high byte */
+#define R_LSB 0x00 /* low byte */
+#define R_MSB 0x80 /* high byte */
+
+#define R_BYT3 0x100 /* if R_BYTE is set, this is a
+ * 3 byte address, of which
+ * the linker must select one byte.
+ */
+#define R_HIB 0x200 /* If R_BYTE & R_BYT3 are set, linker
+ * will select byte 3 of the relocated
+ * 24 bit address.
+ */
#define R_J11 (R_WORD|R_BYT2) /* JLH: 11 bit JMP and CALL (8051) */
#define R_J19 (R_WORD|R_BYT2|R_MSB) /* 19 bit JMP/CALL (DS80C390) */
#define IS_R_J11(x) (((x) & R_J19_MASK) == R_J11)
#define IS_C24(x) (((x) & R_J19_MASK) == R_C24)
+#define R_ESCAPE_MASK 0xf0 /* Used to escape relocation modes
+ * greater than 0xff in the .rel
+ * file.
+ */
+
/*
* Global symbol types.
*/
extern addr_t adb_b();
extern addr_t adb_hi();
extern addr_t adb_lo();
+extern addr_t adb_24_hi(addr_t v, int i);
+extern addr_t adb_24_mid(addr_t v, int i);
+extern addr_t adb_24_lo(addr_t v, int i);
extern addr_t adw_w();
extern addr_t adw_24(addr_t, int);
extern addr_t adw_hi();
* +-----+-----+-----+-----+-----+-----+-----+-----+
*/
-#define R_WORD 0000 /* 16 bit */
-#define R_BYTE 0001 /* 8 bit */
+#define R_WORD 0x00 /* 16 bit */
+#define R_BYTE 0x01 /* 8 bit */
-#define R_AREA 0000 /* Base type */
-#define R_SYM 0002
+#define R_AREA 0x00 /* Base type */
+#define R_SYM 0x02
-#define R_NORM 0000 /* PC adjust */
-#define R_PCR 0004
+#define R_NORM 0x00 /* PC adjust */
+#define R_PCR 0x04
-#define R_BYT1 0000 /* Byte count for R_BYTE = 1 */
-#define R_BYT2 0010 /* Byte count for R_BYTE = 2 */
+#define R_BYT1 0x00 /* Byte count for R_BYTE = 1 */
+#define R_BYT2 0x08 /* Byte count for R_BYTE = 2 */
-#define R_SGND 0000 /* Signed Byte */
-#define R_USGN 0020 /* Unsigned Byte */
+#define R_SGND 0x00 /* Signed Byte */
+#define R_USGN 0x10 /* Unsigned Byte */
-#define R_NOPAG 0000 /* Page Mode */
-#define R_PAG0 0040 /* Page '0' */
-#define R_PAG 0100 /* Page 'nnn' */
+#define R_NOPAG 0x00 /* Page Mode */
+#define R_PAG0 0x20 /* Page '0' */
+#define R_PAG 0x40 /* Page 'nnn' */
-#define R_LSB 0000 /* low byte */
-#define R_MSB 0200 /* high byte */
+#define R_LSB 0x00 /* low byte */
+#define R_MSB 0x80 /* high byte */
+
+#define R_BYT3 0x100 /* if R_BYTE is set, this is a
+ * 3 byte address, of which
+ * the linker must select one byte.
+ */
+#define R_HIB 0x200 /* If R_BYTE & R_BYT3 are set, linker
+ * will select byte 3 of the relocated
+ * 24 bit address.
+ */
#define R_J11 (R_WORD|R_BYT2) /* JLH: 11 bit JMP and CALL (8051) */
#define R_J19 (R_WORD|R_BYT2|R_MSB) /* 19 bit JMP/CALL (DS80C390) */
#define IS_R_J11(x) (((x) & R_J19_MASK) == R_J11)
#define IS_C24(x) (((x) & R_J19_MASK) == R_C24)
+#define R_ESCAPE_MASK 0xf0 /* Used to escape relocation modes
+ * greater than 0xff in the .rel
+ * file.
+ */
+
/*
* Listing Control Flags
*/
struct area *e_ap;
struct sym *e_sp;
} e_base; /* Rel. base */
- char e_rlcf; /* Rel. flags */
+ int e_rlcf; /* Rel. flags */
};
/* C Library functions */
extern VOID outchk();
extern VOID outgsd();
extern VOID outrb();
-extern VOID outrw();
+extern VOID outrw(struct expr *, int);
extern VOID outr24(struct expr *, int);
extern VOID outsym();
extern VOID out_lb();
dot.s_addr += 2;
}
+/*)Function VOID write_rmode(r)
+ *
+ * int r relocation mode
+ *
+ * write_rmode puts the passed relocation mode into the
+ * output relp buffer, escaping it if necessary.
+ *
+ * global variables:
+ * int * relp pointer to rel array
+ *
+ * functions called:
+ * VOID rerr() assubr.c
+ *
+ * side effects:
+ * relp is incremented appropriately.
+ */
+VOID
+write_rmode(int r)
+{
+ /* We need to escape the relocation mode if it is greater
+ * than a byte, or if it happens to look like an escape.
+ * (I don't think that the latter case is legal, but
+ * better safe than sorry).
+ */
+ if ((r > 0xff) || ((r & R_ESCAPE_MASK) == R_ESCAPE_MASK))
+ {
+ /* Hack in up to an extra 4 bits of flags with escape. */
+ if (r > 0xfff)
+ {
+ /* uh-oh.. we have more than 4 extra bits. */
+ fprintf(stderr,
+ "Internal error: relocation mode 0x%X too big.\n",
+ r);
+ rerr();
+ }
+ /* printf("escaping relocation mode\n"); */
+ *relp++ = R_ESCAPE_MASK | (r >> 8);
+ *relp++ = r & 0xff;
+ }
+ else
+ {
+ *relp++ = r;
+ }
+}
+
/*)Function VOID outrb(esp, r)
*
* expr * esp pointer to expr structure
*/
VOID
-outrb(esp, r)
-register struct expr *esp;
-int r;
+outrb(struct expr *esp, int r)
{
register int n;
if (pass == 2) {
if (esp->e_flag==0 && esp->e_base.e_ap==NULL) {
+ /* This is a constant; simply write the
+ * const byte to the T line and don't
+ * generate any relocation info.
+ */
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) {
+ /* We are generating a single byte of relocatable
+ * info.
+ *
+ * In 8051 mode, we generate a 16 bit address. The
+ * linker will later select a single byte based on
+ * whether R_MSB is set.
+ *
+ * In flat24 mode, we generate a 24 bit address. The
+ * linker will select a single byte based on
+ * whether R_MSB or R_HIB is set.
+ */
+ if (!flat24Mode)
+ {
+ r |= R_BYTE | R_BYT2 | esp->e_rlcf;
+ if (r & R_MSB) {
out_lb(hibyte(esp->e_addr),r|R_RELOC|R_HIGH);
- } else {
+ } else {
out_lb(lobyte(esp->e_addr),r|R_RELOC);
- }
- if (oflag) {
- outchk(2, 4);
+ }
+ if (oflag) {
+ outchk(2, 5);
out_tw(esp->e_addr);
if (esp->e_flag) {
n = esp->e_base.e_sp->s_ref;
} else {
n = esp->e_base.e_ap->a_ref;
}
- *relp++ = r;
+ write_rmode(r);
*relp++ = txtp - txt - 2;
out_rw(n);
+ }
+ }
+ else
+ {
+ /* 24 bit mode. */
+ r |= R_BYTE | R_BYT3 | esp->e_rlcf;
+ if (r & R_HIB)
+ {
+ /* Probably should mark this differently in the
+ * listing file.
+ */
+ out_lb(byte3(esp->e_addr),r|R_RELOC|R_HIGH);
+ }
+ else 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(3, 5);
+ out_t24(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;
+ }
+ write_rmode(r);
+ *relp++ = txtp - txt - 3;
+ out_rw(n);
+ }
}
}
}
*/
VOID
-outrw(esp, r)
-register struct expr *esp;
-int r;
+outrw(struct expr *esp, int r)
{
register int n;
out_lw(esp->e_addr,r|R_RELOC);
}
if (oflag) {
- outchk(2, 4);
+ outchk(2, 5);
out_tw(esp->e_addr);
if (esp->e_flag) {
n = esp->e_base.e_sp->s_ref;
"outrw()\n");
rerr();
}
- *relp++ = r;
+ write_rmode(r);
*relp++ = txtp - txt - 2;
out_rw(n);
}
out_l24(esp->e_addr,r|R_RELOC);
}
if (oflag) {
- outchk(3, 4);
+ outchk(3, 5);
out_t24(esp->e_addr);
if (esp->e_flag) {
n = esp->e_base.e_sp->s_ref;
rerr();
}
- *relp++ = r | R_C24;
+ write_rmode(r | R_C24);
*relp++ = txtp - txt - 3;
out_rw(n);
}
} else {
n = esp->e_base.e_ap->a_ref;
}
- *relp++ = r;
+ write_rmode(r);
*relp++ = txtp - txt - 2;
out_rw(n);
}
if (txtp == txt) {
out_tw(dot.s_addr);
if ((ap = dot.s_area) != NULL) {
- *relp++ = R_WORD|R_AREA;
+ write_rmode(R_WORD|R_AREA);
*relp++ = 0;
out_rw(ap->a_ref);
}
*/
VOID
-out(p, n)
-register char *p;
-register int n;
+out(char *p, int n)
{
while (n--) {
if (xflag == 0) {
- fprintf(ofp, " %02X", (*p++)&0377);
+ fprintf(ofp, " %02X", (*p++)&0xff);
} else
if (xflag == 1) {
- fprintf(ofp, " %03o", (*p++)&0377);
+ fprintf(ofp, " %03o", (*p++)&0xff);
} else
if (xflag == 2) {
- fprintf(ofp, " %03u", (*p++)&0377);
+ fprintf(ofp, " %03u", (*p++)&0xff);
}
}
}
r |= R_WORD | esp->e_rlcf;
out_lw(esp->e_addr,r|R_RELOC);
if (oflag) {
- outchk(3, 4);
+ outchk(3, 5);
out_tw(esp->e_addr);
*txtp++ = op;
} else {
n = esp->e_base.e_ap->a_ref;
}
- *relp++ = r;
+ write_rmode(r);
*relp++ = txtp - txt - 3;
out_rw(n);
}
r |= R_WORD | esp->e_rlcf;
out_l24(esp->e_addr,r|R_RELOC);
if (oflag) {
- outchk(4, 4);
+ outchk(4, 5);
out_t24(esp->e_addr);
*txtp++ = op;
} else {
n = esp->e_base.e_ap->a_ref;
}
- *relp++ = r;
+ write_rmode(r);
*relp++ = txtp - txt - 4;
out_rw(n);
}
while (more()) {
error = 0;
mode = eval();
+
+ if ((mode & R_ESCAPE_MASK) == R_ESCAPE_MASK)
+ {
+ mode = ((mode & ~R_ESCAPE_MASK) << 8) | eval();
+ /* printf("unescaping rmode\n"); */
+ }
+
rtp = eval();
rindex = evword();
/*
* R_PAG0 or R_PAG addressing
*/
- if (mode & (R_PAG0|R_PAG)) {
+ if (mode & (R_PAG0 | R_PAG)) {
paga = sdp.s_area->a_addr;
pags = sdp.s_addr;
reli -= paga + pags;
* R_BYTE or R_WORD operation
*/
if (mode & R_BYTE) {
- if (mode & R_BYT2) {
+ if (mode & R_BYT3)
+ {
+ /* This is a three byte address, of which
+ * we will select one byte.
+ */
+ if (mode & R_HIB)
+ {
+ /* printf("24 bit address selecting hi byte.\n"); */
+ relv = adb_24_hi(reli, rtp);
+ }
+ else if (mode & R_MSB)
+ {
+ /* Note that in 24 bit mode, R_MSB
+ * is really the middle byte, not
+ * the most significant byte.
+ *
+ * This is ugly and I can only apologize
+ * for any confusion.
+ */
+ /* printf("24 bit address selecting middle byte.\n"); */
+ relv = adb_24_mid(reli, rtp);
+ }
+ else
+ {
+ /* printf("24 bit address selecting lo byte.\n"); */
+ relv = adb_24_lo(reli, rtp);
+ }
+ }
+ else if (mode & R_BYT2) {
+ /* This is a two byte address, of
+ * which we will select one byte.
+ */
if (mode & R_MSB) {
relv = adb_hi(reli, rtp);
} else {
return (j);
}
+/*)Function addr_t adb_24_hi(v, i)
+ *
+ * int v value to add to byte
+ * int i rtval[] index
+ *
+ * The function adb_24_hi() adds the value of v to the
+ * 24 bit value contained in rtval[i] - rtval[i+2].
+ * The new value of rtval[i] / rtval[i+1] is returned.
+ * The LSB & middle byte rtflg[] is cleared.
+ *
+ * local variable:
+ * addr_t j temporary evaluation variable
+ *
+ * global variables:
+ * hilo byte ordering parameter
+ *
+ * called functions:
+ * none
+ *
+ * side effects:
+ * The value of rtval[] is changed.
+ * The rtflg[] value corresponding to the
+ * LSB & middle byte of the word value is cleared to
+ * reflect the fact that the MSB is the selected byte.
+ *
+ */
+
+addr_t
+adb_24_hi(addr_t v, int i)
+{
+ register addr_t j;
+
+ j = adw_24(v, i);
+
+ /* Remove the lower two bytes. */
+ if (hilo)
+ {
+ rtflg[i+2] = 0;
+ }
+ else
+ {
+ rtflg[i] = 0;
+ }
+ rtflg[i+1] = 0;
+
+ return (j);
+}
+
+/*)Function addr_t adb_24_mid(v, i)
+ *
+ * int v value to add to byte
+ * int i rtval[] index
+ *
+ * The function adb_24_mid() adds the value of v to the
+ * 24 bit value contained in rtval[i] - rtval[i+2].
+ * The new value of rtval[i] / rtval[i+1] is returned.
+ * The LSB & MSB byte rtflg[] is cleared.
+ *
+ * local variable:
+ * addr_t j temporary evaluation variable
+ *
+ * global variables:
+ * hilo byte ordering parameter
+ *
+ * called functions:
+ * none
+ *
+ * side effects:
+ * The value of rtval[] is changed.
+ * The rtflg[] value corresponding to the
+ * LSB & MSB of the 24 bit value is cleared to reflect
+ * the fact that the middle byte is the selected byte.
+ *
+ */
+
+addr_t
+adb_24_mid(addr_t v, int i)
+{
+ register addr_t j;
+
+ j = adw_24(v, i);
+
+ /* remove the MSB & LSB. */
+ rtflg[i+2] = 0;
+ rtflg[i] = 0;
+
+ return (j);
+}
+
+/*)Function addr_t adb_24_lo(v, i)
+ *
+ * int v value to add to byte
+ * int i rtval[] index
+ *
+ * The function adb_24_lo() adds the value of v to the
+ * 24 bit value contained in rtval[i] - rtval[i+2].
+ * The new value of rtval[i] / rtval[i+1] is returned.
+ * The MSB & middle byte rtflg[] is cleared.
+ *
+ * local variable:
+ * addr_t j temporary evaluation variable
+ *
+ * global variables:
+ * hilo byte ordering parameter
+ *
+ * called functions:
+ * none
+ *
+ * side effects:
+ * The value of rtval[] is changed.
+ * The rtflg[] value corresponding to the
+ * MSB & middle byte of the word value is cleared to
+ * reflect the fact that the LSB is the selected byte.
+ *
+ */
+
+addr_t
+adb_24_lo(addr_t v, int i)
+{
+ register addr_t j;
+
+ j = adw_24(v, i);
+
+ /* Remove the upper two bytes. */
+ if (hilo)
+ {
+ rtflg[i] = 0;
+ }
+ else
+ {
+ rtflg[i+2] = 0;
+ }
+ rtflg[i+1] = 0;
+
+ return (j);
+}
+
/*)Function addr_t adw_w(v, i)
*
* int v value to add to word