#define SPARC_RELOC_13 (127)
#define SPARC_RELOC_22 (126)
#define SPARC_RELOC_NONE (125)
#define cypress 1234
#undef DEBUGINSN
#include <stdio.h>
#include <ctype.h>
#include "as.h"
#include "libc.h"
#include "md.h"
#include "messages.h"
#include "symbols.h"
#include "sections.h"
#include "sparc-opcode.h"
#include <mach-o/sparc/reloc.h>
#define PARAMS(paramlist) paramlist
typedef long offsetT;
const cpu_type_t md_cputype = CPU_TYPE_SPARC;
cpu_subtype_t md_cpusubtype = CPU_SUBTYPE_SPARC_ALL;
const enum byte_sex md_target_byte_sex = BIG_ENDIAN_BYTE_SEX;
const char md_comment_chars[] = ";!";
const char md_line_comment_chars[] = "#";
const char md_EXP_CHARS[] = "eE";
const char md_FLT_CHARS[] = "dDfF";
static void sparc_ip PARAMS ((char *));
static enum sparc_architecture current_architecture = v6;
static int architecture_requested;
static int warn_on_bump;
const relax_typeS md_relax_table[1];
static struct hash_control *op_hash = NULL;
#ifdef NeXT_MOD
static void s_proc PARAMS ((int));
static void s_ignore PARAMS ((int));
extern void s_seg PARAMS ((int));
#else
static void s_data1 PARAMS ((void));
static void s_seg PARAMS ((int));
static void s_proc PARAMS ((int));
static void s_reserve PARAMS ((int));
static void s_common PARAMS ((int));
#endif
const pseudo_typeS md_pseudo_table[] =
{
#ifdef NeXT_MOD
{"global", s_globl, 0},
{"proc", s_proc, 0},
{"empty", s_ignore, 0},
{"ident", s_ignore, 0},
{"optim", s_ignore, 0},
{"skip", s_space, 0},
{"type", s_ignore, 0},
{"word", cons, 4},
{"half", cons, 2},
#else
{"seg", s_seg, 0},
{"align", s_align_bytes, 0},
{"common", s_common, 0},
{"global", s_globl, 0},
{"half", cons, 2},
{"optim", s_ignore, 0},
{"proc", s_proc, 0},
{"reserve", s_reserve, 0},
{"seg", s_seg, 0},
{"skip", s_space, 0},
{"word", cons, 4},
#endif
{NULL, 0, 0},
};
const int md_short_jump_size = 4;
const int md_long_jump_size = 4;
const int md_reloc_size = 12;
const char comment_chars[] = "!";
const char line_comment_chars[] = "#";
const char line_separator_chars[] = "";
const char EXP_CHARS[] = "eE";
const char FLT_CHARS[] = "rRsSfFdDxXpP";
static unsigned char octal[256];
#define isoctal(c) octal[(unsigned char) (c)]
static unsigned char toHex[256];
struct sparc_it
{
char *error;
unsigned long opcode;
struct nlist *nlistp;
expressionS exp;
int pcrel;
char pcrel_reloc;
enum reloc_type_sparc reloc;
};
struct sparc_it the_insn;
#ifdef DEBUGINSN
static void print_insn PARAMS ((struct sparc_it *insn));
#endif
static int getExpression PARAMS ((char *str));
static char *expr_end;
static int special_case_set = 0;
static void
s_proc (ignore)
int ignore;
{
totally_ignore_line();
}
static void
s_ignore (ignore)
int ignore;
{
totally_ignore_line();
}
void
md_begin ()
{
register const char *retval = NULL;
int lose = 0;
register unsigned int i = 0;
op_hash = hash_new ();
while (i < NUMOPCODES)
{
const char *name = sparc_opcodes[i].name;
retval = hash_insert (op_hash, (char *)name, (char *)&sparc_opcodes[i]);
if(retval != NULL && *retval != '\0') {
fprintf (stderr, "internal error: can't hash `%s': %s\n",
sparc_opcodes[i].name, retval);
lose = 1;
} do {
if (sparc_opcodes[i].match & sparc_opcodes[i].lose)
{
fprintf (stderr, "internal error: losing opcode: `%s' \"%s\"\n",
sparc_opcodes[i].name, sparc_opcodes[i].args);
lose = 1;
}
++i;
}
while (i < NUMOPCODES
&& !strcmp (sparc_opcodes[i].name, name));
}
if (lose)
as_fatal ("Broken assembler. No assembly attempted.");
for (i = '0'; i < '8'; ++i)
octal[i] = 1;
for (i = '0'; i <= '9'; ++i)
toHex[i] = i - '0';
for (i = 'a'; i <= 'f'; ++i)
toHex[i] = i + 10 - 'a';
for (i = 'A'; i <= 'F'; ++i)
toHex[i] = i + 10 - 'A';
}
void
md_end(
void)
{
return;
}
void
md_assemble (str)
char *str;
{
char *toP;
int rsd;
know (str);
sparc_ip (str);
#ifdef DEBUGINSN
print_insn(&the_insn);
#endif
if (special_case_set && the_insn.exp.X_seg == SEG_ABSOLUTE)
{
if (the_insn.exp.X_add_number >= -(1 << 12)
&& the_insn.exp.X_add_number < (1 << 12))
{
the_insn.opcode = 0x80102000
| (the_insn.opcode & 0x3E000000)
| (the_insn.exp.X_add_number & 0x1FFF);
special_case_set = 0;
the_insn.reloc = SPARC_RELOC_NONE;
}
}
#ifdef NeXT_MOD
frchain_now->frch_section.flags |= S_ATTR_SOME_INSTRUCTIONS;
#endif
toP = frag_more (4);
md_number_to_chars (toP, (valueT) the_insn.opcode, 4);
if (the_insn.reloc != SPARC_RELOC_NONE)
{
fix_new(frag_now,
(toP - frag_now->fr_literal),
4,
the_insn.exp.X_add_symbol,
the_insn.exp.X_subtract_symbol,
the_insn.exp.X_add_number,
the_insn.pcrel,
the_insn.pcrel_reloc,
the_insn.reloc);
}
if (special_case_set) {
special_case_set = 0;
assert (the_insn.reloc == SPARC_RELOC_HI22);
if ((the_insn.exp.X_seg == SEG_ABSOLUTE) &&
((the_insn.exp.X_add_number & 0x3FF) == 0))
return;
toP = frag_more (4);
rsd = (the_insn.opcode >> 25) & 0x1f;
the_insn.opcode = 0x80102000 | (rsd << 25) | (rsd << 14);
md_number_to_chars (toP, (valueT) the_insn.opcode, 4);
the_insn.pcrel_reloc = 0;
fix_new(frag_now,
(toP - frag_now->fr_literal),
4,
the_insn.exp.X_add_symbol,
the_insn.exp.X_subtract_symbol,
the_insn.exp.X_add_number,
the_insn.pcrel,
the_insn.pcrel_reloc,
SPARC_RELOC_LO10);
return;
}
}
static void
sparc_ip (str)
char *str;
{
char *error_message = "";
char *s;
const char *args;
char c;
struct sparc_opcode *insn;
char *argsStart;
unsigned long opcode;
unsigned int mask = 0;
int match = 0;
int comma = 0;
long immediate_max = 0;
for (s = str; islower (*s) || (*s >= '0' && *s <= '3'); ++s)
;
switch (*s)
{
case '\0':
break;
case ',':
comma = 1;
case ' ':
*s++ = '\0';
break;
default:
as_bad ("Unknown opcode: `%s'", str);
exit (1);
}
if ((insn = (struct sparc_opcode *) hash_find (op_hash, str)) == NULL)
{
as_bad ("Unknown opcode: `%s'", str);
return;
}
if (comma)
{
*--s = ',';
}
argsStart = s;
for (;;)
{
opcode = insn->match;
memset (&the_insn, '\0', sizeof (the_insn));
the_insn.reloc = SPARC_RELOC_NONE;
the_insn.pcrel_reloc = 1;
for (args = insn->args;; ++args)
{
switch (*args)
{
case 'M':
case 'm':
if (strncmp (s, "%asr", 4) == 0)
{
s += 4;
if (isdigit (*s))
{
long num = 0;
while (isdigit (*s))
{
num = num * 10 + *s - '0';
++s;
}
if (num < 16 || 31 < num)
{
error_message = ": asr number must be between 15 and 31";
goto error;
}
opcode |= (*args == 'M' ? RS1 (num) : RD (num));
continue;
}
else
{
error_message = ": expecting %asrN";
goto error;
}
}
break;
case '\0':
if (*s == '\0')
{
match = 1;
}
break;
case '+':
if (*s == '+')
{
++s;
continue;
}
if (*s == '-')
{
continue;
}
break;
case '[':
case ']':
case ',':
case ' ':
if (*s++ == *args)
continue;
break;
case '#':
if (isdigit (*s++))
{
while (isdigit (*s))
{
++s;
}
continue;
}
break;
case 'C':
if (strncmp (s, "%csr", 4) == 0)
{
s += 4;
continue;
}
break;
case 'b':
case 'c':
case 'D':
if (*s++ == '%' && *s++ == 'c' && isdigit (*s))
{
mask = *s++;
if (isdigit (*s))
{
mask = 10 * (mask - '0') + (*s++ - '0');
if (mask >= 32)
{
break;
}
}
else
{
mask -= '0';
}
switch (*args)
{
case 'b':
opcode |= mask << 14;
continue;
case 'c':
opcode |= mask;
continue;
case 'D':
opcode |= mask << 25;
continue;
}
}
break;
case 'r':
case 'u':
case '1':
case '2':
case 'd':
if (*s++ == '%')
{
switch (c = *s++)
{
case 'f':
if (*s++ == 'p')
{
mask = 0x1e;
break;
}
error_message = ": register not fp";
goto error;
case 'g':
if (isoctal (c = *s++))
{
mask = c - '0';
break;
}
error_message = ": invalid global register";
goto error;
case 'i':
if (isoctal (c = *s++))
{
mask = c - '0' + 24;
break;
}
error_message = ": invalid in register";
goto error;
case 'l':
if (isoctal (c = *s++))
{
mask = (c - '0' + 16);
break;
}
error_message = ": invalid local register";
goto error;
case 'o':
if (isoctal (c = *s++))
{
mask = (c - '0' + 8);
break;
}
error_message = ": invalid out register";
goto error;
case 's':
if (*s++ == 'p')
{
mask = 0xe;
break;
}
error_message = ": register is not sp";
goto error;
case 'r':
if (!isdigit (c = *s++))
{
error_message = ": invalid register";
goto error;
}
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if (isdigit (*s))
{
if ((c = 10 * (c - '0') + (*s++ - '0')) >= 32)
{
error_message = ": register # out of range";
goto error;
}
}
else
{
c -= '0';
}
mask = c;
break;
default:
error_message = ": invalid resgiter #";
goto error;
}
switch (*args)
{
case '1':
opcode |= mask << 14;
continue;
case '2':
opcode |= mask;
continue;
case 'd':
opcode |= mask << 25;
continue;
case 'r':
opcode |= (mask << 25) | (mask << 14);
continue;
case 'u':
opcode |= (mask << 25) | mask;
continue;
}
}
break;
case 'e':
case 'v':
case 'V':
case 'f':
case 'B':
case 'R':
case 'g':
case 'H':
case 'J':
{
char format;
if (*s++ == '%'
&& ((format = *s) == 'f')
&& isdigit (*++s))
{
for (mask = 0; isdigit (*s); ++s)
{
mask = 10 * mask + (*s - '0');
}
if ((*args == 'v'
|| *args == 'B'
|| *args == 'H')
&& (mask & 1))
{
break;
}
if ((*args == 'V'
|| *args == 'R'
|| *args == 'J')
&& (mask & 3))
{
break;
}
if (mask >= 32)
{
error_message = ": There are only 32 f registers; [0-31]";
goto error;
}
}
else
{
break;
}
switch (*args)
{
case 'v':
case 'V':
case 'e':
opcode |= RS1 (mask);
continue;
case 'f':
case 'B':
case 'R':
opcode |= RS2 (mask);
continue;
case 'g':
case 'H':
case 'J':
opcode |= RD (mask);
continue;
}
know (0);
break;
}
case 'F':
if (strncmp (s, "%fsr", 4) == 0)
{
s += 4;
continue;
}
break;
case 'h':
the_insn.reloc = SPARC_RELOC_HI22;
goto immediate;
case 'l':
the_insn.reloc = SPARC_RELOC_WDISP22;
the_insn.pcrel = 1;
goto immediate;
case 'L':
the_insn.reloc = SPARC_RELOC_WDISP30;
the_insn.pcrel = 1;
goto immediate;
case 'n':
the_insn.reloc = SPARC_RELOC_22;
goto immediate;
case 'i':
the_insn.reloc = SPARC_RELOC_13;
immediate_max = 0x1FFF;
immediate:
if (*s == ' ')
s++;
if (*s == '%')
{
if ((c = s[1]) == 'h' && s[2] == 'i')
{
the_insn.reloc = SPARC_RELOC_HI22;
s += 3;
}
else if (c == 'l' && s[2] == 'o')
{
the_insn.reloc = SPARC_RELOC_LO10;
s += 3;
}
else
break;
}
{
char *s1;
for (s1 = s; *s1 && *s1 != ',' && *s1 != ']'; s1++);
if (s1 != s && isdigit (s1[-1]))
{
if (s1[-2] == '%' && s1[-3] == '+')
{
s1 -= 3;
*s1 = '\0';
(void) getExpression (s);
*s1 = '+';
s = s1;
continue;
}
else if (strchr ("goli0123456789",
s1[-2]) && s1[-3] == '%' && s1[-4] == '+')
{
s1 -= 4;
*s1 = '\0';
(void) getExpression (s);
*s1 = '+';
s = s1;
continue;
}
}
}
(void) getExpression (s);
s = expr_end;
if (the_insn.exp.X_add_symbol != NULL && !flagseen['L']
&& the_insn.exp.X_add_symbol->sy_nlist.n_un.n_name[0] == 'L') {
the_insn.pcrel_reloc = 0;
}
if ((the_insn.exp.X_seg == SEG_ABSOLUTE ||
the_insn.exp.X_seg == SEG_BIG)
&& the_insn.exp.X_add_symbol == 0)
{
if (immediate_max != 0
&& the_insn.reloc != SPARC_RELOC_LO10
&& the_insn.reloc != SPARC_RELOC_HI22
&& (the_insn.exp.X_add_number > immediate_max
|| the_insn.exp.X_add_number < ~immediate_max))
as_bad ("constant value must be between %ld and %ld",
~immediate_max, immediate_max);
if ((the_insn.reloc == SPARC_RELOC_WDISP22 ||
the_insn.reloc == SPARC_RELOC_WDISP30) &&
the_insn.exp.X_add_number & 3)
as_bad ("displacement is not long aligned");
switch(the_insn.reloc) {
case SPARC_RELOC_13:
if (the_insn.exp.X_seg == SEG_BIG)
opcode |= (*(int *) generic_bignum) & 0x1fff;
else
opcode |= the_insn.exp.X_add_number & 0x1fff;
the_insn.reloc = SPARC_RELOC_NONE;
break;
case SPARC_RELOC_22:
if (the_insn.exp.X_seg == SEG_BIG)
opcode |= (*(int *) generic_bignum) & 0x3fffff;
else
opcode |= the_insn.exp.X_add_number & 0x3fffff;
the_insn.reloc = SPARC_RELOC_NONE;
break;
case SPARC_RELOC_HI22:
opcode |= (the_insn.exp.X_add_number >> 10) & 0x3fffff;
the_insn.reloc = SPARC_RELOC_NONE;
break;
case SPARC_RELOC_LO10:
opcode |= the_insn.exp.X_add_number & 0x3ff;
break;
case SPARC_RELOC_WDISP22:
opcode |= (the_insn.exp.X_add_number >> 2) & 0x3fffff;
break;
case SPARC_RELOC_WDISP30:
opcode |= (the_insn.exp.X_add_number >> 2) & 0x3fffffff;
break;
default:
printf("Unknown reloc entry\n");
}
}
immediate_max = 0;
continue;
case 'a':
if (*s++ == 'a')
{
opcode |= ANNUL;
continue;
}
break;
case 'A':
{
char *push = input_line_pointer;
expressionS e;
input_line_pointer = s;
expression (&e);
if (e.X_seg == SEG_ABSOLUTE)
{
opcode |= e.X_add_number << 5;
s = input_line_pointer;
input_line_pointer = push;
continue;
}
break;
}
case 'p':
if (strncmp (s, "%psr", 4) == 0)
{
s += 4;
continue;
}
break;
case 'q':
if (strncmp (s, "%fq", 3) == 0)
{
s += 3;
continue;
}
break;
case 'Q':
if (strncmp (s, "%cq", 3) == 0)
{
s += 3;
continue;
}
break;
case 'S':
if (strcmp (str, "set") == 0)
{
special_case_set = 1;
continue;
}
break;
case 't':
if (strncmp (s, "%tbr", 4) != 0)
break;
s += 4;
continue;
case 'w':
if (strncmp (s, "%wim", 4) != 0)
break;
s += 4;
continue;
case 'y':
if (strncmp (s, "%y", 2) != 0)
break;
s += 2;
continue;
default:
as_fatal ("failed sanity check.");
}
break;
}
error:
if (match == 0)
{
if (((unsigned) (&insn[1] - sparc_opcodes)) < NUMOPCODES
&& !strcmp (insn->name, insn[1].name))
{
++insn;
s = argsStart;
continue;
}
else
{
as_bad ("Illegal operands%s", error_message);
return;
}
}
else
{
if (insn->architecture > current_architecture)
{
if ((!architecture_requested || warn_on_bump)
&&
1
)
{
if (warn_on_bump)
{
as_warn ("architecture bumped from \"%s\" to \"%s\" on \"%s\"",
architecture_pname[current_architecture],
architecture_pname[insn->architecture],
str);
}
current_architecture = insn->architecture;
}
else
{
as_bad ("architecture mismatch on \"%s\" (\"%s\"). current architecture is \"%s\"",
str,
architecture_pname[insn->architecture],
architecture_pname[current_architecture]);
return;
}
}
}
break;
}
the_insn.opcode = opcode;
}
static int
getExpression (str)
char *str;
{
char *save_in;
segT seg;
save_in = input_line_pointer;
input_line_pointer = str;
seg = expression (&the_insn.exp);
if (seg != SEG_ABSOLUTE
&& seg != SEG_SECT
&& seg != SEG_DIFFSECT
&& seg != SEG_UNKNOWN
&& seg != SEG_NONE
&& seg != SEG_BIG) {
the_insn.error = "bad segment";
expr_end = input_line_pointer;
input_line_pointer = save_in;
return 1;
}
expr_end = input_line_pointer;
input_line_pointer = save_in;
return 0;
}
#define MAX_LITTLENUMS 6
char *
md_atof (type, litP, sizeP)
char type;
char *litP;
int *sizeP;
{
int prec;
LITTLENUM_TYPE words[MAX_LITTLENUMS];
LITTLENUM_TYPE *wordP;
char *t;
char *atof_ieee ();
switch (type)
{
case 'f':
case 'F':
case 's':
case 'S':
prec = 2;
break;
case 'd':
case 'D':
case 'r':
case 'R':
prec = 4;
break;
case 'x':
case 'X':
prec = 6;
break;
case 'p':
case 'P':
prec = 6;
break;
default:
*sizeP = 0;
return "Bad call to MD_ATOF()";
}
t = atof_ieee (input_line_pointer, type, words);
if (t)
input_line_pointer = t;
*sizeP = prec * sizeof (LITTLENUM_TYPE);
for (wordP = words; prec--;)
{
md_number_to_chars (litP, (valueT) (*wordP++), sizeof (LITTLENUM_TYPE));
litP += sizeof (LITTLENUM_TYPE);
}
return "";
}
void
md_number_to_chars (buf, val, n)
char *buf;
long val;
int n;
{
switch(n) {
case 4:
*buf++ = val >> 24;
*buf++ = val >> 16;
case 2:
*buf++ = val >> 8;
case 1:
*buf = val;
break;
default:
abort();
}
}
void
md_number_to_imm(unsigned char *buf, long val, int size, fixS *fixP, int nsect)
{
if ((fixP->fx_r_type == NO_RELOC) ||
(fixP->fx_r_type == SPARC_RELOC_NONE) ||
(fixP->fx_r_type == SPARC_RELOC_VANILLA)) {
switch(size){
case 4:
*buf++ = val >> 24;
*buf++ = val >> 16;
case 2:
*buf++ = val >> 8;
case 1:
*buf = val;
break;
default:
abort();
}
return;
}
switch (fixP->fx_r_type) {
case SPARC_RELOC_WDISP30:
val = (val >> 2) + 1;
buf[0] |= (val >> 24) & 0x3f;
buf[1] = (val >> 16);
buf[2] = val >> 8;
buf[3] = val;
break;
case SPARC_RELOC_WDISP22:
val = (val >> 2) + 1;
buf[1] |= (val >> 16) & 0x3f;
buf[2] = val >> 8;
buf[3] = val;
break;
case SPARC_RELOC_HI22:
buf[1] |= (val >> 26) & 0x3f;
buf[2] = val >> 18;
buf[3] = val >> 10;
break;
case SPARC_RELOC_LO10:
buf[2] |= (val >> 8) & 0x03;
buf[3] = val;
break;
case SPARC_RELOC_22:
if (!fixP->fx_addsy) {
if (val & ~0x003fffff) {
as_bad ("relocation overflow");
}
buf[1] |= (val >> 16) & 0x3f;
buf[2] = val >> 8;
buf[3] = val & 0xff;
} else
as_bad ("Undefined symbolic 22-bit immediate reference: %s",
fixP->fx_addsy->sy_name);
break;
case SPARC_RELOC_13:
if (!fixP->fx_addsy) {
if (((val > 0) && (val & ~(offsetT)0x00001fff))
|| ((val < 0) && (~(val - 1) & ~(offsetT)0x00001fff))) {
as_bad ("relocation overflow");
}
buf[2] |= (val >> 8) & 0x1f;
buf[3] = val;
} else
as_bad ("Undefined symbolic 13-bit immediate reference: %s",
fixP->fx_addsy->sy_name);
break;
case SPARC_RELOC_NONE:
default:
as_bad ("bad or unhandled relocation type: 0x%02x", fixP->fx_r_type);
break;
}
}
int
md_parse_option (argP, cntP, vecP)
char **argP;
int *cntP;
char ***vecP;
{
char *p;
const char **arch;
if (!strcmp (*argP, "bump"))
{
warn_on_bump = 1;
}
else if (**argP == 'A')
{
p = (*argP) + 1;
for (arch = architecture_pname; *arch != NULL; ++arch)
{
if (strcmp (p, *arch) == 0)
{
break;
}
}
if (*arch == NULL)
{
as_bad ("unknown architecture: %s", p);
}
else
{
current_architecture = (enum sparc_architecture) (arch - architecture_pname);
architecture_requested = 1;
}
}
#ifndef NeXT_MOD
#ifdef OBJ_ELF
else if (**argP == 'V')
{
print_version_id ();
}
else if (**argP == 'Q')
{
}
else if (**argP == 's')
{
}
#endif
else if (strcmp (*argP, "sparc") == 0)
{
}
#endif
else
{
(*argP)++;
return 0;
}
**argP = '\0';
return 1;
}
int
md_estimate_size_before_relax(
fragS *fragP,
int segment_type)
{
as_fatal("internal error: Relaxation should never occur");
return(0);
}
void
md_convert_frag(
fragS *fragP)
{
as_fatal("internal error: Relaxation should never occur");
}
#ifdef DEBUGINSN
char *
S_GET_NAME(sym)
symbolS *sym;
{
return (sym->sy_nlist.n_un.n_name);
}
static void
print_insn (insn)
struct sparc_it *insn;
{
const char *const Reloc[] = {
"VANILLA",
"PAIR",
"HI22",
"LO10",
"DISP22",
"PCREL",
"22",
"13",
"SECTDIFF",
"HI22_SECTDIFF",
"LO10_SECTDIFF",
"NONE",
"UNUSED"
};
const char *const InternalReloc[] = {
"13",
"22"
};
if (insn->error)
fprintf (stderr, "ERROR: %s\n", insn->error);
fprintf (stderr, "opcode=0x%08x\n", (unsigned int)insn->opcode);
if (insn->reloc >= 127)
fprintf (stderr, "internal reloc = %s\n", InternalReloc[insn->reloc-127]);
else
fprintf (stderr, "reloc = %s\n", Reloc[insn->reloc]);
fprintf (stderr, "X_add_number = 0x%x\n",
insn->exp.X_add_number);
if (insn->exp.X_add_symbol != NULL)
fprintf(stderr, "Add symbol: %s\n", S_GET_NAME(insn->exp.X_add_symbol));
if (insn->exp.X_subtract_symbol != NULL)
fprintf(stderr, "Subtract symbol: %s\n", S_GET_NAME(insn->exp.X_subtract_symbol));
}
#endif