This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
Glitches in gas/objdump handling of i386 STR, SLDT, SMSW instructions
- To: binutils at sources dot redhat dot com
- Subject: Glitches in gas/objdump handling of i386 STR, SLDT, SMSW instructions
- From: Zack Weinberg <zack at codesourcery dot com>
- Date: Sun, 11 Nov 2001 16:19:11 -0800
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 },