public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* Re: i386/x86_64 segment register issuses
@ 2005-03-28 10:39 Ross Ridge
  2005-03-28 19:34 ` H. J. Lu
  0 siblings, 1 reply; 10+ messages in thread
From: Ross Ridge @ 2005-03-28 10:39 UTC (permalink / raw)
  To: binutils

> asm volatile("movl %%gs,%0" : "=g" (gsindex));
>
>The new assembler will disallow them since those instructions with
>memory operand will only use the first 16bits. If the memory operand
>is 16bit, you won't see any problems. But if the memory destinatin
>is 32bit, the upper 16bits may have random values.

I'm pretty sure this isn't the case.  The memory operand can only
be 16-bit, as any operand size prefix (or lack thereof) is ignored.
It's only when the destination is a 32-bit register that the upper
16-bits are undefined.

I think gas should accept both "movl" and "movw" when moving between
a segment register and a memory operand.  Regardless of which suffix
is used the assembler should never emit an operand size prefix for
the instruction.

						Ross Ridge

-- 
 l/  //	  Ross Ridge -- The Great HTMU
[oo][oo]  rridge@csclub.uwaterloo.ca
-()-/()/  http://www.csclub.uwaterloo.ca/u/rridge/ 
 db  //	  

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: i386/x86_64 segment register issuses
  2005-03-28 10:39 i386/x86_64 segment register issuses Ross Ridge
@ 2005-03-28 19:34 ` H. J. Lu
  2005-03-28 20:07   ` Ross Ridge
  0 siblings, 1 reply; 10+ messages in thread
From: H. J. Lu @ 2005-03-28 19:34 UTC (permalink / raw)
  To: Ross Ridge; +Cc: binutils

On Sun, Mar 27, 2005 at 06:55:44PM -0500, Ross Ridge wrote:
> > asm volatile("movl %%gs,%0" : "=g" (gsindex));
> >
> >The new assembler will disallow them since those instructions with
> >memory operand will only use the first 16bits. If the memory operand
> >is 16bit, you won't see any problems. But if the memory destinatin
> >is 32bit, the upper 16bits may have random values.
> 
> I'm pretty sure this isn't the case.  The memory operand can only
> be 16-bit, as any operand size prefix (or lack thereof) is ignored.
> It's only when the destination is a 32-bit register that the upper
> 16-bits are undefined.

In x86_64, for register destination, 16bit segment register is zero
extended to 32/64bits. In ia32, CPUs starting from Pentium Pro also
zero extend to 32bits.

> 
> I think gas should accept both "movl" and "movw" when moving between
> a segment register and a memory operand.  Regardless of which suffix
> is used the assembler should never emit an operand size prefix for
> the instruction.

Gas never emits operand size prefix for

	movw	%(eax),%ds

It isn't a problem. These are real codes:

                unsigned fsindex;
                asm volatile("movl %%fs,%0" : "=g" (fsindex));
                if (unlikely(fsindex | next->fsindex | prev->fs)) {
                        loadsegment(fs, next->fsindex);
                        if (fsindex)
                        prev->fs = 0;
                }

The current gas will accept this and. But if fsindex is ever a memory
operand,

                asm volatile("movl %%fs,%0" : "=g" (fsindex));

fsindex will have some random value in the upper 16bits. In fact, gas
will take

                asm volatile("movl %%fs,%0" : "=m" (fsindex));

I don't want gas to accept instructions which don't do what progamers
think they should do.



H.J.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: i386/x86_64 segment register issuses
  2005-03-28 19:34 ` H. J. Lu
@ 2005-03-28 20:07   ` Ross Ridge
  2005-03-29  0:03     ` H. J. Lu
  0 siblings, 1 reply; 10+ messages in thread
From: Ross Ridge @ 2005-03-28 20:07 UTC (permalink / raw)
  To: H. J. Lu; +Cc: Ross Ridge, binutils

> The current gas will accept this and. But if fsindex is ever a memory
> operand,
> 
>                 asm volatile("movl %%fs,%0" : "=g" (fsindex));
> 
> fsindex will have some random value in the upper 16bits.

fsindex will have whatever value it had before in the upper 16-bits.
It's only undefined because of a bug in the Linux kernel, not because
the instruction itself ever produces an undefined result when a memory
operand is used.  This kind of move instruction can never have a 32-bit
memory operand.

							Ross Ridge

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: i386/x86_64 segment register issuses
  2005-03-28 20:07   ` Ross Ridge
@ 2005-03-29  0:03     ` H. J. Lu
  2005-03-29  2:06       ` Ross Ridge
  0 siblings, 1 reply; 10+ messages in thread
From: H. J. Lu @ 2005-03-29  0:03 UTC (permalink / raw)
  To: Ross Ridge; +Cc: binutils

On Mon, Mar 28, 2005 at 01:57:17AM -0500, Ross Ridge wrote:
> > The current gas will accept this and. But if fsindex is ever a memory
> > operand,
> > 
> >                 asm volatile("movl %%fs,%0" : "=g" (fsindex));
> > 
> > fsindex will have some random value in the upper 16bits.
> 
> fsindex will have whatever value it had before in the upper 16-bits.
> It's only undefined because of a bug in the Linux kernel, not because
> the instruction itself ever produces an undefined result when a memory
> operand is used.  This kind of move instruction can never have a 32-bit
> memory operand.

The assembler in CVS generates the same binary code as

	movw %ds,(%eax)

for

	movl %ds,(%eax)

But the previous assemblers will generate

	66 8c 18   movw   %ds,(%eax)

for

	movw %ds,(%eax)

This bug has been fixed for a while. I guess that may be why Linux
kernel uses

	movl %ds,(%eax)

My patch will force

	movw %ds,(%eax)

which will add the unnecessary "0x66" with older assemblers. I guess I
will add a switch to assembler to allow

	movl %ds,(%eax)

and the kernel will check and use it.


H.J.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: i386/x86_64 segment register issuses
  2005-03-29  0:03     ` H. J. Lu
@ 2005-03-29  2:06       ` Ross Ridge
  2005-03-29  3:00         ` H. J. Lu
  0 siblings, 1 reply; 10+ messages in thread
From: Ross Ridge @ 2005-03-29  2:06 UTC (permalink / raw)
  To: H. J. Lu; +Cc: Ross Ridge, binutils

> The assembler in CVS generates the same binary code as
> 
> 	movw %ds,(%eax)
> 
> for
> 
> 	movl %ds,(%eax)

Which is the way I think the GNU assembler should work.  In case like
Linux kernel code you quoted, you really do want a 16-bit move when a
memory destination is used and a 32-bit move when a register destination
used.  The only problem here is that the Linux kernel doesn't ingore
the higher 16-bits of the resulting variable, which aren't guaranteed
to be zero in either case.

							Ross Ridge

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: i386/x86_64 segment register issuses
  2005-03-29  2:06       ` Ross Ridge
@ 2005-03-29  3:00         ` H. J. Lu
  2005-03-30 15:56           ` Ross Ridge
  0 siblings, 1 reply; 10+ messages in thread
From: H. J. Lu @ 2005-03-29  3:00 UTC (permalink / raw)
  To: Ross Ridge; +Cc: binutils

On Mon, Mar 28, 2005 at 02:34:16PM -0500, Ross Ridge wrote:
> > The assembler in CVS generates the same binary code as
> > 
> > 	movw %ds,(%eax)
> > 
> > for
> > 
> > 	movl %ds,(%eax)
> 
> Which is the way I think the GNU assembler should work.  In case like

I'd like to disallow

 	movl %ds,(%eax)

since there is no such an instruction. People can use

 	mov %ds,(%eax)

with old and new assemblers or

 	movw %ds,(%eax)

with the newer assembler.

> Linux kernel code you quoted, you really do want a 16-bit move when a
> memory destination is used and a 32-bit move when a register destination
> used.  The only problem here is that the Linux kernel doesn't ingore
> the higher 16-bits of the resulting variable, which aren't guaranteed
> to be zero in either case.
> 

The higher bits are guaranteed to be zero for x86_64 and Pentium Pro
or above. I am testing Linux kernel patches to make sure that both
old and new assembler will generate optimized binary.


H.J.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: i386/x86_64 segment register issuses
  2005-03-29  3:00         ` H. J. Lu
@ 2005-03-30 15:56           ` Ross Ridge
  2005-03-30 16:26             ` H. J. Lu
  0 siblings, 1 reply; 10+ messages in thread
From: Ross Ridge @ 2005-03-30 15:56 UTC (permalink / raw)
  To: H. J. Lu; +Cc: Ross Ridge, binutils

> The higher bits are guaranteed to be zero for x86_64 and Pentium Pro
> or above.

No, Intel has made no such guarantee for future processors, nor are they
guaranteed to be zero for other existing processors.  

						Ross Ridge

-- 
 l/  //	  Ross Ridge -- The Great HTMU
[oo][oo]  rridge@csclub.uwaterloo.ca
-()-/()/  http://www.csclub.uwaterloo.ca/u/rridge/ 
 db  //	  

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: i386/x86_64 segment register issuses
  2005-03-30 15:56           ` Ross Ridge
@ 2005-03-30 16:26             ` H. J. Lu
  2005-03-30 16:37               ` Ross Ridge
  0 siblings, 1 reply; 10+ messages in thread
From: H. J. Lu @ 2005-03-30 16:26 UTC (permalink / raw)
  To: Ross Ridge; +Cc: binutils

On Tue, Mar 29, 2005 at 04:27:59PM -0500, Ross Ridge wrote:
> > The higher bits are guaranteed to be zero for x86_64 and Pentium Pro
> > or above.
> 
> No, Intel has made no such guarantee for future processors, nor are they
> guaranteed to be zero for other existing processors.  
> 

Given that it is specified for x86_64, it will be very strange that
the future Intel ia32 processors are different from the future Intel
x86_64 processors in this regard. As for non-Intel processors, they
aren't Pentium Pro compatible if they are different.


H.J.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: i386/x86_64 segment register issuses
  2005-03-30 16:26             ` H. J. Lu
@ 2005-03-30 16:37               ` Ross Ridge
  0 siblings, 0 replies; 10+ messages in thread
From: Ross Ridge @ 2005-03-30 16:37 UTC (permalink / raw)
  To: H. J. Lu; +Cc: Ross Ridge, binutils

> Given that it is specified for x86_64, it will be very strange that
> the future Intel ia32 processors are different from the future Intel
> x86_64 processors in this regard.

Regardless of what you might believe to be strange, the guarantee you're
assuming you have does not in fact exist.

> As for non-Intel processors, they aren't Pentium Pro compatible if
>they are different.

Even Intel doesn't claim any of its processors are Pentium Pro compatable.

Like it or not, the fact is that if a register operand is the destination
of a segment register move instruction then the value placed in the
upper 16-bit of registers is architecturally undefined.

						Ross Ridge

-- 
 l/  //	  Ross Ridge -- The Great HTMU
[oo][oo]  rridge@csclub.uwaterloo.ca
-()-/()/  http://www.csclub.uwaterloo.ca/u/rridge/ 
 db  //	  

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: i386/x86_64 segment register issuses
@ 2005-03-31 10:23 Ross Ridge
  0 siblings, 0 replies; 10+ messages in thread
From: Ross Ridge @ 2005-03-31 10:23 UTC (permalink / raw)
  To: binutils, torvalds

>A "movw" has a 0x66 prefix. The assembler agree with me. Plain logic
>agrees with me. Being consistent _also_ agrees with me (it's the same
>damn instruction to move to a register, for chrissake!)

When "mov" instruction has both a memory and segment operand the operand
size prefix has no effect.  There is no 32-bit operand size version of
this instruction to switch to or from.

>"movw" is totally different from "movl". They _act_ the same, but that's 
>like saying that "orw $5,%ax" is the same as "orl $5,%eax". They also 
>_act_ the same, but that IN NO WAY makes them the same.

The "orw" and "orl" examples you give are not architecturally equivilent.
They will set EFLAGS differently based on the value the EAX register had
before.  There can also be significant performance difference between
the two instructions because of partial register accesses the "orw"
instruction performs.  Whether "orw" or "orl" would be faster depends on
the processor used and context it's used in.  However, in the case of a
"mov" instruction that has both a segment register and a memory operand
encoding the instruction the presence or absense of operand size prefix
makes absolutely no difference architecturally.  The memory operand
is always 16-bits and only 16-bits of memory is read or written by the
instruction.  The only effect of using a unnecessary operand prefix is to
make the instruction one byte larger and slower to decode.  Unlike your in
"or" example, adding the unneccessary operand size prefix always loses.

A correctly implemented IA-32 assembler should never generate an operand
size prefix for a move instruction between a segment register and a
memory operand.  Doing so would be as pointless as generating unecessary
DS segment overrides on instructions whose memory operands already assume
the DS segment.

>The fact is, if users use "movl" and "movw" explicitly (and the kernel has
>traditionally been _very_ careful to use all instruction sizes explicitly,
>partly exactly because gas itself has been very happy-go-lucky about
>them) ...

The bugs that currently exist in kernel show that being "careful" about
using instruction sizes explicitly hasn't helped you when accessing
segment registers in inline assembly.  The following code doesn't do
what you thought it does:

	unsigned fsindex;
        asm volatile("movl %%fs,%0" : "=g" (fsindex));

>... then that is a GOOD THING. It means that the instruction is
>well-defined to somebody who knows the x86 instruction set ...

Whoever wrote the above code didn't know the x86 instruction set well
enough.

						Ross Ridge

-- 
 l/  //	  Ross Ridge -- The Great HTMU
[oo][oo]  rridge@csclub.uwaterloo.ca
-()-/()/  http://www.csclub.uwaterloo.ca/u/rridge/ 
 db  //	  

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2005-03-30 21:08 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2005-03-28 10:39 i386/x86_64 segment register issuses Ross Ridge
2005-03-28 19:34 ` H. J. Lu
2005-03-28 20:07   ` Ross Ridge
2005-03-29  0:03     ` H. J. Lu
2005-03-29  2:06       ` Ross Ridge
2005-03-29  3:00         ` H. J. Lu
2005-03-30 15:56           ` Ross Ridge
2005-03-30 16:26             ` H. J. Lu
2005-03-30 16:37               ` Ross Ridge
2005-03-31 10:23 Ross Ridge

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).