This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
VIA PadLock support
- From: Michal Ludvig <mludvig at suse dot cz>
- To: binutils at sources dot redhat dot com
- Date: Thu, 11 Mar 2004 16:08:10 +0100
- Subject: VIA PadLock support
- Organization: SuSE CR, s.r.o.
Hi all,
this patch adds support for (dis)assembling VIA Nehemiah PadLock
instructions. These insns are 3 bytes long and except for 'xstore' must
have a 'rep' prefix. I modified add_prefix() to accept 'xcrypt' insns
both with and without explicitly mentioned 'rep' (although it is always
emitted exacly once without complains).
OK to commit?
Michal Ludvig
--
SUSE Labs mludvig@suse.cz | Cray is the only computer
(+420) 296.545.373 http://www.suse.cz | that runs an endless loop
Personal homepage http://www.logix.cz/michal | in just four hours.
2004-03-11 Michal Ludvig <mludvig@suse.cz>
* gas/config/tc-i386.c (add_prefix): New parameter 'mayfail'.
(output_insn): Handle PadLock instructions.
* gas/config/tc-i386.h (CpuPadLock): New define.
(CpuUnknownFlags): Added CpuPadLock.
* include/opcode/i386.h (i386_optab): Added xstore/xcrypt insns.
* opcodes/i386-dis.c (PADLOCK_SPECIAL, PADLOCK_0): New defines.
(dis386_twobyte): Opcode 0xa7 is PADLOCK_0.
(padlock_table): New struct with PadLock instructions.
(print_insn): Handle PADLOCK_SPECIAL.
Index: gas/config/tc-i386.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-i386.c,v
retrieving revision 1.149
diff -u -p -r1.149 tc-i386.c
--- gas/config/tc-i386.c 22 Nov 2003 02:35:30 -0000 1.149
+++ gas/config/tc-i386.c 11 Mar 2004 12:41:54 -0000
@@ -70,7 +70,7 @@ static INLINE int fits_in_unsigned_long
static INLINE int fits_in_signed_long PARAMS ((offsetT));
static int smallest_imm_type PARAMS ((offsetT));
static offsetT offset_in_range PARAMS ((offsetT, int));
-static int add_prefix PARAMS ((unsigned int));
+static int add_prefix PARAMS ((unsigned int, int));
static void set_code_flag PARAMS ((int));
static void set_16bit_gcc_code_flag PARAMS ((int));
static void set_intel_syntax PARAMS ((int));
@@ -689,8 +689,9 @@ offset_in_range (val, size)
class already exists, 1 if non rep/repne added, 2 if rep/repne
added. */
static int
-add_prefix (prefix)
+add_prefix (prefix, mayfail)
unsigned int prefix;
+ int mayfail;
{
int ret = 1;
int q;
@@ -734,7 +735,7 @@ add_prefix (prefix)
break;
}
- if (i.prefix[q] != 0)
+ if (!mayfail && i.prefix[q] != 0)
{
as_bad (_("same type of prefix used twice"));
return 0;
@@ -1346,7 +1347,7 @@ md_assemble (line)
}
if (i.tm.opcode_modifier & FWait)
- if (!add_prefix (FWAIT_OPCODE))
+ if (!add_prefix (FWAIT_OPCODE, 0))
return;
/* Check string instruction segment overrides. */
@@ -1474,7 +1475,7 @@ md_assemble (line)
}
if (i.rex != 0)
- add_prefix (REX_OPCODE | i.rex);
+ add_prefix (REX_OPCODE | i.rex, 0);
/* We are ready to output the insn. */
output_insn ();
@@ -1543,7 +1544,7 @@ parse_insn (line, mnemonic)
return NULL;
}
/* Add prefix, checking for repeated prefixes. */
- switch (add_prefix (current_templates->start->base_opcode))
+ switch (add_prefix (current_templates->start->base_opcode, 0))
{
case 0:
return NULL;
@@ -1612,13 +1613,13 @@ parse_insn (line, mnemonic)
{
if (l[2] == 't')
{
- if (!add_prefix (DS_PREFIX_OPCODE))
+ if (!add_prefix (DS_PREFIX_OPCODE, 0))
return NULL;
l += 3;
}
else if (l[2] == 'n')
{
- if (!add_prefix (CS_PREFIX_OPCODE))
+ if (!add_prefix (CS_PREFIX_OPCODE, 0))
return NULL;
l += 3;
}
@@ -2270,7 +2271,7 @@ process_suffix ()
if (i.tm.opcode_modifier & JumpByte) /* jcxz, loop */
prefix = ADDR_PREFIX_OPCODE;
- if (!add_prefix (prefix))
+ if (!add_prefix (prefix, 0))
return 0;
}
@@ -2650,7 +2651,7 @@ process_operands ()
always be used. */
if ((i.seg[0]) && (i.seg[0] != default_seg))
{
- if (!add_prefix (i.seg[0]->seg_prefix))
+ if (!add_prefix (i.seg[0]->seg_prefix, 0))
return 0;
}
return 1;
@@ -3123,7 +3124,6 @@ output_interseg_jump ()
md_number_to_chars (p + size, (valueT) i.op[0].imms->X_add_number, 2);
}
-
static void
output_insn ()
{
@@ -3153,8 +3153,13 @@ output_insn ()
/* All opcodes on i386 have either 1 or 2 bytes. We may use third
byte for the SSE instructions to specify a prefix they require. */
- if (i.tm.base_opcode & 0xff0000)
- add_prefix ((i.tm.base_opcode >> 16) & 0xff);
+ if (i.tm.cpu_flags & CpuPadLock) {
+ if (i.tm.base_opcode & 0xff000000)
+ add_prefix ((i.tm.base_opcode >> 24) & 0xff, 1);
+ } else {
+ if (i.tm.base_opcode & 0xff0000)
+ add_prefix ((i.tm.base_opcode >> 16) & 0xff, 0);
+ }
/* The prefix bytes. */
for (q = i.prefix;
@@ -3175,7 +3180,12 @@ output_insn ()
}
else
{
- p = frag_more (2);
+ if (i.tm.cpu_flags & CpuPadLock) {
+ p = frag_more (3);
+ *p++ = (i.tm.base_opcode >> 16) & 0xff;
+ } else
+ p = frag_more (2);
+
/* Put out high byte first: can't use md_number_to_chars! */
*p++ = (i.tm.base_opcode >> 8) & 0xff;
*p = i.tm.base_opcode & 0xff;
Index: gas/config/tc-i386.h
===================================================================
RCS file: /cvs/src/src/gas/config/tc-i386.h,v
retrieving revision 1.45
diff -u -p -r1.45 tc-i386.h
--- gas/config/tc-i386.h 21 Nov 2003 14:38:06 -0000 1.45
+++ gas/config/tc-i386.h 11 Mar 2004 12:41:54 -0000
@@ -194,13 +194,14 @@ typedef struct
#define CpuSSE2 0x2000 /* Streaming SIMD extensions 2 required */
#define Cpu3dnow 0x4000 /* 3dnow! support required */
#define CpuPNI 0x8000 /* Prescott New Instructions required */
+#define CpuPadLock 0x10000 /* VIA PadLock required */
/* These flags are set by gas depending on the flag_code. */
#define Cpu64 0x4000000 /* 64bit support required */
#define CpuNo64 0x8000000 /* Not supported in the 64bit mode */
/* The default value for unknown CPUs - enable all features to avoid problems. */
-#define CpuUnknownFlags (Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuP4|CpuSledgehammer|CpuMMX|CpuSSE|CpuSSE2|CpuPNI|Cpu3dnow|CpuK6|CpuAthlon)
+#define CpuUnknownFlags (Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuP4|CpuSledgehammer|CpuMMX|CpuSSE|CpuSSE2|CpuPNI|Cpu3dnow|CpuK6|CpuAthlon|CpuPadLock)
/* the bits in opcode_modifier are used to generate the final opcode from
the base_opcode. These bits also are used to detect alternate forms of
Index: include/opcode/i386.h
===================================================================
RCS file: /cvs/src/src/include/opcode/i386.h,v
retrieving revision 1.40
diff -u -p -r1.40 i386.h
--- include/opcode/i386.h 23 Jun 2003 20:15:33 -0000 1.40
+++ include/opcode/i386.h 11 Mar 2004 12:41:54 -0000
@@ -1361,6 +1361,13 @@ static const template i386_optab[] = {
{"sysret", 0, 0x0f07, X, CpuK6, lq_Suf|DefaultSize, { 0, 0, 0} },
{"swapgs", 0, 0x0f01, 0xf8, Cpu64, NoSuf|ImmExt, { 0, 0, 0} },
+/* VIA PadLock extensions. */
+{"xstorerng", 0, 0x0fa7c0, X, Cpu686|CpuPadLock, NoSuf|IsString, { 0, 0, 0} },
+{"xcryptecb", 0, 0xf30fa7c8, X, Cpu686|CpuPadLock, NoSuf|IsString, { 0, 0, 0} },
+{"xcryptcbc", 0, 0xf30fa7d0, X, Cpu686|CpuPadLock, NoSuf|IsString, { 0, 0, 0} },
+{"xcryptcfb", 0, 0xf30fa7e0, X, Cpu686|CpuPadLock, NoSuf|IsString, { 0, 0, 0} },
+{"xcryptofb", 0, 0xf30fa7e8, X, Cpu686|CpuPadLock, NoSuf|IsString, { 0, 0, 0} },
+
/* sentinel */
{NULL, 0, 0, 0, 0, 0, { 0, 0, 0} }
};
Index: opcodes/i386-dis.c
===================================================================
RCS file: /cvs/src/src/opcodes/i386-dis.c,v
retrieving revision 1.42
diff -u -p -r1.42 i386-dis.c
--- opcodes/i386-dis.c 18 Jan 2004 23:12:47 -0000 1.42
+++ opcodes/i386-dis.c 11 Mar 2004 12:41:54 -0000
@@ -362,6 +362,7 @@ fetch_data (struct disassemble_info *inf
#define USE_GROUPS 2
#define USE_PREFIX_USER_TABLE 3
#define X86_64_SPECIAL 4
+#define PADLOCK_SPECIAL 5
#define FLOAT NULL, NULL, FLOATCODE, NULL, 0, NULL, 0
@@ -425,6 +426,8 @@ fetch_data (struct disassemble_info *inf
#define X86_64_0 NULL, NULL, X86_64_SPECIAL, NULL, 0, NULL, 0
+#define PADLOCK_0 NULL, NULL, PADLOCK_SPECIAL, NULL, 0, NULL, 0
+
typedef void (*op_rtn) (int bytemode, int sizeflag);
struct dis386 {
@@ -948,7 +951,7 @@ static const struct dis386 dis386_twobyt
{ "shldS", Ev, Gv, Ib },
{ "shldS", Ev, Gv, CL },
{ "(bad)", XX, XX, XX },
- { "(bad)", XX, XX, XX },
+ { PADLOCK_0 },
/* a8 */
{ "pushT", gs, XX, XX },
{ "popT", gs, XX, XX },
@@ -1694,6 +1697,19 @@ static const struct dis386 x86_64_table[
},
};
+static const struct dis386 padlock_table[][8] = {
+ {
+ { "xstorerng", XX, XX, XX },
+ { "xcryptecb", XX, XX, XX },
+ { "xcryptcbc", XX, XX, XX },
+ { "(bad)", XX, XX, XX },
+ { "xcryptcfb", XX, XX, XX },
+ { "xcryptofb", XX, XX, XX },
+ { "(bad)", XX, XX, XX },
+ { "(bad)", XX, XX, XX },
+ },
+};
+
#define INTERNAL_DISASSEMBLER_ERROR _("<internal disassembler error>")
static void
@@ -2190,6 +2206,12 @@ print_insn (bfd_vma pc, disassemble_info
case X86_64_SPECIAL:
dp = &x86_64_table[dp->bytemode2][mode_64bit];
+ break;
+
+ case PADLOCK_SPECIAL:
+ FETCH_DATA (info, codep + 1);
+ index = (*codep++ >> 3) & 0x07;
+ dp = &padlock_table[dp->bytemode2][index];
break;
default: