Glitches in gas/objdump handling of i386 STR, SLDT, SMSW instructions

Zack Weinberg zack@codesourcery.com
Thu Nov 1 09:25:00 GMT 2001


A comment on linux-kernel led me to discover some bugs in gas and
objdump -d handling of the STR and SMSW instructions.

First and most seriously: gas incorrectly thinks STR is invalid except
with a 16-bit operand.  In reality, STR works like most i386
word/long/quad instructions: the operand size prefixes apply.  To
demonstrate this, compile and run this test program:

static unsigned int
strl(void)
{
   unsigned int r;
   asm ("movl %1, %0; str %w0"
	: "=q" (r) : "i" (0x55555555));
   return r;
}

static unsigned int
str(void)
{
   unsigned int r;
   asm ("movl %1, %0; data16 str %w0"
	: "=q" (r) : "i" (0x55555555));
   return r;
}

extern int printf (const char *, ...);

int
main(void)
{
   printf("strl: %.08x\n", strl());
   printf("str:  %.08x\n", str());
   return 0;
}

$ ./a.out
strl: 000002e0
str:  555502e0

Second, matching this, i386-dis.c misinterprets STR instructions:

   0:   66                      data16
   1:   0f 00 cb                str    %bx
   4:   0f 00 cb                str    %bx

That should read

   0:   66 0f 00 cb             str    %bx
   4:   0f 00 cb                str    %ebx

The same bug applies to the SLDT and SMSW instructions, although GAS
gets them right.

I believe this is an appropriate patch.  I've run test files
containing STR, SMSW, and SLDT instructions through the resultant as
and objdump, but I haven't done a full build+test cycle.  Nor have I
checked the rest of the segment instructions thoroughly.

zw

	* include/opcode/i386.h: Change "str" instruction to
	wlq_Suf|Modrm, WordReg|WordMem.
	* opcodes/i386-dis.c: Change "sldt", "str", and "smsw" entries
	to "sldtQ", "strQ", "smswQ" respectively; all with Ev operand
	category instead of Ew.

===================================================================
Index: include/opcode/i386.h
--- include/opcode/i386.h	2001/05/12 09:52:39	1.33
+++ include/opcode/i386.h	2001/11/12 00:11:42
@@ -555,7 +555,7 @@ static const template i386_optab[] = {
 {"sidt",   1, 0x0f01, 1, Cpu286, wlq_Suf|Modrm,		{ WordMem, 0, 0} },
 {"sldt",   1, 0x0f00, 0, Cpu286, wlq_Suf|Modrm,		{ WordReg|WordMem, 0, 0} },
 {"smsw",   1, 0x0f01, 4, Cpu286, wlq_Suf|Modrm,		{ WordReg|WordMem, 0, 0} },
-{"str",	   1, 0x0f00, 1, Cpu286, w_Suf|Modrm|IgnoreSize,{ Reg16|ShortMem, 0, 0} },
+{"str",	   1, 0x0f00, 1, Cpu286, wlq_Suf|Modrm,		{ WordReg|WordMem, 0, 0} },
 
 {"verr",   1, 0x0f00, 4, Cpu286, w_Suf|Modrm|IgnoreSize,{ Reg16|ShortMem, 0, 0} },
 {"verw",   1, 0x0f00, 5, Cpu286, w_Suf|Modrm|IgnoreSize,{ Reg16|ShortMem, 0, 0} },
===================================================================
Index: opcodes/i386-dis.c
--- opcodes/i386-dis.c	2001/09/04 01:58:07	1.31
+++ opcodes/i386-dis.c	2001/11/12 00:11:43
@@ -1337,8 +1337,8 @@ static const struct dis386 grps[][8] = {
   },
   /* GRP6 */
   {
-    { "sldt",	Ew, XX, XX },
-    { "str",	Ew, XX, XX },
+    { "sldtQ",	Ev, XX, XX },
+    { "strQ",	Ev, XX, XX },
     { "lldt",	Ew, XX, XX },
     { "ltr",	Ew, XX, XX },
     { "verr",	Ew, XX, XX },
@@ -1352,7 +1352,7 @@ static const struct dis386 grps[][8] = {
     { "sidtQ",	 M, XX, XX },
     { "lgdtQ",	 M, XX, XX },
     { "lidtQ",	 M, XX, XX },
-    { "smsw",	Ew, XX, XX },
+    { "smswQ",	Ev, XX, XX },
     { "(bad)",	XX, XX, XX },
     { "lmsw",	Ew, XX, XX },
     { "invlpg",	Ew, XX, XX },



More information about the Binutils mailing list