This is disasm.c in view mode; [Download] [Up]
/* disasm.c - 68000 instruction disassembler for NeXT
*
* Copyright (C) 1989 by Bill Spitzak
* See Copyright notice in makefile
*
*/
/* $Log: disasm.c,v $
* Revision 1.9 94/08/24 22:41:58 ediger
* reformatted some static arrays of strings
*
* Revision 1.8 94/08/22 22:30:50 ediger
* small formatting of disasmblock() arguments
*
* Revision 1.7 94/05/30 23:07:30 ediger
* "readability" changes
*
* Revision 1.6 94/01/25 23:37:10 ediger
* clean, reformatting, add comments removed non-symbolic "magic" constants
*
* Revision 1.5 94/01/19 00:12:02 ediger
* bug fixes, reformatting
*
* Revision 1.4 94/01/16 21:10:57 ediger
* fixed bug in parameters sent to disasmblock()
*
* Revision 1.3 94/01/16 17:23:05 ediger
* got rid of phony struct relocation_info definition
*
* Revision 1.2 94/01/16 17:17:44 ediger
* ditched phony nlist struct def
*
* Revision 1.1 94/01/16 16:48:13 ediger
* Initial revision
* */
static char rcsident[] = "$Id: disasm.c,v 1.9 94/08/24 22:41:58 ediger Exp Locker: ediger $";
#include "dis.h"
#include "disasm.h"
/* Semi-table-lookup. An exact match must be found in this table,
an exact match means (inst>=code && (inst&(~mask))==code). This
exact match is found by finding the largest entry <= inst, then
searching backwards.
This means you can special-case sub-instructions that match some
more general instruction. If the special instruction has some 1
bits set in the general instruction's masked-off area, it can be
put after it. If the masked-off bits are all zero, it must be
placed before the general instruction, and the general instruction
modified to have some 1 bits in it's masked-off area so it represents
the lowest number that is a legal version of that instruction.
If no match is found, it is an illegal instruction, which the
disassembler prints as a word of data. [since this would normally
require a backwards search of the whole table, it assummes the
mask will never be larger than 0x0fff, so it can quit when the
top 4 bits don't match]. You can also mark specific instructions
as illegal by putting in an entry with no name. This can mark
illegal addressing modes.
When an entry is found, it prints the name. It then calls the
"extension" routine, which can print more name (such as a w or a
condition code or a coprocessor instruction). If there is a second
routine a tab is printed and that is called, it is supposed to
print the source (or only) argument. If there is a third routine
a comma is printed and it is called, it is supposed to print the
destination. All these routines are passed the original code, and
they should advance the pc to after any data they use.
*/
extern int decimalrange; /* disasm switch, largest decimal value */
typedef void parsefunc(unsigned short);
struct instruction
{
unsigned short code;
unsigned short mask; /* mask is "inverted" so zero means full match */
char *symbol; /* opcode mnemonic */
parsefunc *extension;
parsefunc *source;
parsefunc *dest;
};
/* global disasm state: */
static flag illegal; /* set true if instruction is illegal */
static int targettype; /* 0 or disasmtype of args to instruction */
static void *reloc; /* pointer to address 0 (not necessarily real) */
static void *pc; /* pointer into mapped area */
static void *endpc; /* never disasm something past here! */
static unsigned short inst2; /* second word of long instructions */
static char *cptr; /* pointer into buffer for unparsed inst */
static flag branched; /* set by an unconditional branch */
static struct nlist *sym; /* source symbol, if any, for comments */
#define cput(c) (*cptr++ = (c))
static void
sput(char *c)
{
while (*c)
*cptr++ = *c++;
}
static void
putf(char *fmt, int x)
{
int l;
sprintf(cptr, fmt, x);
l = strlen(cptr);
cptr += l;
/* cptr += sprintf(cptr, fmt, x); */
}
/* eventually this will print aliases for the registers: */
static void
printregister(n)
unsigned int n;
{
n &= 0xf;
switch (n)
{
case 0xf:
sput("sp");
break;
case 0xe:
sput("fp");
break;
default:
cput(n > 7 ? 'a' : 'd');
cput((n & 0x7) + '0');
break;
}
}
/* symbol extension routines: */
void
branch(unsigned short inst)
{
targettype = CODE;
branched = TRUE;
}
void
sizebyte(unsigned short inst)
{
targettype = CHAR;
cput('b');
}
void
sizeword(unsigned short inst)
{
targettype = SHORT;
cput('w');
}
void
sizelong(unsigned short inst)
{
targettype = LONG;
cput('l');
}
void
size(unsigned short inst)
{
switch ((inst >> 6) & 0x3)
{
case 0:
sizebyte(inst);
break;
case 1:
sizeword(inst);
break;
case 2:
sizelong(inst);
break;
case 3:
illegal = TRUE;
break;
}
}
void
brsizew(unsigned short inst)
{
branch(inst);
sizeword(inst);
}
void
condition(unsigned short inst)
{
static char *table[16] = {
"t", "f", "hi", "ls", "cc", "cs", "ne", "eq",
"vc", "vs", "pl", "mi", "ge",
"lt", "gt", "le"};
sput(table[(inst >> 8) & 0xf]);
}
/* get rest of large inst */
void
i2(unsigned short inst)
{
inst2 = *((signed short *)pc)++;
}
/* get mask and size of movem inst */
void
mmtype(unsigned short inst)
{
inst2 = *((signed short *)pc)++;
inst & 0x40 ? sizelong(inst) : sizeword(inst);
}
/* add a s or u to the long multiply/divide instructions */
void
multype(unsigned short inst)
{
inst2 = *((signed short *)pc)++;
cput(inst2 & 0x800 ? 's' : 'u');
sizelong(inst);
}
/* argument printing routines: */
void
putlabel(struct nlist * sym)
{
putf(sym->n_un.n_name != NULL ? sym->n_un.n_name : "D%x", sym->n_value);
}
void
printlabel(struct nlist * sym)
{
fprint(sym->n_un.n_name != NULL ? sym->n_un.n_name : "D%x", sym->n_value);
}
void
putoffset(signed long i, int sign)
{
if (sign && i > 0)
cput('+');
if (i > decimalrange)
putf("0x%x", i);
else if (i < -decimalrange)
putf("-0x%x", -i);
else if (!sign || i)
putf("%d", i);
}
void
printoffset(signed long i, int sign)
{
if (sign && i > 0)
cprint('+');
if (i > decimalrange || (!sign && i < -decimalrange))
fprint("0x%x", i);
else if (i < -decimalrange)
fprint("-0x%x", -i);
else if (!sign || i)
fprint("%d", i);
}
void
putasciichar(int c)
{
switch (c)
{
case '\t':
sput("\\t");
break;
case '\n':
sput("\\n");
break;
case '\r':
sput("\\r");
break;
case '\\':
sput("\\\\");
break;
case '\"':
sput("\\\"");
break;
case '\'':
sput("\\\'");
break;
default:
if (c >= ' ')
cput(c);
else
putf("\\0%o", c);
break;
}
}
/* most recent symbol, for case tables */
static struct nlist *lastrefsymbol = NULL;
void
immediate(unsigned short inst)
{
signed long i;
void *rpc;
rpc = pc;
cput('#');
sym = 0;
switch (targettype)
{
case LONG:
i = *((long *)pc)++;
sym = getlabel((long unsigned *)&i, rpc, FALSE);
if (sym)
putlabel(sym);
break;
case SHORT:
i = *((signed short *)pc)++;
break;
case CHAR:
i = (signed char)*((signed short *)pc)++;
if (i >= ' ' && i < 127)
{
cput('\'');
putasciichar(i);
cput('\'');
return;
}
break;
case FLOAT:
cptr += sprintf(cptr, "%g", *((float *)pc)++);
return;
case DOUBLE:
cptr += sprintf(cptr, "%g", *((double *)pc)++);
return;
case FLOAT12:
sput("0x");
putf("%08x", *((long *)pc)++);
putf("%08x", *((long *)pc)++);
putf("%08x", *((long *)pc)++);
return;
default:
illegal = TRUE;
return;
}
putoffset(i, sym != 0);
}
/* parse an effective address into the following syntax:
* The name of a register, or
* register@(register.s*scale+base){@(register.s*scale+offset)} or
* (label+register.s*scale+base){@(register.s*scale+offset)} or
* label{@(register.s*scale+offset)}
*/
void
source(unsigned short inst)
{
short unsigned i = 0;
int baseregister = 0; /* 0 = no register, else low bits are reg number */
int indexregister = 0;
long int base = 0; /* if no base register, figure out label from this! */
long int postoffset = 0;
flag memindirect = 0;
flag postindex = 0;
void *rpc = 0; /* pointer to potential relocation */
flag pcrel = 0; /* true if address is naturally relocated */
flag lparen;
switch ((inst >> 3) & 7)
{
case 1:
if (targettype == UCHAR)
illegal = TRUE;
case 0:
printregister(inst & 15);
return;
case 2:
printregister((inst & 7) + 8);
cput('@');
return;
case 3:
printregister(inst & 15);
cput('@');
cput('+');
return;
case 4:
cput('-');
printregister((inst & 7) + 8);
cput('@');
return;
case 5:
baseregister = (inst & 0xf);
rpc = pc;
base = *((signed short *)pc)++;
break;
case 6:
baseregister = (inst & 0x7) | 8; /* a0-a7 */
indirect:
i = *((short unsigned *)pc)++;
indexregister = ((i >> 12) & 15) | 16;
if (!(i & 0x100))
{
rpc = pc - 1;
base += (signed char)i;
} else {
if (i & 0x80)
{
baseregister = 0;
base = 0;
pcrel = 0;
}
if (i & 0x40)
indexregister = 0;
switch (i & 0x30)
{
case 0x00:
illegal = TRUE;
case 0x10: /* base+=0; */
break;
case 0x20:
rpc = pc;
base += *((signed short *)pc)++;
break;
case 0x30:
rpc = pc;
base += *((long *)pc)++;
break;
}
if (i & 4)
postindex = TRUE;
memindirect = TRUE;
switch (i & 3)
{
case 0:
memindirect = FALSE;
break;
case 1:
postoffset = 0;
break;
/* should check for relocation, but we don't: */
case 2:
postoffset = *((signed short *)pc)++;
break;
case 3:
postoffset = *((long *)pc)++;
break;
}
}
break;
case 7:
switch (inst & 7)
{
case 0:
rpc = pc;
base = *((signed short *)pc)++;
break;
case 1:
rpc = pc;
base = *((long *)pc)++;
break;
case 2:
pcrel = TRUE;
rpc = pc;
base = (rpc - reloc) + *((signed short *)pc)++;
break;
case 3:
pcrel = TRUE;
base = (pc - reloc);
baseregister = 0;
goto indirect;
case 4:
return (immediate(inst));
default:
illegal = TRUE;
return;
}
break;
}
lparen = 0;
if (baseregister || memindirect)
{
if (baseregister)
{
printregister(baseregister);
cput('@');
}
cput('(');
lparen = TRUE;
sym = 0;
} else
sym = rpc ? getlabel((long unsigned *)&base, rpc, pcrel) : 0;
if (sym)
{
settype(sym, targettype, 0);
putlabel(sym);
}
PMI:
if (indexregister && !postindex)
{
if (sym)
cput('+');
printregister(indexregister);
cput('.');
cput((i & 0x800) ? 'l' : 'w');
switch (i & 0x600)
{
case 0x0000:
break;
case 0x0200:
sput("*2");
break;
case 0x0400:
sput("*4");
break;
case 0x0600:
sput("*8");
break;
}
}
putoffset(base, sym || (indexregister && !postindex));
if (lparen)
cput(')');
if (memindirect)
{
postindex = !postindex;
base = postoffset;
memindirect = FALSE;
sym = 0;
cput('@');
cput('(');
lparen = TRUE;
goto PMI;
}
}
void
data(unsigned short inst)
{ /* a0-a7 illegal */
if ((inst & 0x38) == 8)
illegal = TRUE;
source(inst);
}
void
memory(unsigned short inst)
{ /* a0-a7, d0-d7 illegal */
if ((inst & 0x38) < 0x10)
illegal = TRUE;
source(inst);
}
void
control(unsigned short inst)
{
switch ((inst >> 3) & 7)
{
/* registers, incr/decr, immediate illegal */
case 0: case 1: case 3: case 4:
illegal = TRUE;
break;
case 7:
if ((inst & 7) == 4)
illegal = TRUE;
break;
}
source(inst);
}
void
alterable(unsigned short inst)
{
/* pc relative and imm illegal */
if ((inst & 0x3f) > 0x39)
illegal = TRUE;
source(inst);
}
void
dest(unsigned short inst)
{
/* data && alterable */
if ((inst & 0x3f) > 0x39)
illegal = TRUE;
if ((inst & 0x38) == 8)
illegal = TRUE;
source(inst);
}
void
destmem(unsigned short inst)
{
/* memory && alterable */
if ((inst & 0x38) < 0x10)
illegal = TRUE;
if ((inst & 0x38) > 0x39)
illegal = TRUE;
source(inst);
}
void
bitfield(void)
{
cput('{');
if (inst2 & 0x800)
printregister((inst2 >> 6) & 7);
else
putf("%d", (inst2 >> 6) & 31);
cput(':');
if (inst2 & 0x20)
printregister(inst2 & 7);
else
putf("%d", (inst2 & 31));
cput('}');
}
void
bfdata(unsigned short inst)
{
data(inst);
bitfield();
}
void
bfdest(unsigned short inst)
{
dest(inst);
bitfield();
}
void
bfreg(unsigned short inst)
{
printregister((inst2 >> 12));
}
/* 8,16,32 bit code displacement, as used by bra instruction */
void
disp(unsigned short inst)
{
long n, disp;
signed char c;
short unsigned *rpc;
struct nlist *sym; /* local, because we don't want label comment */
n = pc - reloc; /* where program counter really would be at */
c = (inst & 0xff);
rpc = pc;
/*
* calculate displacement, and advance program counter past displacement.
* what kind of displacement is encoded in low-byte of instruction.
*/
switch (c)
{
case 0xff: /* 32 bit displacement in the next 4 bytes */
disp = *((long unsigned *)pc)++;
break;
case 0: /* 16 bit displacement in the next 2 bytes */
disp = *((signed short *)pc)++;
break;
default: /* 8 bit displacement right in the instruction */
disp = c;
rpc = (unsigned short *)pc - 1; /* I guess pc doesn't need to
be advanced? */
break;
}
n += disp;
sym = getlabel((long unsigned *)&n, rpc, TRUE);
settype(sym, CODE,
(inst & 0xFF00) == 0x6100 ? "F%x" : (disp > 0 ? "L%x" : "LP%x"));
if (sym != NULL)
putlabel(sym);
putoffset(n, sym != NULL);
}
void
dispw(unsigned short inst)
{
disp(0);
}
/* print 2nd word in hex for badly disassembled instructions */
void
word2(unsigned short inst)
{
putf("#0x%x", *((unsigned short *)pc)++);
}
/* >>6 and swap 3-bit halves to get a dest ea in move instruction */
void
dest6(unsigned short inst)
{
inst = ((inst >> 9) & 7) | ((inst >> 3) & 0x38);
alterable(inst);
}
void
sr(unsigned short inst)
{
sput("sr");
}
void
ccr(unsigned short inst)
{
sput("ccr");
}
void
usp(unsigned short inst)
{
sput("usp");
}
void
mask(unsigned short inst)
{
/* movem mask, also check pre-decrement in ea for order */
unsigned short mask;
int i;
flag divider = FALSE;
mask = inst2;
for (i = 0; i < 16; i++)
{
if (mask & 1)
{
if (divider)
cput('/');
divider = TRUE;
printregister(((inst & 0x38) == 0x20) ? 15 - i : i);
}
mask >>= 1;
}
}
void
dreg(unsigned short inst)
{
printregister(inst & 7);
}
void
areg(unsigned short inst)
{
printregister((inst & 7) + 8);
}
void
dreg9(unsigned short inst)
{
printregister((inst >> 9) & 7);
}
void
areg9(unsigned short inst)
{
printregister(((inst >> 9) & 7) + 8);
}
void
aregdisp(unsigned short inst)
{
printregister((inst & 7) + 8);
putf("@(0x%x)", *((signed short *)pc)++);
}
void
aregpd(unsigned short inst)
{
cput('-');
printregister((inst & 7) + 8);
cput('@');
}
void
aregpi(unsigned short inst)
{
printregister((inst & 7) + 8);
cput('@');
cput('+');
}
void
aregpd9(unsigned short inst)
{
cput('-');
printregister(((inst >> 9) & 7) + 8);
cput('@');
}
void
aregpi9(unsigned short inst)
{
printregister(((inst >> 9) & 7) + 8);
cput('@');
cput('+');
}
void
qbits(unsigned short inst)
{
/* number from the addq or subq instructions */
int i = (inst >> 9) & 7;
if (!i)
i = 8;
putf("#%d", i);
}
void
bits4(unsigned short inst)
{
putf("#%d", inst & 15);
} /* trap #n */
void
bits3(unsigned short inst)
{
putf("#%d", inst & 7);
} /* bkpt #n */
void
bits8(unsigned short inst)
{ /* moveq #n */
cput('#');
putoffset((signed char)inst, FALSE);
}
void
mulregs(unsigned short inst)
{ /* print one or two register destination for
* long mul/div */
if (inst2 & 0x400)
{
printregister(inst2 & 7);
cput(':');
}
printregister((inst2 >> 12) & 7);
}
void floatdisp(short unsigned inst);
void fbranch(short unsigned inst);
void floatccw(short unsigned inst);
void floatccl(short unsigned inst);
void floatcc(short unsigned inst);
void floatop(short unsigned inst);
void floatsrc(short unsigned inst);
void floatdest(short unsigned inst);
static struct instruction thetable[] = {
{0x0000, 0x00ff, "or", size, immediate, dest},
{0x003c, 0x0000, "or", size, immediate, ccr},
{0x007c, 0x0000, "or", size, immediate, sr},
{0x00c0, 0x0037, "cmp/chk2", sizebyte, word2, control},
{0x0100, 0x0e3f, "btst", sizebyte, dreg9, data},
{0x0108, 0x0e07, "movep", sizeword, aregdisp, dreg9},
{0x0140, 0x0e3f, "bchg", sizebyte, dreg9, dest},
{0x0148, 0x0e07, "movep", sizelong, aregdisp, dreg9},
{0x0180, 0x0e3f, "bclr", sizebyte, dreg9, dest},
{0x0188, 0x0e07, "movep", sizeword, dreg9, aregdisp},
{0x01c0, 0x0e3f, "bset", sizebyte, dreg9, dest},
{0x01c8, 0x0e07, "movep", sizelong, dreg9, aregdisp},
{0x0200, 0x00ff, "and", size, immediate, dest},
{0x023c, 0x0000, "and", size, immediate, ccr},
{0x027c, 0x0000, "and", size, immediate, sr},
{0x02c0, 0x0037, "cmp/chk2", sizeword, word2, control},
{0x0400, 0x00ff, "sub", size, immediate, dest},
{0x04c0, 0x0037, "cmp/chk2", sizelong, word2, control},
{0x0600, 0x00ff, "add", size, immediate, dest},
{0x06c0, 0x0007, "rtm", branch, dreg, 0},
{0x06c8, 0x0007, "rtm", branch, areg, 0},
{0x06d0, 0x0037, "callm", 0, word2, control},
{0x0800, 0x003f, "btst", sizebyte, immediate, data},
{0x0840, 0x003f, "bchg", sizebyte, immediate, dest},
{0x0880, 0x003f, "bclr", sizebyte, immediate, dest},
{0x08C0, 0x003f, "bset", sizebyte, immediate, dest},
{0x0a00, 0x00ff, "eor", size, immediate, dest},
{0x0ac0, 0x003f, "cas", sizebyte, word2, destmem},
{0x0aff, 0x0000, "cas2", sizebyte, word2, word2},
{0x0c00, 0x00ff, "cmp", size, immediate, dest},
{0x0cc0, 0x003f, "cas", sizeword, word2, destmem},
{0x0cff, 0x0000, "cas2", sizeword, word2, word2},
{0x0e00, 0x00ff, "moves", size, word2, destmem},
{0x0ec0, 0x003f, "cas", sizelong, word2, destmem},
{0x0eff, 0x0000, "cas2", sizelong, word2, word2},
{0x1000, 0x0fff, "move", sizebyte, source, dest6},
{0x2000, 0x0fff, "move", sizelong, source, dest6},
/* {0x2f00,0x003f, "push", sizelong, source, 0}, */
{0x3000, 0x0fff, "move", sizeword, source, dest6},
{0x4000, 0x00ff, "negx", size, dest, 0},
{0x40c0, 0x003f, "move", sizeword, sr, dest},
{0x4100, 0x0e3f, "chk", sizelong, data, dreg9},
{0x4180, 0x0e3f, "chk", sizeword, data, dreg9},
{0x41c0, 0x0e3f, "lea", 0, control, areg9},
{0x4200, 0x00ff, "clr", size, dest, 0},
{0x42c0, 0x003f, "move", sizeword, ccr, dest},
{0x4400, 0x00ff, "neg", size, dest, 0},
{0x44c0, 0x003f, "move", sizeword, data, ccr},
{0x4600, 0x00ff, "not", size, dest, 0},
{0x46c0, 0x003f, "move", sizeword, data, sr},
{0x4800, 0x003f, "nbcd", 0 /* byte */ , dest, 0},
{0x4808, 0x0007, "link", sizelong, areg, immediate},
{0x4840, 0x0007, "swap", 0, dreg, 0},
{0x4848, 0x0007, "bkpt", 0, bits3, 0},
{0x4850, 0x003f, "pea", 0, control, 0},
{0x4880, 0x0007, "extw", 0, dreg, 0},
{0x4890, 0x007f, "movem", mmtype, mask, dest},
{0x48c0, 0x0007, "extl", 0, dreg, 0},
{0x49c0, 0x0007, "extbl", 0, dreg, 0},
{0x4a00, 0x00ff, "tst", size, source, 0},
{0x4ac0, 0x003f, "tas", sizebyte, dest, 0},
/* "illegal" is 0x4afc, 0x4afa and 0x4afb also specified as illegal */
{0x4c00, 0x007f, "mul", multype, data, mulregs},
{0x4c40, 0x007f, "div", multype, data, mulregs},
{0x4c80, 0x007f, "movem", mmtype, memory, mask},
{0x4e40, 0x000f, "trap", 0, bits4, 0},
{0x4e50, 0x0007, "link", sizeword, areg, immediate},
{0x4e58, 0x0007, "unlk", 0, areg, 0},
{0x4e60, 0x0007, "movel", 0, areg, usp},
{0x4e68, 0x0007, "movel", 0, usp, areg},
{0x4e70, 0x0000, "reset", 0, 0, 0},
{0x4e71, 0x0000, "nop", 0, 0, 0},
{0x4e72, 0x0000, "stop", 0, word2, 0},
{0x4e73, 0x0000, "rte", branch, 0, 0},
{0x4e74, 0x0000, "rtd", brsizew, immediate, 0},
{0x4e75, 0x0000, "rts", branch, 0, 0},
{0x4e76, 0x0000, "trapv", 0, 0, 0},
{0x4e77, 0x0000, "rtr", branch, 0, 0},
{0x4e7a, 0x0001, "movec", 0, word2, 0},
{0x4e80, 0x003f, "jsr", 0, control, 0},
{0x4ec0, 0x003f, "jmp", branch, control, 0},
{0x5000, 0x0eff, "addq", size, qbits, alterable},
{0x50c0, 0x0f3f, "s", condition, dest, 0},
{0x50c8, 0x0f07, "db", condition, dreg, dispw},
{0x50fa, 0x0f00, "trap", condition, 0, 0},
{0x50fb, 0x0f00, "trap", condition, word2, 0},
{0x50fc, 0x0f00, "trap", condition, word2, word2}, /* long arg */
{0x5100, 0x0eff, "subq", size, qbits, alterable},
{0x51c0, 0x0f3f, "s", condition, dest, 0},
{0x51c8, 0x0f07, "db", condition, dreg, dispw},
{0x6000, 0x00ff, "bra", branch, disp, 0},
{0x6100, 0x00ff, "bsr", 0, disp, 0},
{0x6200, 0x0fff, "b", condition, disp, 0},
{0x7000, 0x0fff, "moveq", 0, bits8, dreg9},
{0x8000, 0x0eff, "or", size, data, dreg9},
{0x80c0, 0x0e3f, "divu", sizeword, data, dreg9},
{0x8100, 0x0e07, "sbcd", 0, dreg, dreg9},
{0x8108, 0x0e07, "sbcd", 0, aregpd, aregpd9},
{0x8110, 0x0eff, "or", size, dreg9, destmem},
{0x8140, 0x0e07, "pack", word2, dreg, dreg9},
{0x8148, 0x0e07, "pack", word2, aregpd, aregpd9},
{0x8180, 0x0e07, "unpk", 0, dreg, dreg9},
{0x8188, 0x0e07, "unpk", 0, aregpd, aregpd9},
{0x81c0, 0x0e3f, "divs", sizeword, data, dreg9},
{0x9000, 0x0eff, "sub", size, source, dreg9},
{0x90c0, 0x0e3f, "sub", sizeword, source, areg9},
{0x9100, 0x0ec7, "subx", size, dreg, dreg9},
{0x9108, 0x0ec7, "subx", size, aregpd, aregpd9},
{0x9110, 0x0eff, "sub", size, dreg9, destmem},
{0x91c0, 0x0e3f, "sub", sizelong, source, areg9},
{0xb000, 0x0eff, "cmp", size, source, dreg9},
{0xb0c0, 0x0e3f, "cmp", sizeword, source, areg9},
{0xb100, 0x0eff, "eor", size, dreg9, dest},
{0xb108, 0x0ec7, "cmp", size, aregpi, aregpi9},
{0xb1c0, 0x0e3f, "cmp", sizelong, source, areg9},
{0xc000, 0x0eff, "and", size, data, dreg9},
{0xc0c0, 0x0e3f, "mulu", sizeword, data, dreg9},
{0xc100, 0x0e07, "abcd", 0, dreg, dreg9},
{0xc108, 0x0e07, "abcd", 0, aregpd, aregpd9},
{0xc110, 0x0eff, "and", size, dreg9, destmem},
{0xc140, 0x0e07, "exg", 0, dreg, dreg9},
{0xc148, 0x0e07, "exg", 0, areg, areg9},
{0xc188, 0x0e07, "exg", 0, areg, dreg9},
{0xc1c0, 0x0e3f, "muls", sizeword, data, dreg9},
{0xd000, 0x0eff, "add", size, source, dreg9},
{0xd0c0, 0x0e3f, "add", sizeword, source, areg9},
{0xd100, 0x0ec7, "addx", size, dreg, dreg9},
{0xd108, 0x0ec7, "addx", size, aregpd, aregpd9},
{0xd110, 0x0eff, "add", size, dreg9, destmem},
{0xd1c0, 0x0e3f, "add", sizelong, source, areg9},
{0xe000, 0x0ec7, "asr", size, qbits, dreg},
{0xe008, 0x0ec7, "lsr", size, qbits, dreg},
{0xe010, 0x0ec7, "roxr", size, qbits, dreg},
{0xe018, 0x0ec7, "ror", size, qbits, dreg},
{0xe020, 0x0ec7, "asr", size, dreg9, dreg},
{0xe028, 0x0ec7, "lsr", size, dreg9, dreg},
{0xe030, 0x0ec7, "roxr", size, dreg9, dreg},
{0xe038, 0x0ec7, "ror", size, dreg9, dreg},
{0xe0c0, 0x003f, "asr", sizeword, destmem, 0},
{0xe100, 0x0ec7, "asl", size, qbits, dreg},
{0xe108, 0x0ec7, "lsl", size, qbits, dreg},
{0xe110, 0x0ec7, "roxl", size, qbits, dreg},
{0xe118, 0x0ec7, "rol", size, qbits, dreg},
{0xe120, 0x0ec7, "asl", size, dreg9, dreg},
{0xe128, 0x0ec7, "lsl", size, dreg9, dreg},
{0xe130, 0x0ec7, "roxl", size, dreg9, dreg},
{0xe138, 0x0ec7, "rol", size, dreg9, dreg},
{0xe1c0, 0x003f, "asl", sizeword, destmem, 0},
{0xe2c0, 0x003f, "lsr", sizeword, destmem, 0},
{0xe3c0, 0x003f, "lsl", sizeword, destmem, 0},
{0xe4c0, 0x003f, "roxr", sizeword, destmem, 0},
{0xe5c0, 0x003f, "roxl", sizeword, destmem, 0},
{0xe6c0, 0x003f, "ror", sizeword, destmem, 0},
{0xe7c0, 0x003f, "rol", sizeword, destmem, 0},
{0xe8c0, 0x003f, "bftst", i2, bfdata, 0},
{0xe9c0, 0x003f, "bfextu", i2, bfdata, bfreg},
{0xeac0, 0x003f, "bfchg", i2, bfdest, 0},
{0xebc0, 0x003f, "bfexts", i2, bfdata, bfreg},
{0xecc0, 0x003f, "bfclr", i2, bfdest, 0},
{0xedc0, 0x003f, "bfffo", i2, bfdata, bfreg},
{0xeec0, 0x003f, "bfset", i2, bfdest, 0},
{0xefc0, 0x003f, "bfins", i2, bfreg, bfdest},
{0xf200, 0x003f, "f", floatop, floatsrc, floatdest},
{0xf240, 0x003f, "fs", floatcc, dest, 0},
{0xf248, 0x0007, "fdb", floatcc, dreg, dispw},
{0xf27a, 0x0000, "ftrap", floatccw, immediate, 0},
{0xf27b, 0x0000, "ftrap", floatccl, immediate, 0},
{0xf27c, 0x0000, "ftrap", floatcc, 0, 0},
{0xf280, 0x007f, "fb", fbranch, floatdisp, 0},
{0xf300, 0x003f, "fsave", 0, destmem, 0},
{0xf340, 0x003f, "frestore", 0, source, 0}
};
/*----- floating point internals -------*/
static parsefunc *fsrc, *fdest;
void
floatsrc(short unsigned inst)
{
(*fsrc) (inst);
}
void
floatdest(short unsigned inst)
{
(*fdest) (inst);
}
void
nodest(short unsigned inst)
{
cptr--;
} /* delete the comma */
void
fp7(short unsigned inst)
{
sput("fp");
cput('0' + ((inst2 >> 7) & 7));
}
void
fp10(short unsigned inst)
{
sput("fp");
cput('0' + ((inst2 >> 10) & 7));
}
void
fextension(short unsigned inst)
{
putf("#0x%x", inst2 & 0x7f);
}
void
fpcr(short unsigned inst)
{
flag divider = FALSE;
if (inst2 & 0x1000)
{
sput("fpcr");
divider = TRUE;
}
if (inst2 & 0x0800)
{
if (divider)
cput('/');
sput("fpsr");
divider = TRUE;
}
if (inst2 & 0x0400)
{
if (divider)
cput('/');
sput("fpiar");
}
}
void
fmask(short unsigned inst)
{
/* movem mask, also check pre-decrement in ea for order */
unsigned short mask;
int i;
flag divider = FALSE;
mask = inst2;
for (i = 0; i < 8; i++)
{
if (mask & 1)
{
if (divider)
cput('/');
divider = TRUE;
sput("fp");
cput('0' + (((inst & 0x38) == 0x20) ? 7 - i : i));
}
mask >>= 1;
}
}
static char *floatops[0x3B] = {
"move", "int", "sinh", "intrz", "sqrt", 0, "lognp1", 0,
"etoxm1", "tanh", "atan", 0, "asin", "atanh", "sin", "tan",
"etox", "twotox", "tentox", 0, "logn", "log10", "log2", 0,
"abs", "cosh", "neg", 0, "acos", "cos", "getexp", "getman",
"div", "mod", "add", "mul", "sgldiv", "rem", "scale", "sglmul",
"sub", 0, 0, 0, 0, 0, 0, 0,
"sincos", "sincos", "sincos", "sincos", "sincos", "sincos", "sincos", "sincos",
"cmp", 0, "tst"
};
void
floatop(short unsigned inst)
{
int i;
inst2 = *((unsigned short *)pc)++;
switch ((inst2 >> 13) & 7)
{
case 0:
i = inst2 & 0x7f;
if (i > 0x3A || !floatops[i])
{
illegal = TRUE;
return;
}
sput(floatops[i]);
fsrc = fp10;
fdest = fp7;
break;
case 2:
fdest = fp7;
if ((inst2 & 0x1c00) == 0x1c00)
{
sput("movecr");
fsrc = fextension;
break;
}
fsrc = source;
i = inst2 & 0x7f;
if (i > 0x3A || !floatops[i])
{
illegal = TRUE;
return;
}
sput(floatops[i]);
SIZEIT:
switch ((inst2 >> 10) & 7)
{
case 0:
sizelong(inst);
break;
case 1:
cput('s');
targettype = FLOAT;
break;
case 2:
cput('x');
targettype = FLOAT12;
break;
case 3:
cput('p');
targettype = FLOAT12;
break;
case 4:
sizeword(inst);
break;
case 5:
cput('d');
targettype = DOUBLE;
break;
case 6:
sizebyte(inst);
break;
}
break;
case 3:
sput("move");
fsrc = fp7;
fdest = dest;
goto SIZEIT;
case 4:
sput("movem");
fsrc = source;
fdest = fpcr;
break;
case 5:
sput("movem");
fsrc = fpcr;
fdest = dest;
break;
case 6:
sput("movem");
fsrc = memory;
fdest = fmask;
break;
case 7:
sput("movem");
fsrc = fmask;
fdest = destmem;
break;
}
}
static char *fcond[32] = {
"f", "eq", "ogt", "oge", "olt", "ole", "ogl", "or",
"un", "ueq", "ugt", "uge", "ult", "ule", "ne", "t",
"sf", "seq", "gt", "ge", "lt", "le", "gl", "gle",
"ngle", "ngl", "nle", "nlt", "nge", "ngt", "sne", "st"
};
void
floatcc(short unsigned inst)
{
int i;
i = (*((short unsigned *)pc)++) & 0x3f;
if (i > 31)
illegal = TRUE;
else
sput(fcond[i]);
}
void
floatccw(short unsigned inst)
{
floatcc(inst);
sizeword(inst);
}
void
floatccl(short unsigned inst)
{
floatcc(inst);
sizelong(inst);
}
void
fbranch(short unsigned inst)
{
int i;
i = inst & 0x3f;
if (i > 31)
illegal = TRUE;
else
sput(fcond[i]);
}
void
floatdisp(short unsigned inst)
{
/* displacement is long or short depending on bit 6 */
disp((inst & 0x40) ? -1 : 0);
}
/*==================== The disassembler ======================*/
/* Multiple passes are done by setting newlabels to zero, disasmblock
for each section of the program, and if newlabels is not zero,
doing it again. If newlabels is zero, we are done, turn on printit
and disasmblock again.
Disasmblock cuts up the code at each symbol, and calls a routine
for each of these symbol sections, depending on the type of symbol.
pc points at the start, endpc points at the end of the section.
The routine may quit earlier if it feels the type it is disassembling
is not allowed (in particular it can not move pc at all) but be
very careful in how guesstype is done so all possible states will
eventually be disassembled, it is extremely easy to make a loop!
*/
int newlabels; /* incremented only by labels that require a pass */
extern flag printit; /* set true during printing pass */
flag incode; /* true for text segment to encourage code guessing */
static struct relocation_info *rtab;
static struct relocation_info *lastr;
static struct relocation_info *curr;
static int cursection;
static unsigned curstart; /* used to address relocation entries */
static flag samelineflag; /* true if label small enough to be on same line */
static unsigned nextsymat; /* set by created symbols */
static unsigned mapstart, mapend;
static void
tab()
{ /* tab over to the disassemble column */
if (samelineflag)
samelineflag = FALSE; /* tab after label */
else
startline(pc - reloc);
cprint('\t');
}
/* our own disassembly types: */
#define ZEROBLOCK -1 /* a set of zeros */
#define CASEWTABLE -2 /* a gcc case table, word offsets from start */
/*
* Return pointer to next relocatable thing after pc.
* or endpc if none.
* The table is expected to be in high to low order, and is
* linearlly searched backwards from the last entry found.
* (the reason it is sorted backwards is that gcc produces
* them that way, and it saves some time to not have to
* reverse it)
*/
void *
nextreloc()
{
void *ret;
struct relocation_info *x;
unsigned a = pc - reloc - curstart;
for (x = curr; x >= rtab; x--)
{
if (x->r_address >= a)
{
ret = x->r_address + curstart + reloc;
return (ret < endpc ? ret : endpc);
}
}
return (endpc);
}
extern flag globalscode;
int
guesstype(void)
{
signed char *p;
void *end = nextreloc();
int n = end - pc;
if (!n)
return (ULONG); /* get pointer at start of block */
for (p = (signed char *)pc; !*p++;)
if ((void *)p >= end)
return (ZEROBLOCK);
/* see if it looks like code: */
if (incode && !(((unsigned)pc | (unsigned)end) & 1) && n > 2)
{
if (*(unsigned short *)pc == 0x4e56
&& !(*((unsigned short *)pc + 1) & 3))
return (CODE); /* link a6,n*4 */
if (*(unsigned short *)pc == 0x204f)
return (CODE); /* move sp,a0 */
}
/* see if it looks like a string: */
p = (signed char *)pc;
for (p = (signed char *)pc; p < (signed char *)end; p++)
{
if (*p >= ' ')
{
if ((void *)p - pc >= 8)
return (STRTY);
} else if (*p == '\n' || *p == '\r' || *p == '\t')
;
else if (!*p && (void *)p > pc)
return (STRTY);
else
break;
}
if ((unsigned)pc & 1 || n == 1)
return (UCHAR);
if (incode || n < 4)
return (USHORT);
return (ULONG);
}
void
disasmcode(void)
{
void *savepc;
unsigned short inst;
int i, s, e;
struct nlist *sourcesym;
char buf[256];
if (((unsigned)pc & 1) || nextreloc() == pc)
return;
branched = FALSE;
lastrefsymbol = 0;
while (pc < endpc)
{
savepc = pc;
inst = *((unsigned short *)pc)++;
s = 0;
e = sizeof(thetable) / sizeof(struct instruction);
while (i = (s + e) / 2, i > s)
{
if (thetable[i].code > inst)
e = i;
else
s = i;
}
while ((inst ^ thetable[i].code) & ~thetable[i].mask)
{
i--;
if (i < 0 || (inst & 0xf000) != (thetable[i].code & 0xf000))
{
pc = savepc;
return;
}
}
cptr = buf;
sput(thetable[i].symbol); /* put opcode mnemonic in buffer */
illegal = FALSE;
targettype = 0;
sym = 0;
if (thetable[i].extension)
(thetable[i].extension)(inst);
if (illegal || pc > endpc)
{
pc = savepc;
break;
}
if (thetable[i].source)
{
cput('\t');
(thetable[i].source)(inst);
}
if (illegal || pc > endpc)
{
pc = savepc;
break;
}
sourcesym = sym;
if (thetable[i].dest)
{
cput(',');
(thetable[i].dest)(inst);
}
if (illegal || pc > endpc)
{
pc = savepc;
break;
}
*cptr = 0; /* null terminate the string concocted in the buffer */
if (printit)
{
if (samelineflag)
samelineflag = FALSE; /* tab after label */
else
startline(savepc - reloc);
cprint('\t');
sprint(buf);
printlabelcomment(sourcesym);
}
if (branched)
{
if (lastrefsymbol == NULL)
{
;
/* detect new case tables: */
} else if ((inst & 0xfff0) == 0x4ed0) { /* jmp aN@ */
settype(lastrefsymbol, PTR | CODE, 0);
/* detect older Gnu case tables: */
} else if (inst == 0x4efb && lastrefsymbol->n_desc == SHORT) {
/* jmp pc+x.w, assumme table at pc */
lastrefsymbol->n_desc = CASEWTABLE;
}
break;
}
}
}
/* this is not called unless we already know it is all zeros */
void
disasmzeros(void)
{
if (printit && endpc > pc)
{
tab();
if (endpc == pc + 1 && (((unsigned)pc) & 1))
fprint(".even");
else
fprint(".skip %d", endpc - pc);
}
pc = endpc;
}
/* find more than 1 trailing zero on block, return pointer to it or end */
void *
findtail(int size, void *e)
{
void *p;
if (e <= pc)
return (pc);
for (p = e - 1; !*(char *)p && p >= pc; p--)
; /* find last non-zero byte */
/* point at sized object after it */
p = pc + ((p + size - pc) / size) * size;
if (p > e)
return (p - size);
if (p + size > e)
return (p);
if (p + size + size > e)
return (p + size);
return (p);
}
/* Characters that don't look like strings are strongly discouraged,
* as I only print one and then let it guesstype again. Chiefly this
* eats odd addresses.
*/
void
disasmchar(int type)
{
if (findtail(1, nextreloc()) > pc)
{
tab();
fprint(".byte ");
printoffset(*((signed char *)pc)++, FALSE);
}
}
/* Shorts will continue until the next relocatable (assumed to be long) */
void
disasmshort(int type)
{
void *e;
if (((unsigned)pc) & 1)
return; /* odd address is n.g */
e = nextreloc();
if (((unsigned)e) & 1)
e--;
if (printit)
{
e = findtail(2, e);
while (pc < e)
{
tab();
fprint(".word ");
printoffset(*((signed short *)pc)++, FALSE);
}
}
pc = e;
}
/* Longs will continue until we hit non-multiple of 4:
Pointers are very similar to longs, but checks are made to see
if they are legitimate. In particular they should all relocate.
Even addresses are also insisted on unless pointed to type is CHAR
*/
void
disasmlong(int type)
{
void *e, *f;
unsigned long i;
struct nlist *sym;
if (((unsigned)pc) & 1)
return; /* odd address is n.g */
e = findtail(4, endpc);
while (pc < e)
{
f = nextreloc();
if (f > pc && f < pc + 4)
return;
i = *((unsigned long *)pc);
if ((i & 1)
&& (type & PTR)
&& (type & 15) != CHAR
&& (type & 15) != UCHAR)
return;
sym = getlabel(&i, pc, FALSE);
if (type & PTR)
{
if (!sym)
return;
settype(sym, type & 15, "C%x");
}
if (printit)
{
tab();
fprint(".long ");
if (sym)
printlabel(sym);
printoffset(i, sym != 0);
printlabelcomment(sym);
}
((unsigned long *)pc)++;
}
}
/* Floating numbers go until next relocatable. It would probably be
a good idea to quit on NaN's */
void
disasmfloat(void)
{
void *e;
if (((unsigned)pc) & 1)
return; /* odd address is n.g */
e = nextreloc();
e -= (e - pc) & 3;
if (printit)
{
e = findtail(4, e);
while (pc < e)
{
tab();
fprint(".float %g", *((float *)pc)++);
}
}
pc = e;
}
void
disasmdouble(void)
{
void *e;
if (((unsigned)pc) & 1)
return; /* odd address is n.g */
e = nextreloc();
e -= (e - pc) & 7;
if (printit)
{
e = findtail(8, e);
while (pc < e)
{
tab();
fprint(".double %g", *((double *)pc)++);
}
}
pc = e;
}
/* strings print thru the next null or to a relocatable or symbol:
* this routine prints one line, cutting at \n or 60 characters: */
int
printascii(void *e)
{
signed char c;
if (e - pc > 62)
{
e = pc + 60;
if (*(signed char *)e == 0)
e++;
}
cprint('\"');
while (pc < e)
{
c = *((signed char *)pc)++;
switch (c)
{
case 0:
sprint("\\0\"");
return (0);
case '\t':
sprint("\\t");
break;
case '\n':
sprint("\\n");
if (!*(signed char *)pc)
break;
cprint('\"');
return (TRUE);
case '\r':
sprint("\\r");
break;
case '\\':
sprint("\\\\");
break;
case '\"':
sprint("\\\"");
break;
default:
if (c >= ' ')
cprint(c);
else
fprint("\\%03o", (int)c & 0xff);
break;
}
}
cprint('\"');
return (TRUE);
}
void
disasmstring(void)
{
void *e;
e = nextreloc();
if (printit)
{
while (pc < e && (tab(), sprint(".ascii "), printascii(e)))
;
} else
while (pc < endpc && *((signed char *)pc)++)
;
}
/* Gnu cc produces tables of forward offsets relative to the start
of the table for case statements. This will print them. It
detects the end of the table by either running into some labelled
code, or by an odd address
*/
void
disasmcasewtable(void)
{
long unsigned table, base;
signed short *p;
int i;
struct nlist *tablesym, *sym;
table = pc - reloc;
tablesym = findlabel(table);
if (!tablesym)
return; /* no reference to table! */
i = 0;
while (pc < endpc)
{
base = table + *((signed short *)pc);
if ( /* base<pc-reloc || */ base & 1)
return;
for (p = (signed short *)pc + 1;
(void *)p < endpc && table + *p == base; p++)
;
sym = settype(getlabel(&base, pc, TRUE), CODE, "C%x");
if (printit)
{
tab();
sprint(".word ");
printlabel(sym);
cprint('-');
printlabel(tablesym);
((signed short *)pc)++;
fprint("\t|case %d", i);
i += (p - (signed short *)pc) + 1;
if (pc < (void *)p)
fprint("..%d", i - 1);
while (pc < (void *)p)
{
tab();
sprint(".word ");
printlabel(sym);
cprint('-');
printlabel(tablesym);
((signed short *)pc)++;
}
}
pc = (void *)p;
}
}
void
disasmblock(
struct segment_command *p,
struct section *q,
int sectn, char *bpMap
)
{
struct nlist *n;
int disasmtype;
unsigned a;
unsigned start, end; /* address to start at, address to end at */
extern unsigned symaddress;
/* fill in some globals as appropriate for this section */
curstart = start = q->addr; /* address to start at */
end = q->addr + q->size; /* address to end at */
/* where what address 0 would be, is memory mapped in this addr space */
reloc = (void *)((unsigned)bpMap + p->fileoff - p->vmaddr);
/* sorted array of relocation info for this section */
rtab = (struct relocation_info *)(bpMap + q->reloff);
/* address of last relocation info array entry */
lastr = rtab + q->nreloc;
/* current relocation info entry (sorted in rev order?) */
curr = lastr - 1;
cursection = sectn;
/* first address memory mapped ??? */
mapstart = p->vmaddr;
/* last address memory mapped ??? */
mapend = q->offset ? p->vmaddr + p->vmsize : 0;
if (!printit)
{
if (start < mapstart)
start = mapstart;
if (end > mapend)
end = mapend;
}
n = firstsymbol(start);
pc = reloc + start;
while ((a = pc - reloc) < end)
{
if (nextsymat)
n = firstsymbol(nextsymat);
nextsymat = 0;
disasmtype = 0;
/* handles all the symbols with the same "address". */
while (n && symaddress == a)
{
if (printit)
samelineflag = printsymbol(n);
if (n->n_sect)
{
if (n->n_desc && !(n->n_type & N_STAB))
disasmtype = n->n_desc; /* not a debugging entry */
else if (n->n_type == N_SLINE)
disasmtype = CODE;
else if (incode && globalscode && n->n_type == (N_SECT | 1))
disasmtype = CODE;
}
n = nextsymbol();
}
a = (n && symaddress < end) ? symaddress : end;
if (pc - reloc < mapstart && a > mapstart)
a = mapstart;
if (pc - reloc < mapstart || pc - reloc >= mapend)
{
tab();
fprint(".skip %d", a - (pc - reloc));
pc = reloc + a;
continue;
}
if (a > mapend)
a = mapend;
endpc = reloc + a;
pushsymbol();
if (!disasmtype)
disasmtype = guesstype();
switch (disasmtype)
{
case CASEWTABLE:
disasmcasewtable();
break;
case ZEROBLOCK:
disasmzeros();
break;
case CODE:
disasmcode();
break;
case CHAR:
case UCHAR:
disasmchar(disasmtype);
break;
case SHORT:
case USHORT:
disasmshort(disasmtype);
break;
case FLOAT:
disasmfloat();
break;
case DOUBLE:
disasmdouble();
break;
case STRTY:
disasmstring();
break;
default:
disasmlong(disasmtype);
break;
}
popsymbol();
}
}
/*==================== Label finding/creation ===================*/
/* If something interesting can be said about a label, print it as
* a comment. This version will print any constant strings it points
* at.
*/
void
printlabelcomment(struct nlist * n)
{
void *savepc, *saveendpc;
flag saveincode;
if (!printit || !n || !n->n_sect || n->n_value < mapstart ||
n->n_value >= mapend)
return;
savepc = pc;
saveendpc = endpc;
saveincode = incode;
pc = reloc + n->n_value;
endpc = pc + 100;
incode = TRUE;
if (n->n_desc == STRTY || (!n->n_desc && guesstype() == STRTY))
{
sprint("\t|");
printascii(endpc);
}
pc = savepc;
endpc = saveendpc;
incode = saveincode;
}
struct nlist *
getlabel(unsigned long *address, void *pc, int pcrel)
{
struct nlist *n;
struct relocation_info *r;
unsigned a;
extern struct nlist *sourcesymtab;
extern long unsigned symaddress;
/* first see if there is an entry in the relocation table: */
a = pc - reloc - curstart;
for (r = 0; curr >= rtab; curr--)
{
if (curr->r_address == a)
{
if (pcrel ? curr->r_pcrel : !curr->r_pcrel)
r = curr;
break;
}
if (curr->r_address > a)
break;
}
/* if relocated relative to an external symbol, use that: */
if (r && r->r_extern)
{
/* note that address is relative already */
return (lastrefsymbol = sourcesymtab + r->r_symbolnum);
}
/*
* If there is any relocation table, anything that is not relocated
* must be an absolute value:
*/
if (lastr != rtab)
{
if (!r && !pcrel)
return (0);
} else {
/* Otherwise, we guess that values near zero are absolute: */
if (!pcrel && (*address <= 0x2000
|| *address >= 0x100000
|| (*address & 0xFFF) == 0xFFF
|| (*address & 0xFFF) == 0))
return (0);
}
/* otherwise it is a local label, find it: */
if (n = findlabel(*address))
{
*address = 0; /* modify address to relative value */
return (lastrefsymbol = n);
} else if (symaddress > *address - 4 && (n = findlabel(symaddress))) {
/* fix use of bytes to test parts of long symbols: */
if (n->n_desc == ULONG
|| n->n_desc == LONG ||
(symaddress > *address - 2 &&
(n->n_desc == USHORT || n->n_desc == SHORT)))
{
*address -= symaddress;
return (n);
}
}
/* otherwise make a label. Give it the type needed: */
n = createlabel(*address, r ? r->r_symbolnum : cursection, 0, 0);
if (*address <= pc - reloc)
{
newlabels++; /* increment for earlier code */
} else if (*address < endpc - reloc) {
/* make it be the next symbol */
endpc = reloc + *address;
nextsymat = *address;
}
*address = 0;
return (lastrefsymbol = n);
}
struct nlist *
settype(struct nlist *s, int type, char *name)
{
if (s != NULL)
{
if (s->n_desc == 0)
s->n_desc = type;
if (s->n_un.n_name == NULL)
s->n_un.n_name = name;
}
return s;
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.