mirror of
https://frontier.innolan.net/github/amigaos-cross-toolchain6.git
synced 2024-10-19 10:29:55 +00:00
758 lines
24 KiB
Diff
758 lines
24 KiB
Diff
--- binutils-2.9.1/gas/config/tc-m68k.c 1998-05-01 17:44:43.000000000 +0200
|
|
+++ binutils-2.9.1/gas/config/tc-m68k.c 2012-08-04 12:43:35.000000000 +0200
|
|
@@ -27,6 +27,12 @@
|
|
#include "opcode/m68k.h"
|
|
#include "m68k-parse.h"
|
|
|
|
+/* FIXME: delete this #define as soon as the code that references
|
|
+ N_TEXT is changed */
|
|
+#ifdef BFD_ASSEMBLER
|
|
+#define N_TEXT 4
|
|
+#endif
|
|
+
|
|
/* This string holds the chars that always start a comment. If the
|
|
pre-processor is disabled, these aren't very useful. The macro
|
|
tc_comment_chars points to this. We use this, rather than the
|
|
@@ -70,6 +76,7 @@
|
|
|
|
static int flag_short_refs; /* -l option */
|
|
static int flag_long_jumps; /* -S option */
|
|
+static int flag_small_code; /* -sc option */
|
|
|
|
#ifdef REGISTER_PREFIX_OPTIONAL
|
|
int flag_reg_prefix_optional = REGISTER_PREFIX_OPTIONAL;
|
|
@@ -156,6 +163,9 @@
|
|
/* Mode AINDX (apc-relative) using PC, with variable target, might fit
|
|
in 16 or 8 bits. */
|
|
#define PCINDEX 7
|
|
+/* AmigaOS relocations */
|
|
+#define ABSREL 8
|
|
+#define IMMREL 9
|
|
|
|
struct m68k_incant
|
|
{
|
|
@@ -243,6 +253,7 @@
|
|
so, which. */
|
|
enum pic_relocation pic_reloc;
|
|
#endif
|
|
+ char baserel;
|
|
}
|
|
reloc[5]; /* Five is enough??? */
|
|
};
|
|
@@ -268,7 +279,7 @@
|
|
/* Static functions. */
|
|
|
|
static void insop PARAMS ((int, const struct m68k_incant *));
|
|
-static void add_fix PARAMS ((int, struct m68k_exp *, int, int));
|
|
+static void add_fix PARAMS ((int, struct m68k_exp *, int, int, int));
|
|
static void add_frag PARAMS ((symbolS *, offsetT, int));
|
|
|
|
/* Like addword, but goes BEFORE general operands */
|
|
@@ -291,11 +302,12 @@
|
|
/* The numo+1 kludge is so we can hit the low order byte of the prev word.
|
|
Blecch. */
|
|
static void
|
|
-add_fix (width, exp, pc_rel, pc_fix)
|
|
+add_fix (width, exp, pc_rel, pc_fix, base_rel)
|
|
int width;
|
|
struct m68k_exp *exp;
|
|
int pc_rel;
|
|
int pc_fix;
|
|
+ int base_rel;
|
|
{
|
|
the_ins.reloc[the_ins.nrel].n = ((width == 'B' || width == '3')
|
|
? (the_ins.numo*2-1)
|
|
@@ -308,7 +320,8 @@
|
|
#ifdef OBJ_ELF
|
|
the_ins.reloc[the_ins.nrel].pic_reloc = exp->pic_reloc;
|
|
#endif
|
|
- the_ins.reloc[the_ins.nrel++].pcrel = pc_rel;
|
|
+ the_ins.reloc[the_ins.nrel].pcrel = pc_rel;
|
|
+ the_ins.reloc[the_ins.nrel++].baserel = base_rel;
|
|
}
|
|
|
|
/* Cause an extra frag to be generated here, inserting up to 10 bytes
|
|
@@ -425,6 +438,15 @@
|
|
/* BCC68000 is for patching in an extra jmp instruction for long offsets
|
|
on the 68000. The 68000 doesn't support long branches with branchs */
|
|
|
|
+/* ABSREL (nice name;-)) is used in small-code, it might be
|
|
+ * implemented base-relative (a4), pc-relative, or base-rel with an extra
|
|
+ * add instruction to add the base-register
|
|
+ *
|
|
+ * IMMREL is the analogous mode for immediate addressing of variables. This
|
|
+ * one can lead into situations, where a replacement is not possible:
|
|
+ * addl #foo,a0
|
|
+ * can't be made pc-relative, if foo is in the text segment */
|
|
+
|
|
/* This table desribes how you change sizes for the various types of variable
|
|
size expressions. This version only supports two kinds. */
|
|
|
|
@@ -479,6 +501,17 @@
|
|
{32765, -32770, 2, TAB (PCINDEX, LONG)},
|
|
{0, 0, 4, 0},
|
|
{1, 1, 0, 0},
|
|
+
|
|
+ {127, -128, 0, 0},
|
|
+ {32767, -32768, 2, TAB(ABSREL,LONG)},
|
|
+ {0, 0, 6, 0},
|
|
+ {1, 1, 0, 0},
|
|
+
|
|
+ {127, -128, 0, 0},
|
|
+ {32767, -32768, 2, TAB(IMMREL,LONG)},
|
|
+ {0, 0, 6, 0},
|
|
+ {1, 1, 0, 0},
|
|
+
|
|
};
|
|
|
|
/* These are the machine dependent pseudo-ops. These are included so
|
|
@@ -500,12 +533,14 @@
|
|
{"even", s_even, 0},
|
|
{"skip", s_space, 0},
|
|
{"proc", s_proc, 0},
|
|
+#ifndef __amigaos__
|
|
#if defined (TE_SUN3) || defined (OBJ_ELF)
|
|
{"align", s_align_bytes, 0},
|
|
#endif
|
|
#ifdef OBJ_ELF
|
|
{"swbeg", s_ignore, 0},
|
|
#endif
|
|
+#endif
|
|
{"extend", float_cons, 'x'},
|
|
{"ldouble", float_cons, 'x'},
|
|
|
|
@@ -1820,7 +1855,20 @@
|
|
else
|
|
nextword = get_num (&opP->disp, 0);
|
|
if (isvar (&opP->disp))
|
|
- add_fix (s[1], &opP->disp, 0, 0);
|
|
+ {
|
|
+/* This doesn't work when the symbol is N_UNDF! So we ignore this for the moment.
|
|
+
|
|
+ if (flag_small_code)
|
|
+ {
|
|
+ add_frag (adds(&opP->disp),
|
|
+ offs(&opP->disp),
|
|
+ TAB(IMMREL, SZ_UNDEF));
|
|
+ break;
|
|
+ }
|
|
+ else
|
|
+*/
|
|
+ add_fix(s[1], &opP->disp, 0, 0, opP->disp.baserel);
|
|
+ }
|
|
switch (s[1])
|
|
{
|
|
case 'b':
|
|
@@ -1980,7 +2028,7 @@
|
|
)
|
|
{
|
|
addword (0x0170);
|
|
- add_fix ('l', &opP->disp, 1, 2);
|
|
+ add_fix ('l', &opP->disp, 1, 2, opP->disp.baserel);
|
|
}
|
|
else
|
|
{
|
|
@@ -1993,7 +2041,7 @@
|
|
else
|
|
{
|
|
addword (0x0170);
|
|
- add_fix ('l', &opP->disp, 0, 0);
|
|
+ add_fix ('l', &opP->disp, 0, 0, opP->disp.baserel);
|
|
}
|
|
}
|
|
else
|
|
@@ -2011,10 +2059,10 @@
|
|
{
|
|
if (opP->reg == PC)
|
|
{
|
|
- add_fix ('w', &opP->disp, 1, 0);
|
|
+ add_fix ('w', &opP->disp, 1, 0, opP->disp.baserel);
|
|
}
|
|
else
|
|
- add_fix ('w', &opP->disp, 0, 0);
|
|
+ add_fix ('w', &opP->disp, 0, 0, opP->disp.baserel);
|
|
}
|
|
}
|
|
addword (nextword);
|
|
@@ -2119,9 +2167,9 @@
|
|
fit (possible on m68000) let the
|
|
fixup processing complain later. */
|
|
if (opP->reg == PC)
|
|
- add_fix ('B', &opP->disp, 1, 1);
|
|
+ add_fix ('B', &opP->disp, 1, 1, 0); /* FIXME? -fnf */
|
|
else
|
|
- add_fix ('B', &opP->disp, 0, 0);
|
|
+ add_fix ('B', &opP->disp, 0, 0, 0); /* FIXME? -fnf */
|
|
}
|
|
else if (siz1 != SIZE_BYTE)
|
|
{
|
|
@@ -2251,9 +2299,9 @@
|
|
if (siz1 != SIZE_UNSPEC && isvar (&opP->disp))
|
|
{
|
|
if (opP->reg == PC || opP->reg == ZPC)
|
|
- add_fix (siz1 == SIZE_LONG ? 'l' : 'w', &opP->disp, 1, 2);
|
|
+ add_fix (siz1 == SIZE_LONG ? 'l' : 'w', &opP->disp, 1, 2, opP->disp.baserel);
|
|
else
|
|
- add_fix (siz1 == SIZE_LONG ? 'l' : 'w', &opP->disp, 0, 0);
|
|
+ add_fix (siz1 == SIZE_LONG ? 'l' : 'w', &opP->disp, 0, 0, opP->disp.baserel);
|
|
}
|
|
if (siz1 == SIZE_LONG)
|
|
addword (baseo >> 16);
|
|
@@ -2261,7 +2309,7 @@
|
|
addword (baseo);
|
|
|
|
if (siz2 != SIZE_UNSPEC && isvar (&opP->odisp))
|
|
- add_fix (siz2 == SIZE_LONG ? 'l' : 'w', &opP->odisp, 0, 0);
|
|
+ add_fix (siz2 == SIZE_LONG ? 'l' : 'w', &opP->odisp, 0, 0, opP->disp.baserel);
|
|
if (siz2 == SIZE_LONG)
|
|
addword (outro >> 16);
|
|
if (siz2 != SIZE_UNSPEC)
|
|
@@ -2293,7 +2341,7 @@
|
|
&& opP->disp.pic_reloc == pic_none
|
|
#endif
|
|
&& S_GET_SEGMENT (adds (&opP->disp)) == now_seg
|
|
- && HAVE_LONG_BRANCH(current_architecture)
|
|
+ && (HAVE_LONG_BRANCH(current_architecture) || flag_small_code)
|
|
&& !flag_long_jumps
|
|
&& !strchr ("~%&$?", s[0]))
|
|
{
|
|
@@ -2305,8 +2353,20 @@
|
|
}
|
|
/* Fall through into long */
|
|
case SIZE_LONG:
|
|
+#if 0
|
|
+ /* This doesn't work when the symbol is N_UNDF! We ignore this for now. */
|
|
+
|
|
+ if (flag_small_code)
|
|
+ {
|
|
+ tmpreg=0x3A; /* 7.2 */
|
|
+ add_frag (adds(&opP->disp),
|
|
+ offs(&opP->disp),
|
|
+ TAB(ABSREL, SZ_UNDEF));
|
|
+ break;
|
|
+ }
|
|
+#endif
|
|
if (isvar (&opP->disp))
|
|
- add_fix ('l', &opP->disp, 0, 0);
|
|
+ add_fix ('l', &opP->disp, 0, 0, opP->disp.baserel);
|
|
|
|
tmpreg = 0x39;/* 7.1 mode */
|
|
addword (nextword >> 16);
|
|
@@ -2318,7 +2378,7 @@
|
|
/* Fall through. */
|
|
case SIZE_WORD: /* Word */
|
|
if (isvar (&opP->disp))
|
|
- add_fix ('w', &opP->disp, 0, 0);
|
|
+ add_fix ('w', &opP->disp, 0, 0, opP->disp.baserel);
|
|
|
|
tmpreg = 0x38;/* 7.0 mode */
|
|
addword (nextword);
|
|
@@ -2354,7 +2414,7 @@
|
|
}
|
|
tmpreg = get_num (&opP->disp, tmpreg);
|
|
if (isvar (&opP->disp))
|
|
- add_fix (s[1], &opP->disp, 0, 0);
|
|
+ add_fix (s[1], &opP->disp, 0, 0, opP->disp.baserel);
|
|
switch (s[1])
|
|
{
|
|
case 'b': /* Danger: These do no check for
|
|
@@ -2423,10 +2483,10 @@
|
|
which is a char, and may therefore be unsigned. We
|
|
want to pass -1, but we pass 64 instead, and convert
|
|
back in md_pcrel_from. */
|
|
- add_fix ('B', &opP->disp, 1, 64);
|
|
+ add_fix ('B', &opP->disp, 1, 64, opP->disp.baserel);
|
|
break;
|
|
case 'W':
|
|
- add_fix ('w', &opP->disp, 1, 0);
|
|
+ add_fix ('w', &opP->disp, 1, 0, opP->disp.baserel);
|
|
addword (0);
|
|
break;
|
|
case 'L':
|
|
@@ -2434,7 +2494,7 @@
|
|
if (!HAVE_LONG_BRANCH(current_architecture))
|
|
as_warn ("Can't use long branches on 68000/68010/5200");
|
|
the_ins.opcode[the_ins.numo - 1] |= 0xff;
|
|
- add_fix ('l', &opP->disp, 1, 0);
|
|
+ add_fix ('l', &opP->disp, 1, 0, opP->disp.baserel);
|
|
addword (0);
|
|
addword (0);
|
|
break;
|
|
@@ -2479,19 +2539,19 @@
|
|
break;
|
|
}
|
|
#endif
|
|
- add_fix ('w', &opP->disp, 1, 0);
|
|
+ add_fix ('w', &opP->disp, 1, 0, opP->disp.baserel);
|
|
}
|
|
addword (0);
|
|
break;
|
|
case 'C': /* Fixed size LONG coproc branches */
|
|
- add_fix ('l', &opP->disp, 1, 0);
|
|
+ add_fix ('l', &opP->disp, 1, 0, opP->disp.baserel);
|
|
addword (0);
|
|
addword (0);
|
|
break;
|
|
case 'c': /* Var size Coprocesssor branches */
|
|
if (subs (&opP->disp))
|
|
{
|
|
- add_fix ('l', &opP->disp, 1, 0);
|
|
+ add_fix ('l', &opP->disp, 1, 0, opP->disp.baserel);
|
|
add_frag ((symbolS *) 0, (offsetT) 0, TAB (FBRANCH, LONG));
|
|
}
|
|
else if (adds (&opP->disp))
|
|
@@ -2502,7 +2562,7 @@
|
|
/* add_frag ((symbolS *) 0, offs (&opP->disp),
|
|
TAB(FBRANCH,SHORT)); */
|
|
the_ins.opcode[the_ins.numo - 1] |= 0x40;
|
|
- add_fix ('l', &opP->disp, 1, 0);
|
|
+ add_fix ('l', &opP->disp, 1, 0, opP->disp.baserel);
|
|
addword (0);
|
|
addword (0);
|
|
}
|
|
@@ -2856,7 +2916,7 @@
|
|
break;
|
|
case '_': /* used only for move16 absolute 32-bit address */
|
|
if (isvar (&opP->disp))
|
|
- add_fix ('l', &opP->disp, 0, 0);
|
|
+ add_fix ('l', &opP->disp, 0, 0, opP->disp.baserel);
|
|
tmpreg = get_num (&opP->disp, 80);
|
|
addword (tmpreg >> 16);
|
|
addword (tmpreg & 0xFFFF);
|
|
@@ -3162,8 +3222,8 @@
|
|
{ "a3", ADDR3 },
|
|
{ "a4", ADDR4 },
|
|
{ "a5", ADDR5 },
|
|
+ { "fp", ADDR5 },
|
|
{ "a6", ADDR6 },
|
|
- { "fp", ADDR6 },
|
|
{ "a7", ADDR7 },
|
|
{ "sp", ADDR7 },
|
|
{ "ssp", ADDR7 },
|
|
@@ -3439,7 +3499,8 @@
|
|
&the_ins.reloc[m].exp,
|
|
the_ins.reloc[m].pcrel,
|
|
get_reloc_code (n, the_ins.reloc[m].pcrel,
|
|
- the_ins.reloc[m].pic_reloc));
|
|
+ the_ins.reloc[m].pic_reloc),
|
|
+ the_ins.reloc[m].baserel);
|
|
fixP->fx_pcrel_adjust = the_ins.reloc[m].pcrel_fix;
|
|
if (the_ins.reloc[m].wid == 'B')
|
|
fixP->fx_signed = 1;
|
|
@@ -3486,7 +3547,8 @@
|
|
&the_ins.reloc[m].exp,
|
|
the_ins.reloc[m].pcrel,
|
|
get_reloc_code (wid, the_ins.reloc[m].pcrel,
|
|
- the_ins.reloc[m].pic_reloc));
|
|
+ the_ins.reloc[m].pic_reloc),
|
|
+ the_ins.reloc[m].baserel);
|
|
fixP->fx_pcrel_adjust = the_ins.reloc[m].pcrel_fix;
|
|
}
|
|
(void) frag_var (rs_machine_dependent, 10, 0,
|
|
@@ -3523,7 +3585,8 @@
|
|
&the_ins.reloc[m].exp,
|
|
the_ins.reloc[m].pcrel,
|
|
get_reloc_code (wid, the_ins.reloc[m].pcrel,
|
|
- the_ins.reloc[m].pic_reloc));
|
|
+ the_ins.reloc[m].pic_reloc),
|
|
+ the_ins.reloc[m].baserel);
|
|
fixP->fx_pcrel_adjust = the_ins.reloc[m].pcrel_fix;
|
|
}
|
|
}
|
|
@@ -4146,7 +4209,11 @@
|
|
case TAB (ABRANCH, LONG):
|
|
if (!HAVE_LONG_BRANCH(current_architecture))
|
|
{
|
|
- if (fragP->fr_opcode[0] == 0x61)
|
|
+ if (flag_small_code)
|
|
+ {
|
|
+ as_bad("Long branch in small code model, not supported.");
|
|
+ }
|
|
+ else if (fragP->fr_opcode[0] == 0x61)
|
|
/* BSR */
|
|
{
|
|
fragP->fr_opcode[0] = 0x4E;
|
|
@@ -4158,7 +4225,7 @@
|
|
fragP->fr_symbol,
|
|
fragP->fr_offset,
|
|
0,
|
|
- NO_RELOC);
|
|
+ NO_RELOC, 0);
|
|
|
|
fragP->fr_fix += 4;
|
|
ext = 0;
|
|
@@ -4169,7 +4236,7 @@
|
|
fragP->fr_opcode[0] = 0x4E;
|
|
fragP->fr_opcode[1] = (char) 0xF9; /* JMP with ABSL LONG offset */
|
|
fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol,
|
|
- fragP->fr_offset, 0, NO_RELOC);
|
|
+ fragP->fr_offset, 0, NO_RELOC, 0);
|
|
fragP->fr_fix += 4;
|
|
ext = 0;
|
|
}
|
|
@@ -4197,7 +4264,7 @@
|
|
*buffer_address++ = (char) 0xf9;
|
|
fragP->fr_fix += 2; /* account for jmp instruction */
|
|
fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol,
|
|
- fragP->fr_offset, 0, NO_RELOC);
|
|
+ fragP->fr_offset, 0, NO_RELOC, 0);
|
|
fragP->fr_fix += 4;
|
|
ext = 0;
|
|
break;
|
|
@@ -4214,7 +4281,7 @@
|
|
|
|
fragP->fr_fix += 6; /* account for bra/jmp instructions */
|
|
fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol,
|
|
- fragP->fr_offset, 0, NO_RELOC);
|
|
+ fragP->fr_offset, 0, NO_RELOC, 0);
|
|
fragP->fr_fix += 4;
|
|
ext = 0;
|
|
break;
|
|
@@ -4233,8 +4300,10 @@
|
|
/* The thing to do here is force it to ABSOLUTE LONG, since
|
|
PCREL is really trying to shorten an ABSOLUTE address anyway */
|
|
/* JF FOO This code has not been tested */
|
|
+ if (flag_small_code)
|
|
+ as_bad ("Trying to force a pcrel thing into absolute mode while in small code mode");
|
|
fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol, fragP->fr_offset,
|
|
- 0, NO_RELOC);
|
|
+ 0, NO_RELOC, 0);
|
|
if ((fragP->fr_opcode[1] & 0x3F) != 0x3A)
|
|
as_bad ("Internal error (long PC-relative operand) for insn 0x%04x at 0x%lx",
|
|
(unsigned) fragP->fr_opcode[0],
|
|
@@ -4246,14 +4315,14 @@
|
|
break;
|
|
case TAB (PCLEA, SHORT):
|
|
fix_new (fragP, (int) (fragP->fr_fix), 2, fragP->fr_symbol,
|
|
- fragP->fr_offset, 1, NO_RELOC);
|
|
+ fragP->fr_offset, 1, NO_RELOC, 0);
|
|
fragP->fr_opcode[1] &= ~0x3F;
|
|
fragP->fr_opcode[1] |= 0x3A; /* 072 - mode 7.2 */
|
|
ext = 2;
|
|
break;
|
|
case TAB (PCLEA, LONG):
|
|
fixP = fix_new (fragP, (int) (fragP->fr_fix) + 2, 4, fragP->fr_symbol,
|
|
- fragP->fr_offset, 1, NO_RELOC);
|
|
+ fragP->fr_offset, 1, NO_RELOC, 0);
|
|
fixP->fx_pcrel_adjust = 2;
|
|
/* Already set to mode 7.3; this indicates: PC indirect with
|
|
suppressed index, 32-bit displacement. */
|
|
@@ -4283,7 +4352,7 @@
|
|
buffer_address[-1] = 0x20;
|
|
fixP = fix_new (fragP, (int) (fragP->fr_fix), 2, fragP->fr_symbol,
|
|
fragP->fr_offset, (fragP->fr_opcode[1] & 077) == 073,
|
|
- NO_RELOC);
|
|
+ NO_RELOC, 0);
|
|
fixP->fx_pcrel_adjust = 2;
|
|
ext = 2;
|
|
break;
|
|
@@ -4291,13 +4360,89 @@
|
|
disp += 2;
|
|
fixP = fix_new (fragP, (int) (fragP->fr_fix), 4, fragP->fr_symbol,
|
|
fragP->fr_offset, (fragP->fr_opcode[1] & 077) == 073,
|
|
- NO_RELOC);
|
|
+ NO_RELOC, 0);
|
|
fixP->fx_pcrel_adjust = 2;
|
|
assert (fragP->fr_fix >= 2);
|
|
buffer_address[-2] |= 0x1;
|
|
buffer_address[-1] = 0x30;
|
|
ext = 4;
|
|
break;
|
|
+ case TAB(ABSREL,BYTE):
|
|
+ as_bad ("ABSREL_BYTE: how the ** does this look ?? \n");
|
|
+ break;
|
|
+ case TAB(ABSREL,SHORT):
|
|
+ subseg_change (text_section, 0);
|
|
+ ext = 2;
|
|
+ fragP->fr_opcode[1] &= ~0x3f;
|
|
+ if ((S_GET_TYPE (fragP->fr_symbol)) == N_TEXT)
|
|
+ {
|
|
+ /* so this is really a pc-relative address */
|
|
+ fragP->fr_opcode[1] |= 0x3a;
|
|
+ fix_new(fragP,(int)(fragP->fr_fix),2,fragP->fr_symbol, fragP->fr_offset+2, 1, NO_RELOC, 0);
|
|
+ break;
|
|
+ }
|
|
+ /* in that case we have to generate base-relative code
|
|
+ * (note: if we're in N_UNDF, this could as well be pc-relative, but the linker
|
|
+ * will have to do the final patch in that case) */
|
|
+ fragP->fr_opcode[1] |= 0x2c; /* (a4) */
|
|
+ fix_new(fragP,(int)(fragP->fr_fix),2,fragP->fr_symbol,fragP->fr_offset, 0, NO_RELOC, 1);
|
|
+ break;
|
|
+ case TAB(ABSREL,LONG):
|
|
+ as_bad ("ABSREL_LONG: sorry, not supported.\n");
|
|
+ break;
|
|
+
|
|
+ case TAB(IMMREL,BYTE):
|
|
+ as_bad ("IMMREL_BYTE: how the ** does this look ?? \n");
|
|
+ break;
|
|
+ case TAB(IMMREL,SHORT):
|
|
+ subseg_change (text_section, 0);
|
|
+ ext = 0;
|
|
+ if ((S_GET_TYPE (fragP->fr_symbol)) == N_TEXT)
|
|
+ {
|
|
+ /* we can only fix operations on data registers, not on <ea> */
|
|
+ if ((fragP->fr_opcode[1] & 0x38) != 0)
|
|
+ {
|
|
+ /* use the normal reloc32, sigh... */
|
|
+ fix_new (fragP,(int)(fragP->fr_fix),4,fragP->fr_symbol, fragP->fr_offset, 0, NO_RELOC, 0);
|
|
+ fragP->fr_fix += 4;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ /* so this is really a pc-relative address
|
|
+ * What we have to do now is a VERY UGLY AND BIG KLUDGE. Basically do the
|
|
+ * following thing:
|
|
+ * turn
|
|
+ * addl #foo,d0 (foo is N_TEXT)
|
|
+ * into
|
|
+ * pea foo(pc)
|
|
+ * addl (sp)+,d0
|
|
+ */
|
|
+ *buffer_address++ = fragP->fr_opcode[0]; /* save the original command */
|
|
+ *buffer_address++ = fragP->fr_opcode[1];
|
|
+ fragP->fr_opcode[0] = 0x48; /* PEA */
|
|
+ fragP->fr_opcode[1] = 0x7a;
|
|
+ fix_new(fragP,(int)(fragP->fr_fix),2,fragP->fr_symbol, fragP->fr_offset+2, 1, NO_RELOC, 0);
|
|
+
|
|
+ *buffer_address++ = 0x9f; /* sp@+ */
|
|
+ fragP->fr_fix += 4; /* two byte fix, two byte code extension */
|
|
+ break;
|
|
+ }
|
|
+ /* in that case we have to generate base-relative code
|
|
+ * (note: if we're in N_UNDF, this could as well be pc-relative, but the linker
|
|
+ * will have to do the final patch in that case) */
|
|
+
|
|
+ /* analogous (more or less;-)) to above, the following conversion is done
|
|
+ * turn
|
|
+ * addl #bar,d0 (bar is N_DATA)
|
|
+ * into
|
|
+ * addl #<bar>,d0 where <bar> is a baserel-reloc
|
|
+ * addl a4,d0
|
|
+ */
|
|
+
|
|
+ fix_new(fragP,(int)(fragP->fr_fix), 4,fragP->fr_symbol,fragP->fr_offset, 0, NO_RELOC, 1);
|
|
+ *buffer_address++ = 0xd0;
|
|
+ *buffer_address++ = 0x8c;
|
|
+ break;
|
|
}
|
|
|
|
if (ext)
|
|
@@ -4355,26 +4500,68 @@
|
|
fragP->fr_subtype = TAB (TABTYPE (fragP->fr_subtype), BYTE);
|
|
break;
|
|
}
|
|
- else if ((fragP->fr_symbol == 0) || !HAVE_LONG_BRANCH(current_architecture))
|
|
+ else if ((fragP->fr_symbol == 0) || !HAVE_LONG_BRANCH(current_architecture) || !flag_small_code)
|
|
{
|
|
/* On 68000, or for absolute value, switch to abs long */
|
|
/* FIXME, we should check abs val, pick short or long */
|
|
- if (fragP->fr_opcode[0] == 0x61)
|
|
+ if (fragP->fr_opcode[0] == 0x61)
|
|
{
|
|
- fragP->fr_opcode[0] = 0x4E;
|
|
- fragP->fr_opcode[1] = (char) 0xB9; /* JBSR with ABSL LONG offset */
|
|
- fix_new (fragP, fragP->fr_fix, 4,
|
|
- fragP->fr_symbol, fragP->fr_offset, 0, NO_RELOC);
|
|
- fragP->fr_fix += 4;
|
|
+ if (flag_small_code)
|
|
+ {
|
|
+ /* leave the BSR, no need to change
|
|
+ * it into a JSR (PC,..) */
|
|
+ subseg_change(text_section, 0);
|
|
+ fix_new(fragP, fragP->fr_fix, 2,
|
|
+ fragP->fr_symbol, fragP->fr_offset, 1, NO_RELOC, 0);
|
|
+ fragP->fr_fix+=2;
|
|
+ fragP->fr_opcode[1]=0x00;
|
|
+ }
|
|
+ else if (flag_short_refs)
|
|
+ {
|
|
+ subseg_change(text_section, 0);
|
|
+ fix_new(fragP,(int)(fragP->fr_fix),2,fragP->fr_symbol,
|
|
+ fragP->fr_offset + 2, 0, NO_RELOC, 0);
|
|
+ fragP->fr_fix+=2;
|
|
+ fragP->fr_opcode[1]=0x00;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ fragP->fr_opcode[0] = 0x4E;
|
|
+ fragP->fr_opcode[1] = (char) 0xB9; /* JBSR with ABSL LONG offset */
|
|
+ subseg_change (text_section, 0);
|
|
+ fix_new (fragP, fragP->fr_fix, 4,
|
|
+ fragP->fr_symbol, fragP->fr_offset, 0, NO_RELOC, 0);
|
|
+ fragP->fr_fix += 4;
|
|
+ }
|
|
frag_wane (fragP);
|
|
}
|
|
else if (fragP->fr_opcode[0] == 0x60)
|
|
{
|
|
- fragP->fr_opcode[0] = 0x4E;
|
|
- fragP->fr_opcode[1] = (char) 0xF9; /* JMP with ABSL LONG offset */
|
|
- fix_new (fragP, fragP->fr_fix, 4,
|
|
- fragP->fr_symbol, fragP->fr_offset, 0, NO_RELOC);
|
|
- fragP->fr_fix += 4;
|
|
+ if (flag_small_code)
|
|
+ {
|
|
+ subseg_change(text_section, 0);
|
|
+ fix_new(fragP, fragP->fr_fix, 2,
|
|
+ fragP->fr_symbol, fragP->fr_offset, 1, NO_RELOC, 0);
|
|
+ fragP->fr_fix+=2;
|
|
+ }
|
|
+ else if (flag_short_refs)
|
|
+ {
|
|
+ fragP->fr_opcode[0]= 0x4E;
|
|
+ fragP->fr_opcode[1]= 0xF8; /* JMP with ABSL WORD offset */
|
|
+ subseg_change(text_section, 0);
|
|
+ fix_new(fragP, fragP->fr_fix, 2,
|
|
+ fragP->fr_symbol, fragP->fr_offset, 0, NO_RELOC, 0);
|
|
+ fragP->fr_fix+=2;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ fragP->fr_opcode[0] = 0x4E;
|
|
+ fragP->fr_opcode[1] = (char) 0xF9; /* JMP with ABSL LONG offset */
|
|
+ subseg_change (text_section, 0);
|
|
+ fix_new (fragP, fragP->fr_fix, 4,
|
|
+ fragP->fr_symbol, fragP->fr_offset, 0, NO_RELOC, 0);
|
|
+ fragP->fr_fix += 4;
|
|
+ }
|
|
frag_wane (fragP);
|
|
}
|
|
else
|
|
@@ -4385,7 +4572,7 @@
|
|
else
|
|
{ /* Symbol is still undefined. Make it simple */
|
|
fix_new (fragP, (int) (fragP->fr_fix), 4, fragP->fr_symbol,
|
|
- fragP->fr_offset, 1, NO_RELOC);
|
|
+ fragP->fr_offset, 1, NO_RELOC, 0);
|
|
fragP->fr_fix += 4;
|
|
fragP->fr_opcode[1] = (char) 0xff;
|
|
frag_wane (fragP);
|
|
@@ -4405,7 +4592,7 @@
|
|
else
|
|
{
|
|
fix_new (fragP, (int) fragP->fr_fix, 4, fragP->fr_symbol,
|
|
- fragP->fr_offset, 1, NO_RELOC);
|
|
+ fragP->fr_offset, 1, NO_RELOC, 0);
|
|
fragP->fr_fix += 4;
|
|
fragP->fr_opcode[1] |= 0x40; /* Turn on LONG bit */
|
|
frag_wane (fragP);
|
|
@@ -4450,7 +4637,7 @@
|
|
buffer_address[1] = (char) 0xf8;
|
|
fragP->fr_fix += 2; /* account for jmp instruction */
|
|
fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol,
|
|
- fragP->fr_offset, 0, NO_RELOC);
|
|
+ fragP->fr_offset, 0, NO_RELOC, 0);
|
|
fragP->fr_fix += 2;
|
|
}
|
|
else
|
|
@@ -4461,7 +4648,7 @@
|
|
buffer_address[1] = (char) 0xf9;
|
|
fragP->fr_fix += 2; /* account for jmp instruction */
|
|
fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol,
|
|
- fragP->fr_offset, 0, NO_RELOC);
|
|
+ fragP->fr_offset, 0, NO_RELOC, 0);
|
|
fragP->fr_fix += 4;
|
|
}
|
|
frag_wane (fragP);
|
|
@@ -4491,7 +4678,7 @@
|
|
buffer_address[5] = (char) 0xf8;
|
|
fragP->fr_fix += 6; /* account for bra/jmp instruction */
|
|
fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol,
|
|
- fragP->fr_offset, 0, NO_RELOC);
|
|
+ fragP->fr_offset, 0, NO_RELOC, 0);
|
|
fragP->fr_fix += 2;
|
|
}
|
|
else
|
|
@@ -4502,7 +4689,7 @@
|
|
buffer_address[5] = (char) 0xf9;
|
|
fragP->fr_fix += 6; /* account for bra/jmp instruction */
|
|
fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol,
|
|
- fragP->fr_offset, 0, NO_RELOC);
|
|
+ fragP->fr_offset, 0, NO_RELOC, 0);
|
|
fragP->fr_fix += 4;
|
|
}
|
|
|
|
@@ -4542,6 +4729,16 @@
|
|
}
|
|
break;
|
|
|
|
+ case TAB(ABSREL,SZ_UNDEF):
|
|
+ if ((S_GET_SEGMENT (fragP->fr_symbol)) == segment || flag_short_refs || flag_small_code) {
|
|
+ fragP->fr_subtype = TAB(ABSREL, SHORT);
|
|
+ fragP->fr_var += 2;
|
|
+ } else {
|
|
+ fragP->fr_subtype = TAB(ABSREL, LONG);
|
|
+ fragP->fr_var += 6;
|
|
+ }
|
|
+ break;
|
|
+
|
|
default:
|
|
break;
|
|
}
|
|
@@ -4604,7 +4801,7 @@
|
|
the_bytes[5] = (ri->r_symbolnum >> 8) & 0x0ff;
|
|
the_bytes[6] = ri->r_symbolnum & 0x0ff;
|
|
the_bytes[7] = (((ri->r_pcrel << 7) & 0x80) | ((ri->r_length << 5) & 0x60) |
|
|
- ((ri->r_extern << 4) & 0x10));
|
|
+ ((ri->r_extern << 4) & 0x10) | ((ri->r_baserel << 3) & 0x08));
|
|
}
|
|
|
|
#endif /* comment */
|
|
@@ -4638,7 +4835,7 @@
|
|
where[5] = (r_symbolnum >> 8) & 0x0ff;
|
|
where[6] = r_symbolnum & 0x0ff;
|
|
where[7] = (((fixP->fx_pcrel << 7) & 0x80) | ((nbytes_r_length[fixP->fx_size] << 5) & 0x60) |
|
|
- (((!S_IS_DEFINED (fixP->fx_addsy)) << 4) & 0x10));
|
|
+ (((!S_IS_DEFINED (fixP->fx_addsy)) << 4) & 0x10) | ((fixP->tc_fix_data << 3) & 0x08));
|
|
}
|
|
#endif
|
|
|
|
@@ -4678,7 +4875,7 @@
|
|
md_number_to_chars (ptr, (valueT) 0x4EF9, 2);
|
|
md_number_to_chars (ptr + 2, (valueT) offset, 4);
|
|
fix_new (frag, (ptr + 2) - frag->fr_literal, 4, to_symbol, (offsetT) 0,
|
|
- 0, NO_RELOC);
|
|
+ 0, NO_RELOC, 0);
|
|
}
|
|
else
|
|
{
|
|
@@ -6549,7 +6746,7 @@
|
|
#ifdef OBJ_ELF
|
|
CONST char *md_shortopts = "lSA:m:kQ:V";
|
|
#else
|
|
-CONST char *md_shortopts = "lSA:m:k";
|
|
+CONST char *md_shortopts = "SA:m:s:k";
|
|
#endif
|
|
|
|
struct option md_longopts[] = {
|
|
@@ -6589,6 +6786,13 @@
|
|
flag_long_jumps = 1;
|
|
break;
|
|
|
|
+ case 's':
|
|
+ if (!strcmp(arg, "c") || !strcmp(arg, "mallcode"))
|
|
+ flag_small_code = 1;
|
|
+ else
|
|
+ return 0;
|
|
+ break;
|
|
+
|
|
case 'A':
|
|
if (*arg == 'm')
|
|
arg++;
|
|
@@ -6731,7 +6935,6 @@
|
|
{
|
|
fprintf(stream, "\
|
|
680X0 options:\n\
|
|
--l use 1 word for refs to undefined symbols [default 2]\n\
|
|
-m68000 | -m68008 | -m68010 | -m68020 | -m68030 | -m68040 | -m68060\n\
|
|
| -m68302 | -m68331 | -m68332 | -m68333 | -m68340 | -m68360\n\
|
|
| -mcpu32 | -m5200\n\
|
|
@@ -6745,6 +6948,7 @@
|
|
[default yes for 68020 and up]\n\
|
|
-pic, -k generate position independent code\n\
|
|
-S turn jbsr into jsr\n\
|
|
+-smallcode, -sc small code model\n\
|
|
--register-prefix-optional\n\
|
|
recognize register names without prefix character\n\
|
|
--bitwise-or do not treat `|' as a comment character\n");
|