summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH.J. Lu <hjl.tools@gmail.com>2015-05-08 15:14:49 -0700
committerH.J. Lu <hjl.tools@gmail.com>2015-05-17 07:18:59 -0700
commitd04be5f94460129a60578c76869ff870ac1c7b9e (patch)
treeb3950d854b83ef7f153ffbc060a6d0c358c7b009
parent3e999aa0fa88629279e17bf4f9e2d18ae54540fc (diff)
downloadbinutils-gdb-d04be5f94460129a60578c76869ff870ac1c7b9e.tar.gz
Add pseudo RELAX prefix
Check valid call/jmp instruction after relax prefix
-rw-r--r--gas/config/tc-i386.c78
-rw-r--r--include/opcode/i386.h6
-rw-r--r--opcodes/i386-opc.tbl3
-rw-r--r--opcodes/i386-tbl.h13
4 files changed, 84 insertions, 16 deletions
diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c
index 0a5a6bb27e6..def4ec3bdef 100644
--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -369,6 +369,9 @@ struct _i386_insn
/* Have BND prefix. */
const char *bnd_prefix;
+ /* Have RELAX prefix and RELAX prefix opcode. */
+ unsigned int relax_prefix;
+
/* Need VREX to support upper 16 registers. */
int need_vrex;
@@ -2052,7 +2055,8 @@ enum PREFIX_GROUP
PREFIX_EXIST = 0,
PREFIX_LOCK,
PREFIX_REP,
- PREFIX_OTHER
+ PREFIX_OTHER,
+ PREFIX_NONE
};
/* Returns
@@ -2085,6 +2089,11 @@ add_prefix (unsigned int prefix)
default:
abort ();
+ case PSEUDO_RELAX_PREFIX_OPCODE:
+ i.relax_prefix = RELAX_PREFIX_OPCODE;
+ ret = PREFIX_NONE;
+ break;
+
case CS_PREFIX_OPCODE:
case DS_PREFIX_OPCODE:
case ES_PREFIX_OPCODE:
@@ -2117,15 +2126,18 @@ add_prefix (unsigned int prefix)
q = DATA_PREFIX;
break;
}
- if (i.prefix[q] != 0)
+ if (ret != PREFIX_NONE && i.prefix[q] != 0)
ret = PREFIX_EXIST;
}
if (ret)
{
- if (!i.prefix[q])
- ++i.prefixes;
- i.prefix[q] |= prefix;
+ if (ret != PREFIX_NONE)
+ {
+ if (!i.prefix[q])
+ ++i.prefixes;
+ i.prefix[q] |= prefix;
+ }
}
else
as_bad (_("same type of prefix used twice"));
@@ -2792,6 +2804,7 @@ static bfd_reloc_code_real_type
reloc (unsigned int size,
int pcrel,
int sign,
+ int relax_prefix,
bfd_reloc_code_real_type other)
{
if (other != NO_RELOC)
@@ -2870,7 +2883,11 @@ reloc (unsigned int size,
{
case 1: return BFD_RELOC_8_PCREL;
case 2: return BFD_RELOC_16_PCREL;
- case 4: return BFD_RELOC_32_PCREL;
+ case 4: return (relax_prefix
+ ? (object_64bit
+ ? BFD_RELOC_X86_64_RELAX_PC32
+ : BFD_RELOC_386_RELAX_PC32)
+ : BFD_RELOC_32_PCREL);
case 8: return BFD_RELOC_64_PCREL;
}
as_bad (_("cannot do %u byte pc-relative relocation"), size);
@@ -3543,6 +3560,12 @@ md_assemble (char *line)
if (i.bnd_prefix && !i.tm.opcode_modifier.bndprefixok)
as_bad (_("expecting valid branch instruction after `bnd'"));
+ /* Check RELAX prefix. */
+ if (i.relax_prefix
+ && i.tm.base_opcode != 0xe8
+ && i.tm.base_opcode != 0xeb)
+ as_bad (_("expecting valid call/jmp instruction after `relax'"));
+
if (i.tm.cpu_flags.bitfield.cpumpx
&& flag_code == CODE_64BIT
&& i.prefix[ADDR_PREFIX])
@@ -6696,6 +6719,10 @@ output_branch (void)
i.prefixes -= 1;
}
+ /* Place RELAX prefix after BND prefix. */
+ if (i.relax_prefix)
+ FRAG_APPEND_1_CHAR (i.relax_prefix);
+
if (i.prefixes != 0 && !intel_syntax)
as_warn (_("skipping prefixes on this instruction"));
@@ -6737,7 +6764,13 @@ output_branch (void)
/* 1 possible extra opcode + 4 byte displacement go in var part.
Pass reloc in fr_var. */
- frag_var (rs_machine_dependent, 5, i.reloc[0], subtype, sym, off, p);
+ frag_var (rs_machine_dependent, 5,
+ ((i.reloc[0] != NO_RELOC || !i.relax_prefix)
+ ? i.reloc[0]
+ : (object_64bit
+ ? BFD_RELOC_X86_64_RELAX_PC32
+ : BFD_RELOC_386_RELAX_PC32)),
+ subtype, sym, off, p);
}
static void
@@ -6797,6 +6830,10 @@ output_jump (void)
i.prefixes -= 1;
}
+ /* Place RELAX prefix after BND prefix. */
+ if (i.relax_prefix)
+ FRAG_APPEND_1_CHAR (i.relax_prefix);
+
if (i.prefixes != 0 && !intel_syntax)
as_warn (_("skipping prefixes on this instruction"));
@@ -6813,7 +6850,9 @@ output_jump (void)
}
fixP = fix_new_exp (frag_now, p - frag_now->fr_literal, size,
- i.op[0].disps, 1, reloc (size, 1, 1, i.reloc[0]));
+ i.op[0].disps, 1, reloc (size, 1, 1,
+ i.relax_prefix,
+ i.reloc[0]));
/* All jumps handled here are signed, but don't use a signed limit
check for 32 and 16 bit jumps as we want to allow wrap around at
@@ -6830,6 +6869,8 @@ output_interseg_jump (void)
int prefix;
int code16;
+ gas_assert (!i.relax_prefix);
+
code16 = 0;
if (flag_code == CODE_16BIT)
code16 = CODE16;
@@ -6879,7 +6920,7 @@ output_interseg_jump (void)
}
else
fix_new_exp (frag_now, p - frag_now->fr_literal, size,
- i.op[1].imms, 0, reloc (size, 0, 0, i.reloc[1]));
+ i.op[1].imms, 0, reloc (size, 0, 0, 0, i.reloc[1]));
if (i.op[0].imms->X_op != O_constant)
as_bad (_("can't handle non absolute segment in `%s'"),
i.tm.name);
@@ -7158,7 +7199,8 @@ output_disp (fragS *insn_start_frag, offsetT insn_start_off)
}
p = frag_more (size);
- reloc_type = reloc (size, pcrel, sign, i.reloc[n]);
+ reloc_type = reloc (size, pcrel, sign, i.relax_prefix,
+ i.reloc[n]);
if (GOT_symbol
&& GOT_symbol == i.op[n].disps->X_add_symbol
&& (((reloc_type == BFD_RELOC_32
@@ -7249,7 +7291,7 @@ output_imm (fragS *insn_start_frag, offsetT insn_start_off)
sign = 0;
p = frag_more (size);
- reloc_type = reloc (size, 0, sign, i.reloc[n]);
+ reloc_type = reloc (size, 0, sign, 0, i.reloc[n]);
/* This is tough to explain. We end up with this one if we
* have operands that look like
@@ -7342,7 +7384,7 @@ void
x86_cons_fix_new (fragS *frag, unsigned int off, unsigned int len,
expressionS *exp, bfd_reloc_code_real_type r)
{
- r = reloc (len, 0, cons_sign, r);
+ r = reloc (len, 0, cons_sign, 0, r);
#ifdef TE_PE
if (exp->X_op == O_secrel)
@@ -8065,7 +8107,7 @@ i386_displacement (char *disp_start, char *disp_end)
{
/* For PC-relative branches, the width of the displacement
is dependent upon data size, not address size. */
- override = (i.prefix[DATA_PREFIX] != 0);
+ override = i.prefix[DATA_PREFIX] != 0 && !i.relax_prefix;
if (flag_code == CODE_64BIT)
{
if (override || i.suffix == WORD_MNEM_SUFFIX)
@@ -9139,7 +9181,9 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
&& (fixP->fx_r_type == BFD_RELOC_32_PCREL
|| fixP->fx_r_type == BFD_RELOC_64_PCREL
|| fixP->fx_r_type == BFD_RELOC_16_PCREL
- || fixP->fx_r_type == BFD_RELOC_8_PCREL)
+ || fixP->fx_r_type == BFD_RELOC_8_PCREL
+ || fixP->fx_r_type == BFD_RELOC_386_RELAX_PC32
+ || fixP->fx_r_type == BFD_RELOC_X86_64_RELAX_PC32)
&& !use_rela_relocations)
{
/* This is a hack. There should be a better way to handle this.
@@ -10417,7 +10461,11 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
break;
case 1: code = BFD_RELOC_8_PCREL; break;
case 2: code = BFD_RELOC_16_PCREL; break;
- case 4: code = BFD_RELOC_32_PCREL; break;
+ case 4:
+ code = ((fixp->fx_r_type == BFD_RELOC_386_RELAX_PC32
+ || fixp->fx_r_type == BFD_RELOC_X86_64_RELAX_PC32)
+ ? fixp-> fx_r_type : BFD_RELOC_32_PCREL);
+ break;
#ifdef BFD64
case 8: code = BFD_RELOC_64_PCREL; break;
#endif
diff --git a/include/opcode/i386.h b/include/opcode/i386.h
index 85d253372ae..ed0a622094f 100644
--- a/include/opcode/i386.h
+++ b/include/opcode/i386.h
@@ -77,9 +77,13 @@
#define XACQUIRE_PREFIX_OPCODE 0xf2
#define XRELEASE_PREFIX_OPCODE 0xf3
#define BND_PREFIX_OPCODE 0xf2
+#define REX64_PREFIX_OPCODE 0x48
+
+#define RELAX_PREFIX_OPCODE ADDR_PREFIX_OPCODE
+#define PSEUDO_RELAX_PREFIX_OPCODE -1
#define TWO_BYTE_OPCODE_ESCAPE 0x0f
-#define NOP_OPCODE (char) 0x90
+#define NOP_OPCODE 0x90
/* register numbers */
#define EAX_REG_NUM 0
diff --git a/opcodes/i386-opc.tbl b/opcodes/i386-opc.tbl
index 56eddbfadc6..f3001cbdab0 100644
--- a/opcodes/i386-opc.tbl
+++ b/opcodes/i386-opc.tbl
@@ -3062,6 +3062,9 @@ stac, 0, 0xf01, 0xcb, 2, CpuSMAP, No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldS
// BND prefix
bnd, 0, 0xf2, None, 1, CpuMPX, No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf|IsPrefix, { 0 }
+// Pseudo RELAX prefix
+relax, 0, -1, None, 1, 0, No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf|IsPrefix, { 0 }
+
// MPX instructions.
bndmk, 2, 0xf30f1b, None, 2, CpuMPX, Modrm|IgnoreSize|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf, { Anysize|BaseIndex|Disp8|Disp32|Disp32S, RegBND }
bndmov, 2, 0x660f1a, None, 2, CpuMPX, Modrm|IgnoreSize|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf|NoAVX, { Xmmword|Unspecified|BaseIndex|Disp8|Disp32|Disp32S|RegBND, RegBND }
diff --git a/opcodes/i386-tbl.h b/opcodes/i386-tbl.h
index 080a4c048dc..8cd0476e63d 100644
--- a/opcodes/i386-tbl.h
+++ b/opcodes/i386-tbl.h
@@ -70242,6 +70242,19 @@ const insn_template i386_optab[] =
{ { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } } },
+ { "relax", 0, -1, None, 1,
+ { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0 } },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
+ 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0 },
+ { { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } } },
{ "bndmk", 2, 0xf30f1b, None, 2,
{ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,