public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* PATCH: Fix x86 segment register access
@ 2005-03-26 23:31 H. J. Lu
  2005-03-28 10:21 ` i386/x86_64 segment register issuses (Re: PATCH: Fix x86 segment register access) H. J. Lu
  0 siblings, 1 reply; 12+ messages in thread
From: H. J. Lu @ 2005-03-26 23:31 UTC (permalink / raw)
  To: binutils

X86 segment register access is a special. We can move between a segment
register and a 16/32/64bit general-purpose register. But we can only
move between a segment register and a 16bit memory address. The current
assembler allows "movl (%eax),%ds", but doesn't allow "movq %rax,%ds".
The disassembler display "movl (%eax),%ds". This patch tries to fix
those.


H.J.
----
gas/testsuite/

2005-03-25  H.J. Lu  <hongjiu.lu@intel.com>

	* gas/i386/i386.exp: Run segment and inval-seg for i386. Run
	x86-64-segment and x86-64-inval-seg for x86-64.

	* gas/i386/intel.d: Expect movw for moving between memory and
	segment register.
	* gas/i386/naked.d: Likewise.
	* gas/i386/opcode.d: Likewise.
	* gas/i386/x86-64-opcode.d: Likewise.

	* gas/i386/opcode.s: Use movw for moving between memory and
	segment register.
	* gas/i386/x86-64-opcode.s: Likewise.

	* : Likewise.

	* gas/i386/inval-seg.l: New.
	* gas/i386/inval-seg.s: New.
	* gas/i386/segment.l: New.
	* gas/i386/segment.s: New.
	* gas/i386/x86-64-inval-seg.l: New.
	* gas/i386/x86-64-inval-seg.s: New.
	* gas/i386/x86-64-segment.l: New.
	* gas/i386/x86-64-segment.s: New.

include/opcode/

2005-03-25  H.J. Lu  <hongjiu.lu@intel.com>

	* i386.h (i386_optab): Don't allow the `l' suffix for moving
	moving between memory and segment register. Allow movq for
	moving between general-purpose register and segment register.

opcodes/

2005-03-25  H.J. Lu  <hongjiu.lu@intel.com>

	* i386-dis.c (SEG_Fixup): New.
	(Sv): New.
	(dis386): Use "Sv" for 0x8c and 0x8e.

--- binutils/gas/testsuite/gas/i386/i386.exp.seg	2005-03-02 11:54:52.000000000 -0800
+++ binutils/gas/testsuite/gas/i386/i386.exp	2005-03-25 12:53:28.000000000 -0800
@@ -42,6 +42,8 @@ if [expr ([istarget "i*86-*-*"] ||  [ist
     run_list_test "float" "-al"
     run_list_test "general" "-al --listing-lhs-width=2"
     run_list_test "inval" "-al"
+    run_list_test "segment" "-al"
+    run_list_test "inval-seg" "-al"
     run_list_test "modrm" "-al --listing-lhs-width=2"
     run_dump_test "naked"
     run_dump_test "opcode"
@@ -120,6 +122,8 @@ if [expr ([istarget "i*86-*-*"] || [ista
     run_dump_test "x86-64-opcode"
     run_dump_test "x86-64-rip"
     run_list_test "x86-64-inval" "-al"
+    run_list_test "x86-64-segment" "-al"
+    run_list_test "x86-64-inval-seg" "-al"
 
     # For ELF targets verify that @unwind works.
     if { ([istarget "*-*-elf*"] || [istarget "*-*-linux*"]
--- binutils/gas/testsuite/gas/i386/intel.d.seg	2005-03-17 12:31:19.000000000 -0800
+++ binutils/gas/testsuite/gas/i386/intel.d	2005-03-25 17:42:46.416175591 -0800
@@ -138,9 +138,9 @@ Disassembly of section .text:
  1a3:	89 90 90 90 90 90 [ 	]*mov    %edx,0x90909090\(%eax\)
  1a9:	8a 90 90 90 90 90 [ 	]*mov    0x90909090\(%eax\),%dl
  1af:	8b 90 90 90 90 90 [ 	]*mov    0x90909090\(%eax\),%edx
- 1b5:	8c 90 90 90 90 90 [ 	]*movl   %ss,0x90909090\(%eax\)
+ 1b5:	8c 90 90 90 90 90 [ 	]*movw   %ss,0x90909090\(%eax\)
  1bb:	8d 90 90 90 90 90 [ 	]*lea    0x90909090\(%eax\),%edx
- 1c1:	8e 90 90 90 90 90 [ 	]*movl   0x90909090\(%eax\),%ss
+ 1c1:	8e 90 90 90 90 90 [ 	]*movw   0x90909090\(%eax\),%ss
  1c7:	8f 80 90 90 90 90 [ 	]*popl   0x90909090\(%eax\)
  1cd:	90 [ 	]*nop    
  1ce:	91 [ 	]*xchg   %eax,%ecx
@@ -481,7 +481,7 @@ Disassembly of section .text:
  7be:	66 87 90 90 90 90 90 [ 	]*xchg   %dx,0x90909090\(%eax\)
  7c5:	66 89 90 90 90 90 90 [ 	]*mov    %dx,0x90909090\(%eax\)
  7cc:	66 8b 90 90 90 90 90 [ 	]*mov    0x90909090\(%eax\),%dx
- 7d3:	8c 90 90 90 90 90 [ 	]*mov[l ]   %ss,0x90909090\(%eax\)
+ 7d3:	8c 90 90 90 90 90 [ 	]*mov[w ]   %ss,0x90909090\(%eax\)
  7d9:	66 8d 90 90 90 90 90 [ 	]*lea    0x90909090\(%eax\),%dx
  7e0:	66 8f 80 90 90 90 90 [ 	]*popw   0x90909090\(%eax\)
  7e7:	66 91 [ 	]*xchg   %ax,%cx
--- binutils/gas/testsuite/gas/i386/inval-seg.l.seg	2005-03-25 11:34:16.000000000 -0800
+++ binutils/gas/testsuite/gas/i386/inval-seg.l	2005-03-25 11:58:22.000000000 -0800
@@ -0,0 +1,10 @@
+.*: Assembler messages:
+.*:3: Error: .*
+.*:4: Error: .*
+GAS LISTING .*
+
+
+   1 [ 	]*	.text
+   2 [ 	]*# All the following should be illegal
+   3 [ 	]*	movl	%ds,\(%eax\)
+   4 [ 	]*	movl	\(%eax\),%ds
--- binutils/gas/testsuite/gas/i386/inval-seg.s.seg	2005-03-25 11:34:14.000000000 -0800
+++ binutils/gas/testsuite/gas/i386/inval-seg.s	2005-03-25 11:33:22.000000000 -0800
@@ -0,0 +1,4 @@
+	.text
+# All the following should be illegal
+	movl	%ds,(%eax)
+	movl	(%eax),%ds
--- binutils/gas/testsuite/gas/i386/naked.d.seg	1999-08-31 13:09:58.000000000 -0700
+++ binutils/gas/testsuite/gas/i386/naked.d	2005-03-25 17:40:20.371050512 -0800
@@ -11,8 +11,8 @@ Disassembly of section .text:
    a:	b2 20 [ 	]*mov    \$0x20,%dl
    c:	bb 00 00 00 00 [ 	]*mov    \$0x0,%ebx	d: (R_386_)?(dir)?32	.text
   11:	d9 c9 [ 	]*fxch   %st\(1\)
-  13:	36 8c a4 81 d2 04 00 00 [ 	]*movl   %fs,%ss:0x4d2\(%ecx,%eax,4\)
-  1b:	8c 2c ed 00 00 00 00 [ 	]*movl   %gs,0x0\(,%ebp,8\)
+  13:	36 8c a4 81 d2 04 00 00 [ 	]*movw   %fs,%ss:0x4d2\(%ecx,%eax,4\)
+  1b:	8c 2c ed 00 00 00 00 [ 	]*movw   %gs,0x0\(,%ebp,8\)
   22:	26 88 25 00 00 00 00 [ 	]*mov    %ah,%es:0x0
   29:	2e 8b 74 14 80 [ 	]*mov    %cs:0xffffff80\(%esp,%edx,1\),%esi
   2e:	f3 65 a5 [ 	]*repz movsl %gs:\(%esi\),%es:\(%edi\)
--- binutils/gas/testsuite/gas/i386/opcode.d.seg	2004-11-10 09:20:22.000000000 -0800
+++ binutils/gas/testsuite/gas/i386/opcode.d	2005-03-25 17:41:11.042501717 -0800
@@ -137,9 +137,9 @@ Disassembly of section .text:
  1a3:	89 90 90 90 90 90 [ 	]*mov    %edx,0x90909090\(%eax\)
  1a9:	8a 90 90 90 90 90 [ 	]*mov    0x90909090\(%eax\),%dl
  1af:	8b 90 90 90 90 90 [ 	]*mov    0x90909090\(%eax\),%edx
- 1b5:	8c 90 90 90 90 90 [ 	]*movl   %ss,0x90909090\(%eax\)
+ 1b5:	8c 90 90 90 90 90 [ 	]*movw   %ss,0x90909090\(%eax\)
  1bb:	8d 90 90 90 90 90 [ 	]*lea    0x90909090\(%eax\),%edx
- 1c1:	8e 90 90 90 90 90 [ 	]*movl   0x90909090\(%eax\),%ss
+ 1c1:	8e 90 90 90 90 90 [ 	]*movw   0x90909090\(%eax\),%ss
  1c7:	8f 80 90 90 90 90 [ 	]*popl   0x90909090\(%eax\)
  1cd:	90 [ 	]*nop    
  1ce:	91 [ 	]*xchg   %eax,%ecx
@@ -480,7 +480,7 @@ Disassembly of section .text:
  7be:	66 87 90 90 90 90 90 [ 	]*xchg   %dx,0x90909090\(%eax\)
  7c5:	66 89 90 90 90 90 90 [ 	]*mov    %dx,0x90909090\(%eax\)
  7cc:	66 8b 90 90 90 90 90 [ 	]*mov    0x90909090\(%eax\),%dx
- 7d3:	8c 90 90 90 90 90 [ 	]*mov[l ]   %ss,0x90909090\(%eax\)
+ 7d3:	8c 90 90 90 90 90 [ 	]*mov[w ]   %ss,0x90909090\(%eax\)
  7d9:	66 8d 90 90 90 90 90 [ 	]*lea    0x90909090\(%eax\),%dx
  7e0:	66 8f 80 90 90 90 90 [ 	]*popw   0x90909090\(%eax\)
  7e7:	66 91 [ 	]*xchg   %ax,%cx
--- binutils/gas/testsuite/gas/i386/opcode.s.seg	2004-11-10 09:20:23.000000000 -0800
+++ binutils/gas/testsuite/gas/i386/opcode.s	2005-03-25 12:00:28.000000000 -0800
@@ -130,9 +130,9 @@ foo:
  mov    %edx,0x90909090(%eax)
  mov    0x90909090(%eax),%dl
  mov    0x90909090(%eax),%edx
- movl   %ss,0x90909090(%eax)
+ movw   %ss,0x90909090(%eax)
  lea    0x90909090(%eax),%edx
- movl   0x90909090(%eax),%ss
+ movw   0x90909090(%eax),%ss
  popl   0x90909090(%eax)
  xchg   %eax,%eax
  xchg   %eax,%ecx
--- binutils/gas/testsuite/gas/i386/segment.l.seg	2005-03-25 11:18:47.000000000 -0800
+++ binutils/gas/testsuite/gas/i386/segment.l	2005-03-25 11:26:35.000000000 -0800
@@ -0,0 +1,10 @@
+   1              	.psize 0
+   2              	.text
+   3              	# test segment reg insns with memory operand
+   4 0000 8C18     		movw	%ds,\(%eax\)
+   5 0002 8C18     		mov	%ds,\(%eax\)
+   6 0004 8E18     		movw	\(%eax\),%ds
+   7 0006 8E18     		mov	\(%eax\),%ds
+   8              		# Force a good alignment.
+   9 0008 00000000 		.p2align	4,0
+   9      00000000 
--- binutils/gas/testsuite/gas/i386/segment.s.seg	2005-03-25 11:18:45.000000000 -0800
+++ binutils/gas/testsuite/gas/i386/segment.s	2005-03-25 11:25:37.000000000 -0800
@@ -0,0 +1,9 @@
+.psize 0
+.text
+# test segment reg insns with memory operand
+	movw	%ds,(%eax)
+	mov	%ds,(%eax)
+	movw	(%eax),%ds
+	mov	(%eax),%ds
+	# Force a good alignment.
+	.p2align	4,0
--- binutils/gas/testsuite/gas/i386/x86-64-inval-seg.l.seg	2005-03-25 12:03:19.000000000 -0800
+++ binutils/gas/testsuite/gas/i386/x86-64-inval-seg.l	2005-03-25 12:04:15.000000000 -0800
@@ -0,0 +1,14 @@
+.*: Assembler messages:
+.*:3: Error: .*
+.*:4: Error: .*
+.*:5: Error: .*
+.*:6: Error: .*
+GAS LISTING .*
+
+
+   1 [ 	]*	.text
+   2 [ 	]*# All the following should be illegal
+   3 [ 	]*	movq	%ds,\(%rax\)
+   4 [ 	]*	movl	%ds,\(%rax\)
+   5 [ 	]*	movq	\(%rax\),%ds
+   6 [ 	]*	movl	\(%rax\),%ds
--- binutils/gas/testsuite/gas/i386/x86-64-inval-seg.s.seg	2005-03-25 12:03:21.000000000 -0800
+++ binutils/gas/testsuite/gas/i386/x86-64-inval-seg.s	2005-03-25 12:04:25.000000000 -0800
@@ -0,0 +1,6 @@
+	.text
+# All the following should be illegal
+	movq	%ds,(%rax)
+	movl	%ds,(%rax)
+	movq	(%rax),%ds
+	movl	(%rax),%ds
--- binutils/gas/testsuite/gas/i386/x86-64-opcode.d.seg	2005-03-25 17:47:02.668057512 -0800
+++ binutils/gas/testsuite/gas/i386/x86-64-opcode.d	2005-03-25 17:46:39.007115460 -0800
@@ -16,22 +16,16 @@ Disassembly of section .text:
 [	 ]*[0-9a-f]+:[	 ]+cf[	 ]+iret[	 ]*(#.*)*
 [	 ]*[0-9a-f]+:[	 ]+66 cf[	 ]+iretw[	 ]*(#.*)*
 [	 ]*[0-9a-f]+:[	 ]+48 cf[	 ]+iretq[	 ]*(#.*)*
-[	 ]*[0-9a-f]+:[	 ]+41 8c 08[	 ]+movl?[	 ]+%cs,\(%r8\)[	 ]*(#.*)*
-[	 ]*[0-9a-f]+:[	 ]+8c 08[	 ]+movl?[	 ]+%cs,\(%rax\)[	 ]*(#.*)*
-[	 ]*[0-9a-f]+:[	 ]+41 8c 10[	 ]+movl?[	 ]+%ss,\(%r8\)[	 ]*(#.*)*
-[	 ]*[0-9a-f]+:[	 ]+8c 10[	 ]+movl?[	 ]+%ss,\(%rax\)[	 ]*(#.*)*
-[	 ]*[0-9a-f]+:[	 ]+41 8c 20[	 ]+movl?[	 ]+%fs,\(%r8\)[	 ]*(#.*)*
-[	 ]*[0-9a-f]+:[	 ]+8c 20[	 ]+movl?[	 ]+%fs,\(%rax\)[	 ]*(#.*)*
-[	 ]*[0-9a-f]+:[	 ]+41 8c 08[	 ]+movl?[	 ]+%cs,\(%r8\)[	 ]*(#.*)*
-[	 ]*[0-9a-f]+:[	 ]+8c 08[	 ]+movl?[	 ]+%cs,\(%rax\)[	 ]*(#.*)*
-[	 ]*[0-9a-f]+:[	 ]+41 8c 10[	 ]+movl?[	 ]+%ss,\(%r8\)[	 ]*(#.*)*
-[	 ]*[0-9a-f]+:[	 ]+8c 10[	 ]+movl?[	 ]+%ss,\(%rax\)[	 ]*(#.*)*
-[	 ]*[0-9a-f]+:[	 ]+41 8c 20[	 ]+movl?[	 ]+%fs,\(%r8\)[	 ]*(#.*)*
-[	 ]*[0-9a-f]+:[	 ]+8c 20[	 ]+movl?[	 ]+%fs,\(%rax\)[	 ]*(#.*)*
-[	 ]*[0-9a-f]+:[	 ]+41 8e 10[	 ]+movl?[	 ]+\(%r8\),%ss[	 ]*(#.*)*
-[	 ]*[0-9a-f]+:[	 ]+8e 10[	 ]+movl?[	 ]+\(%rax\),%ss[	 ]*(#.*)*
-[	 ]*[0-9a-f]+:[	 ]+41 8e 20[	 ]+movl?[	 ]+\(%r8\),%fs[	 ]*(#.*)*
-[	 ]*[0-9a-f]+:[	 ]+8e 20[	 ]+movl?[	 ]+\(%rax\),%fs[	 ]*(#.*)*
+[	 ]*[0-9a-f]+:[	 ]+41 8c 08[	 ]+movw?[	 ]+%cs,\(%r8\)[	 ]*(#.*)*
+[	 ]*[0-9a-f]+:[	 ]+8c 08[	 ]+movw?[	 ]+%cs,\(%rax\)[	 ]*(#.*)*
+[	 ]*[0-9a-f]+:[	 ]+41 8c 10[	 ]+movw?[	 ]+%ss,\(%r8\)[	 ]*(#.*)*
+[	 ]*[0-9a-f]+:[	 ]+8c 10[	 ]+movw?[	 ]+%ss,\(%rax\)[	 ]*(#.*)*
+[	 ]*[0-9a-f]+:[	 ]+41 8c 20[	 ]+movw?[	 ]+%fs,\(%r8\)[	 ]*(#.*)*
+[	 ]*[0-9a-f]+:[	 ]+8c 20[	 ]+movw?[	 ]+%fs,\(%rax\)[	 ]*(#.*)*
+[	 ]*[0-9a-f]+:[	 ]+41 8e 10[	 ]+movw?[	 ]+\(%r8\),%ss[	 ]*(#.*)*
+[	 ]*[0-9a-f]+:[	 ]+8e 10[	 ]+movw?[	 ]+\(%rax\),%ss[	 ]*(#.*)*
+[	 ]*[0-9a-f]+:[	 ]+41 8e 20[	 ]+movw?[	 ]+\(%r8\),%fs[	 ]*(#.*)*
+[	 ]*[0-9a-f]+:[	 ]+8e 20[	 ]+movw?[	 ]+\(%rax\),%fs[	 ]*(#.*)*
 [	 ]*[0-9a-f]+:[	 ]+41 c6 00 00[	 ]+movb[	 ]+\$0[x0]*,\(%r8\)[	 ]*(#.*)*
 [	 ]*[0-9a-f]+:[	 ]+c6 00 00[	 ]+movb[	 ]+\$0[x0]*,\(%rax\)[	 ]*(#.*)*
 [	 ]*[0-9a-f]+:[	 ]+66 41 c7 00 00 70[	 ]+movw[	 ]+\$0x7000,\(%r8\)[	 ]*(#.*)*
@@ -274,5 +268,4 @@ Disassembly of section .text:
 [	 ]*[0-9a-f]+:[	 ]+e7 00[	 ]+out[	 ]+%eax,\$0[x0]*[	 ]*(#.*)*
 [	 ]*[0-9a-f]+:[	 ]+00 00[	 ]+.*
 [	 ]*[0-9a-f]+:[	 ]+00 00[	 ]+.*
-[	 ]*[0-9a-f]+:[	 ]+00 00[	 ]+.*
 [	 *]...
--- binutils/gas/testsuite/gas/i386/x86-64-opcode.s.seg	2003-02-27 11:27:13.000000000 -0800
+++ binutils/gas/testsuite/gas/i386/x86-64-opcode.s	2005-03-25 12:16:15.000000000 -0800
@@ -20,22 +20,16 @@
 	# CMP
 
 	# MOV
-	MOVw %cs,(%r8)		      # 66  --  -- 41   8C 08				 ; REX to access upper reg. O16 for 16-bit operand size
-	MOVw %cs,(%rax)		      # 66  --  -- --   8C 08				 ; O16 for 16-bit operand size
-	MOVw %ss,(%r8)		      # 66  --  -- 41   8C 10				 ; REX to access upper reg. O16 for 16-bit operand size
-	MOVw %ss,(%rax)		      # 66  --  -- --   8C 10				 ; O16 for 16-bit operand size
-	MOVw %fs,(%r8)		      # 66  --  -- 41   8C 20				 ; REX to access upper reg. O16 for 16-bit operand size
-	MOVw %fs,(%rax)		      # 66  --  -- --   8C 20				 ; O16 for 16-bit operand size
-	MOVl %cs,(%r8)		      # --  --  -- 41   8C 08				 ; REX to access upper reg.
-	MOVl %cs,(%rax)		      # --  --  -- --   8C 08
-	MOVl %ss,(%r8)		      # --  --  -- 41   8C 10				 ; REX to access upper reg.
-	MOVl %ss,(%rax)		      # --  --  -- --   8C 10
-	MOVl %fs,(%r8)		      # --  --  -- 41   8C 20				 ; REX to access upper reg.
-	MOVl %fs,(%rax)		      # --  --  -- --   8C 20
-	MOVl (%r8),%ss		      # --  --  -- 41   8E 10				 ; REX to access upper reg.
-	MOVl (%rax),%ss		      # --  --  -- --   8E 10
-	MOVl (%r8),%fs		      # --  --  -- 41   8E 20				 ; REX to access upper reg.
-	MOVl (%rax),%fs		      # --  --  -- --   8E 20
+	MOVw %cs,(%r8)		      # --  --  -- 41   8C 08				 ; REX to access upper reg.
+	MOVw %cs,(%rax)		      # --  --  -- --   8C 08
+	MOVw %ss,(%r8)		      # --  --  -- 41   8C 10				 ; REX to access upper reg.
+	MOVw %ss,(%rax)		      # --  --  -- --   8C 10
+	MOVw %fs,(%r8)		      # --  --  -- 41   8C 20				 ; REX to access upper reg.
+	MOVw %fs,(%rax)		      # --  --  -- --   8C 20
+	MOVw (%r8),%ss		      # --  --  -- 41   8E 10				 ; REX to access upper reg.
+	MOVw (%rax),%ss		      # --  --  -- --   8E 10
+	MOVw (%r8),%fs		      # --  --  -- 41   8E 20				 ; REX to access upper reg.
+	MOVw (%rax),%fs		      # --  --  -- --   8E 20
 	MOVb $0,(%r8)		      # --  --  -- 41   C6 00 00			 ; REX to access upper reg.
 	MOVb $0,(%rax)		      # --  --  -- --   C6 00 00
 	MOVw $0x7000,(%r8)	      # 66  --  -- 41   C7 00 00 70			 ; REX to access upper reg. O16 for 16-bit operand size
--- binutils/gas/testsuite/gas/i386/x86-64-segment.l.seg	2005-03-25 11:28:25.000000000 -0800
+++ binutils/gas/testsuite/gas/i386/x86-64-segment.l	2005-03-25 12:53:59.000000000 -0800
@@ -0,0 +1,12 @@
+   1              	.psize 0
+   2              	.text
+   3              	# test segment reg insns with memory operand
+   4 0000 8C18     		movw	%ds,\(%rax\)
+   5 0002 8C18     		mov	%ds,\(%rax\)
+   6 0004 8E18     		movw	\(%rax\),%ds
+   7 0006 8E18     		mov	\(%rax\),%ds
+   8              	# test segment reg insns with REX
+   9 0008 488CD8   		movq	%ds,%rax
+  10 000b 488ED8   		movq	%rax,%ds
+  11              		# Force a good alignment.
+  12 000e 0000     		.p2align	4,0
--- binutils/gas/testsuite/gas/i386/x86-64-segment.s.seg	2005-03-25 11:28:27.000000000 -0800
+++ binutils/gas/testsuite/gas/i386/x86-64-segment.s	2005-03-25 12:18:47.000000000 -0800
@@ -0,0 +1,12 @@
+.psize 0
+.text
+# test segment reg insns with memory operand
+	movw	%ds,(%rax)
+	mov	%ds,(%rax)
+	movw	(%rax),%ds
+	mov	(%rax),%ds
+# test segment reg insns with REX
+	movq	%ds,%rax
+	movq	%rax,%ds
+	# Force a good alignment.
+	.p2align	4,0
--- binutils/include/opcode/i386.h.seg	2005-03-03 09:24:08.000000000 -0800
+++ binutils/include/opcode/i386.h	2005-03-25 12:44:54.000000000 -0800
@@ -98,11 +98,13 @@ static const template i386_optab[] =
    are set to an implementation defined value (on the Pentium Pro,
    the implementation defined value is zero).  */
 { "mov",   2,	0x8c, X, 0,	 wl_Suf|Modrm,			{ SReg2, WordReg|InvMem, 0 } },
-{ "mov",   2,	0x8c, X, 0,	 wl_Suf|Modrm|IgnoreSize,	{ SReg2, WordMem, 0 } },
+{ "mov",   2,	0x8c, X, 0,	 w_Suf|Modrm|IgnoreSize,	{ SReg2, WordMem, 0 } },
 { "mov",   2,	0x8c, X, Cpu386, wl_Suf|Modrm,			{ SReg3, WordReg|InvMem, 0 } },
-{ "mov",   2,	0x8c, X, Cpu386, wl_Suf|Modrm|IgnoreSize,	{ SReg3, WordMem, 0 } },
-{ "mov",   2,	0x8e, X, 0,	 wl_Suf|Modrm|IgnoreSize,	{ WordReg|WordMem, SReg2, 0 } },
-{ "mov",   2,	0x8e, X, Cpu386, wl_Suf|Modrm|IgnoreSize,	{ WordReg|WordMem, SReg3, 0 } },
+{ "mov",   2,	0x8c, X, Cpu386, w_Suf|Modrm|IgnoreSize,	{ SReg3, WordMem, 0 } },
+{ "mov",   2,	0x8e, X, 0,	 wl_Suf|Modrm|IgnoreSize,	{ WordReg, SReg2, 0 } },
+{ "mov",   2,	0x8e, X, 0,	 w_Suf|Modrm|IgnoreSize,	{ WordMem, SReg2, 0 } },
+{ "mov",   2,	0x8e, X, Cpu386, wl_Suf|Modrm|IgnoreSize,	{ WordReg, SReg3, 0 } },
+{ "mov",   2,	0x8e, X, Cpu386, w_Suf|Modrm|IgnoreSize,	{ WordMem, SReg3, 0 } },
 /* Move to/from control debug registers.  In the 16 or 32bit modes they are 32bit.  In the 64bit
    mode they are 64bit.*/
 { "mov",   2, 0x0f20, X, Cpu386|CpuNo64, l_Suf|D|Modrm|IgnoreSize,{ Control, Reg32|InvMem, 0} },
@@ -1003,6 +1005,10 @@ static const template i386_optab[] =
 {"movq",   2,	0x88, X, Cpu64,	 NoSuf|D|W|Modrm|Size64,{ Reg64, Reg64|AnyMem, 0 } },
 {"movq",   2,	0xc6, 0, Cpu64,	 NoSuf|W|Modrm|Size64,	{ Imm32S, Reg64|WordMem, 0 } },
 {"movq",   2,	0xb0, X, Cpu64,	 NoSuf|W|ShortForm|Size64,{ Imm64, Reg64, 0 } },
+/* The segment register moves accept Reg64 so that a segment register
+   can be copied to a 64 bit register, and vice versa.  */
+{"movq",   2,	0x8c, X, Cpu64,  NoSuf|Modrm|Size64,	{ SReg2|SReg3, Reg64|InvMem, 0 } },
+{"movq",   2,	0x8e, X, Cpu64,	 NoSuf|Modrm|Size64,	{ Reg64, SReg2|SReg3, 0 } },
 /* Move to/from control debug registers.  In the 16 or 32bit modes they are 32bit.  In the 64bit
    mode they are 64bit.*/
 {"movq",   2, 0x0f20, X, Cpu64,	 NoSuf|D|Modrm|IgnoreSize|NoRex64|Size64,{ Control, Reg64|InvMem, 0} },
--- binutils/opcodes/i386-dis.c.seg	2005-03-25 09:03:01.000000000 -0800
+++ binutils/opcodes/i386-dis.c	2005-03-25 17:38:10.097887059 -0800
@@ -97,6 +97,7 @@ static void SIMD_Fixup (int, int);
 static void PNI_Fixup (int, int);
 static void INVLPG_Fixup (int, int);
 static void BadOp (void);
+static void SEG_Fixup (int, int);
 
 struct dis_private {
   /* Points to first byte not fetched.  */
@@ -221,6 +222,7 @@ fetch_data (struct disassemble_info *inf
 #define Cm OP_C, m_mode
 #define Dm OP_D, m_mode
 #define Td OP_T, d_mode
+#define Sv SEG_Fixup, v_mode
 
 #define RMeAX OP_REG, eAX_reg
 #define RMeBX OP_REG, eBX_reg
@@ -642,9 +644,9 @@ static const struct dis386 dis386[] = {
   { "movS",		Ev, Gv, XX },
   { "movB",		Gb, Eb, XX },
   { "movS",		Gv, Ev, XX },
-  { "movQ",		Ev, Sw, XX },
+  { "movQ",		Sv, Sw, XX },
   { "leaS",		Gv, M, XX },
-  { "movQ",		Sw, Ev, XX },
+  { "movQ",		Sw, Sv, XX },
   { "popU",		Ev, XX, XX },
   /* 90 */
   { "nop",		NOP_Fixup, 0, XX, XX },
@@ -4422,3 +4424,52 @@ BadOp (void)
   codep = insn_codep + 1;
   oappend ("(bad)");
 }
+
+static void
+SEG_Fixup (int extrachar, int sizeflag)
+{
+  if (mod == 3)
+    {
+      /* We need to add a proper suffix with
+
+		movw %ds,%ax
+		movl %ds,%eax
+		movq %ds,%rax
+		movw %ax,%ds
+		movl %eax,%ds
+		movq %rax,%ds
+       */
+      const char *suffix;
+
+      if (prefixes & PREFIX_DATA)
+	suffix = "w";
+      else
+	{
+	  USED_REX (REX_MODE64);
+	  if (rex & REX_MODE64)
+	    suffix = "q";
+	  else
+	    suffix = "l";
+	}
+      strcat (obuf, suffix);
+    }
+  else
+    {
+      /* We need to fix the suffix for
+
+		movw %ds,(%eax)
+		movw %ds,(%rax)
+		movw (%eax),%ds
+		movw (%rax),%ds
+
+	 Override "mov[l|q]".  */
+      char *p = obuf + strlen (obuf) - 1;
+
+      /* We might not have a suffix.  */
+      if (*p == 'v')
+	++p;
+      *p = 'w';
+    }
+
+  OP_E (extrachar, sizeflag);
+}

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

* i386/x86_64 segment register issuses (Re: PATCH: Fix x86 segment register access)
  2005-03-26 23:31 PATCH: Fix x86 segment register access H. J. Lu
@ 2005-03-28 10:21 ` H. J. Lu
  2005-03-30  9:46   ` PATCH: i386/x86_64 segment register access update H. J. Lu
       [not found]   ` <m14qev3h8l.fsf@muc.de>
  0 siblings, 2 replies; 12+ messages in thread
From: H. J. Lu @ 2005-03-28 10:21 UTC (permalink / raw)
  To: binutils, GNU C Library; +Cc: linux kernel

It turns out that 2.4 kernel has

arch/i386/kernel/process.c:     asm volatile("movl %%" #seg ",%0":"=m" (*(int *)&(value)))
arch/i386/kernel/process.c:     asm volatile("movl %%fs,%0":"=m" (*(int *)&prev->fs));
arch/i386/kernel/process.c:     asm volatile("movl %%gs,%0":"=m" (*(int *)&prev->gs));
arch/x86_64/kernel/process.c:   asm("movl %%gs,%0" : "=m" (p->thread.gsindex));
arch/x86_64/kernel/process.c:   asm("movl %%fs,%0" : "=m" (p->thread.fsindex));
arch/x86_64/kernel/process.c:   asm("movl %%es,%0" : "=m" (p->thread.es));
arch/x86_64/kernel/process.c:   asm("movl %%ds,%0" : "=m" (p->thread.ds));
arch/x86_64/kernel/process.c:   asm volatile("movl %%es,%0" : "=m" (prev->es));
arch/x86_64/kernel/process.c:   asm volatile ("movl %%ds,%0" : "=m" (prev->ds));

2.6 kernel has

arch/i386/kernel/process.c:     asm volatile("movl %%fs,%0":"=m" (*(int *)&prev->fs));
arch/i386/kernel/process.c:     asm volatile("movl %%gs,%0":"=m" (*(int *)&prev->gs));
arch/x86_64/kernel/process.c:   asm("movl %%gs,%0" : "=m" (p->thread.gsindex));
arch/x86_64/kernel/process.c:   asm("movl %%fs,%0" : "=m" (p->thread.fsindex));
arch/x86_64/kernel/process.c:   asm("movl %%es,%0" : "=m" (p->thread.es));
arch/x86_64/kernel/process.c:   asm("movl %%ds,%0" : "=m" (p->thread.ds));
arch/x86_64/kernel/process.c:   asm volatile("movl %%es,%0" : "=m" (prev->es));
arch/x86_64/kernel/process.c:   asm volatile ("movl %%ds,%0" : "=m" (prev->ds));
arch/x86_64/kernel/process.c:           asm volatile("movl %%fs,%0" : "=g" (fsindex));
arch/x86_64/kernel/process.c:           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. The new assembler
will force people to use

	mov (%eax),%ds
	movw (%eax),%ds
	movw %ds,(%eax)
	mov %ds,(%eax)

Will it be a big problem for kernel people?

BTW, I haven't checked glibc yet. It may have similar issues.

H.J.
---
On Fri, Mar 25, 2005 at 06:05:06PM -0800, H. J. Lu wrote:
> X86 segment register access is a special. We can move between a segment
> register and a 16/32/64bit general-purpose register. But we can only
> move between a segment register and a 16bit memory address. The current
> assembler allows "movl (%eax),%ds", but doesn't allow "movq %rax,%ds".
> The disassembler display "movl (%eax),%ds". This patch tries to fix
> those.
> 
> 
> H.J.
> ----
> gas/testsuite/
> 
> 2005-03-25  H.J. Lu  <hongjiu.lu@intel.com>
> 
> 	* gas/i386/i386.exp: Run segment and inval-seg for i386. Run
> 	x86-64-segment and x86-64-inval-seg for x86-64.
> 
> 	* gas/i386/intel.d: Expect movw for moving between memory and
> 	segment register.
> 	* gas/i386/naked.d: Likewise.
> 	* gas/i386/opcode.d: Likewise.
> 	* gas/i386/x86-64-opcode.d: Likewise.
> 
> 	* gas/i386/opcode.s: Use movw for moving between memory and
> 	segment register.
> 	* gas/i386/x86-64-opcode.s: Likewise.
> 
> 	* : Likewise.
> 
> 	* gas/i386/inval-seg.l: New.
> 	* gas/i386/inval-seg.s: New.
> 	* gas/i386/segment.l: New.
> 	* gas/i386/segment.s: New.
> 	* gas/i386/x86-64-inval-seg.l: New.
> 	* gas/i386/x86-64-inval-seg.s: New.
> 	* gas/i386/x86-64-segment.l: New.
> 	* gas/i386/x86-64-segment.s: New.
> 
> include/opcode/
> 
> 2005-03-25  H.J. Lu  <hongjiu.lu@intel.com>
> 
> 	* i386.h (i386_optab): Don't allow the `l' suffix for moving
> 	moving between memory and segment register. Allow movq for
> 	moving between general-purpose register and segment register.
> 
> opcodes/
> 
> 2005-03-25  H.J. Lu  <hongjiu.lu@intel.com>
> 
> 	* i386-dis.c (SEG_Fixup): New.
> 	(Sv): New.
> 	(dis386): Use "Sv" for 0x8c and 0x8e.
> 

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

* PATCH: i386/x86_64 segment register access update
  2005-03-28 10:21 ` i386/x86_64 segment register issuses (Re: PATCH: Fix x86 segment register access) H. J. Lu
@ 2005-03-30  9:46   ` H. J. Lu
       [not found]   ` <m14qev3h8l.fsf@muc.de>
  1 sibling, 0 replies; 12+ messages in thread
From: H. J. Lu @ 2005-03-30  9:46 UTC (permalink / raw)
  To: binutils; +Cc: linux kernel

[-- Attachment #1: Type: text/plain, Size: 987 bytes --]

The new i386/x86_64 assemblers no longer accept instructions for moving
between a segment register and a 32bit memory location, i.e.,

        movl (%eax),%ds
        movl %ds,(%eax)

To generate instructions for moving between a segment register and a
16bit memory location without the 16bit operand size prefix, 0x66,

        mov (%eax),%ds
        mov %ds,(%eax)

should be used. It will work with both new and old assemblers. The
assembler starting from 2.16.90.0.1 will also support

        movw (%eax),%ds
        movw %ds,(%eax)

without the 0x66 prefix. I am enclosing patches for 2.4 and 2.6 kernels
here. The resulting kernel binaries should be unchanged as before, with
old and new assemblers, if gcc never generates memory access for

               unsigned gsindex;
               asm volatile("movl %%gs,%0" : "=g" (gsindex));

If gcc does generate memory access for the code above, the upper bits
in gsindex are undefined and the new assembler doesn't allow it.


H.J.

[-- Attachment #2: linux-2.4-seg-4.patch --]
[-- Type: text/plain, Size: 4115 bytes --]

--- linux/arch/i386/kernel/apm.c.seg	2005-03-27 13:10:45.000000000 -0800
+++ linux/arch/i386/kernel/apm.c	2005-03-28 10:30:24.000000000 -0800
@@ -327,7 +327,7 @@ extern int (*console_blank_hook)(int);
  * Save a segment register away
  */
 #define savesegment(seg, where) \
-		__asm__ __volatile__("movl %%" #seg ",%0" : "=m" (where))
+		__asm__ __volatile__("mov %%" #seg ",%0" : "=m" (where))
 
 /*
  * Maximum number of events stored
@@ -553,7 +553,7 @@ static inline void apm_restore_cpus(unsi
 
 #ifdef APM_ZERO_SEGS
 #	define APM_DECL_SEGS \
-		unsigned int saved_fs; unsigned int saved_gs;
+		unsigned short saved_fs; unsigned short saved_gs;
 #	define APM_DO_SAVE_SEGS \
 		savesegment(fs, saved_fs); savesegment(gs, saved_gs)
 #	define APM_DO_ZERO_SEGS \
--- linux/arch/i386/kernel/process.c.seg	2005-03-27 13:10:45.000000000 -0800
+++ linux/arch/i386/kernel/process.c	2005-03-28 10:30:24.000000000 -0800
@@ -544,7 +544,7 @@ void release_thread(struct task_struct *
  * Save a segment.
  */
 #define savesegment(seg,value) \
-	asm volatile("movl %%" #seg ",%0":"=m" (*(int *)&(value)))
+	asm volatile("mov %%" #seg ",%0":"=m" (value))
 
 int copy_thread(int nr, unsigned long clone_flags, unsigned long esp,
 	unsigned long unused,
@@ -661,8 +661,8 @@ void fastcall __switch_to(struct task_st
 	 * Save away %fs and %gs. No need to save %es and %ds, as
 	 * those are always kernel segments while inside the kernel.
 	 */
-	asm volatile("movl %%fs,%0":"=m" (*(int *)&prev->fs));
-	asm volatile("movl %%gs,%0":"=m" (*(int *)&prev->gs));
+	asm volatile("mov %%fs,%0":"=m" (prev->fs));
+	asm volatile("mov %%gs,%0":"=m" (prev->gs));
 
 	/*
 	 * Restore %fs and %gs.
--- linux/arch/x86_64/kernel/process.c.seg	2005-03-27 13:10:51.000000000 -0800
+++ linux/arch/x86_64/kernel/process.c	2005-03-28 11:16:57.000000000 -0800
@@ -527,10 +527,10 @@ int copy_thread(int nr, unsigned long cl
 	p->thread.fs = me->thread.fs;
 	p->thread.gs = me->thread.gs;
 
-	asm("movl %%gs,%0" : "=m" (p->thread.gsindex));
-	asm("movl %%fs,%0" : "=m" (p->thread.fsindex));
-	asm("movl %%es,%0" : "=m" (p->thread.es));
-	asm("movl %%ds,%0" : "=m" (p->thread.ds));
+	asm("mov %%gs,%0" : "=m" (p->thread.gsindex));
+	asm("mov %%fs,%0" : "=m" (p->thread.fsindex));
+	asm("mov %%es,%0" : "=m" (p->thread.es));
+	asm("mov %%ds,%0" : "=m" (p->thread.ds));
 
 	unlazy_fpu(current);	
 	p->thread.i387 = current->thread.i387;
@@ -575,11 +575,11 @@ struct task_struct *__switch_to(struct t
 	/* 
 	 * Switch DS and ES.	 
 	 */
-	asm volatile("movl %%es,%0" : "=m" (prev->es)); 
+	asm volatile("mov %%es,%0" : "=m" (prev->es)); 
 	if (unlikely(next->es | prev->es))
 		loadsegment(es, next->es); 
 	
-	asm volatile ("movl %%ds,%0" : "=m" (prev->ds)); 
+	asm volatile ("mov %%ds,%0" : "=m" (prev->ds)); 
 	if (unlikely(next->ds | prev->ds))
 		loadsegment(ds, next->ds);
 
@@ -588,7 +588,7 @@ struct task_struct *__switch_to(struct t
 	 */
 	{ 
 		unsigned fsindex;
-		asm volatile("movl %%fs,%0" : "=g" (fsindex)); 
+		asm volatile("movl %%fs,%0" : "=r" (fsindex)); 
 		/* segment register != 0 always requires a reload. 
 		   also reload when it has changed. 
 		   when prev process used 64bit base always reload
@@ -609,7 +609,7 @@ struct task_struct *__switch_to(struct t
 	}
 	{
 		unsigned gsindex;
-		asm volatile("movl %%gs,%0" : "=g" (gsindex)); 
+		asm volatile("movl %%gs,%0" : "=r" (gsindex)); 
 		if (unlikely((gsindex | next->gsindex) || prev->gs)) {
 			load_gs_index(next->gsindex);
 			if (gsindex)
--- linux/include/asm-i386/system.h.seg	2005-03-27 15:33:12.000000000 -0800
+++ linux/include/asm-i386/system.h	2005-03-28 10:30:24.000000000 -0800
@@ -84,7 +84,7 @@ static inline unsigned long _get_base(ch
 #define loadsegment(seg,value)			\
 	asm volatile("\n"			\
 		"1:\t"				\
-		"movl %0,%%" #seg "\n"		\
+		"mov %0,%%" #seg "\n"		\
 		"2:\n"				\
 		".section .fixup,\"ax\"\n"	\
 		"3:\t"				\
@@ -96,7 +96,7 @@ static inline unsigned long _get_base(ch
 		".align 4\n\t"			\
 		".long 1b,3b\n"			\
 		".previous"			\
-		: :"m" (*(unsigned int *)&(value)))
+		: :"m" (value))
 
 /*
  * Clear and set 'TS' bit respectively

[-- Attachment #3: linux-2.6-seg-5.patch --]
[-- Type: text/plain, Size: 3961 bytes --]

--- linux/arch/i386/kernel/process.c.seg	2005-03-27 13:07:14.000000000 -0800
+++ linux/arch/i386/kernel/process.c	2005-03-28 10:28:47.000000000 -0800
@@ -597,8 +597,8 @@ struct task_struct fastcall * __switch_t
 	 * Save away %fs and %gs. No need to save %es and %ds, as
 	 * those are always kernel segments while inside the kernel.
 	 */
-	asm volatile("movl %%fs,%0":"=m" (*(int *)&prev->fs));
-	asm volatile("movl %%gs,%0":"=m" (*(int *)&prev->gs));
+	asm volatile("mov %%fs,%0":"=m" (prev->fs));
+	asm volatile("mov %%gs,%0":"=m" (prev->gs));
 
 	/*
 	 * Restore %fs and %gs if needed.
--- linux/arch/i386/kernel/vm86.c.seg	2005-03-27 13:07:14.000000000 -0800
+++ linux/arch/i386/kernel/vm86.c	2005-03-28 10:28:47.000000000 -0800
@@ -294,8 +294,8 @@ static void do_sys_vm86(struct kernel_vm
  */
 	info->regs32->eax = 0;
 	tsk->thread.saved_esp0 = tsk->thread.esp0;
-	asm volatile("movl %%fs,%0":"=m" (tsk->thread.saved_fs));
-	asm volatile("movl %%gs,%0":"=m" (tsk->thread.saved_gs));
+	asm volatile("mov %%fs,%0":"=m" (tsk->thread.saved_fs));
+	asm volatile("mov %%gs,%0":"=m" (tsk->thread.saved_gs));
 
 	tss = &per_cpu(init_tss, get_cpu());
 	tsk->thread.esp0 = (unsigned long) &info->VM86_TSS_ESP0;
--- linux/arch/x86_64/kernel/process.c.seg	2005-03-27 13:07:49.000000000 -0800
+++ linux/arch/x86_64/kernel/process.c	2005-03-28 11:11:04.206766410 -0800
@@ -391,10 +391,10 @@ int copy_thread(int nr, unsigned long cl
 	p->thread.fs = me->thread.fs;
 	p->thread.gs = me->thread.gs;
 
-	asm("movl %%gs,%0" : "=m" (p->thread.gsindex));
-	asm("movl %%fs,%0" : "=m" (p->thread.fsindex));
-	asm("movl %%es,%0" : "=m" (p->thread.es));
-	asm("movl %%ds,%0" : "=m" (p->thread.ds));
+	asm("mov %%gs,%0" : "=m" (p->thread.gsindex));
+	asm("mov %%fs,%0" : "=m" (p->thread.fsindex));
+	asm("mov %%es,%0" : "=m" (p->thread.es));
+	asm("mov %%ds,%0" : "=m" (p->thread.ds));
 
 	if (unlikely(me->thread.io_bitmap_ptr != NULL)) { 
 		p->thread.io_bitmap_ptr = kmalloc(IO_BITMAP_BYTES, GFP_KERNEL);
@@ -457,11 +457,11 @@ struct task_struct *__switch_to(struct t
 	 * Switch DS and ES.
 	 * This won't pick up thread selector changes, but I guess that is ok.
 	 */
-	asm volatile("movl %%es,%0" : "=m" (prev->es)); 
+	asm volatile("mov %%es,%0" : "=m" (prev->es)); 
 	if (unlikely(next->es | prev->es))
 		loadsegment(es, next->es); 
 	
-	asm volatile ("movl %%ds,%0" : "=m" (prev->ds)); 
+	asm volatile ("mov %%ds,%0" : "=m" (prev->ds)); 
 	if (unlikely(next->ds | prev->ds))
 		loadsegment(ds, next->ds);
 
@@ -472,7 +472,7 @@ struct task_struct *__switch_to(struct t
 	 */
 	{ 
 		unsigned fsindex;
-		asm volatile("movl %%fs,%0" : "=g" (fsindex)); 
+		asm volatile("movl %%fs,%0" : "=r" (fsindex)); 
 		/* segment register != 0 always requires a reload. 
 		   also reload when it has changed. 
 		   when prev process used 64bit base always reload
@@ -493,7 +493,7 @@ struct task_struct *__switch_to(struct t
 	}
 	{ 
 		unsigned gsindex;
-		asm volatile("movl %%gs,%0" : "=g" (gsindex)); 
+		asm volatile("movl %%gs,%0" : "=r" (gsindex)); 
 		if (unlikely(gsindex | next->gsindex | prev->gs)) {
 			load_gs_index(next->gsindex);
 			if (gsindex)
--- linux/include/asm-i386/system.h.seg	2005-03-27 13:09:12.000000000 -0800
+++ linux/include/asm-i386/system.h	2005-03-28 10:28:47.000000000 -0800
@@ -81,7 +81,7 @@ static inline unsigned long _get_base(ch
 #define loadsegment(seg,value)			\
 	asm volatile("\n"			\
 		"1:\t"				\
-		"movl %0,%%" #seg "\n"		\
+		"mov %0,%%" #seg "\n"		\
 		"2:\n"				\
 		".section .fixup,\"ax\"\n"	\
 		"3:\t"				\
@@ -93,13 +93,13 @@ static inline unsigned long _get_base(ch
 		".align 4\n\t"			\
 		".long 1b,3b\n"			\
 		".previous"			\
-		: :"m" (*(unsigned int *)&(value)))
+		: :"m" (value))
 
 /*
  * Save a segment register away
  */
 #define savesegment(seg, value) \
-	asm volatile("movl %%" #seg ",%0":"=m" (*(int *)&(value)))
+	asm volatile("mov %%" #seg ",%0":"=m" (value))
 
 /*
  * Clear and set 'TS' bit respectively

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

* Re: i386/x86_64 segment register issuses (Re: PATCH: Fix x86 segment register access)
       [not found]           ` <20050330040017.GA29523@lucon.org>
@ 2005-03-30 22:19             ` Linus Torvalds
  2005-03-30 23:24               ` linux-os
  2005-03-31  8:55               ` H. J. Lu
  0 siblings, 2 replies; 12+ messages in thread
From: Linus Torvalds @ 2005-03-30 22:19 UTC (permalink / raw)
  To: H. J. Lu, binutils, GNU C Library; +Cc: Andi Kleen, linux kernel


[ binutils and libc back in the discussion - I don't know why they got 
  dropped ]

On Tue, 29 Mar 2005, H. J. Lu wrote:
> 
> There is no such an instruction of "movl %ds,(%eax)". The old assembler
> accepts it and turns it into "movw %ds,(%eax)".

I disagree. Violently. As does the old assembler, which does not turn 
"mov" into "movw" as you say. AT ALL.

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!)

"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.

According to your logic, the assembler should disallow "orl $5,ax" because
it does the same thing as "or $5,%eax" and "orw $5,%eax", and thus to
"protect" the user, the user should not be able to say the size
explicitly.

The fact is, every single "mov" instruction takes the size hint, and it
HAS MEANING, even if the meaning is only about performance, not about
semantics. In other words, yes, in the specific case of "mov segment to
memory", it ends up being only a performance hit, but as such IT DOES HAVE
MEANING. And in fact, even if it didn't end up having any meaning at all, 
it's still a good idea as just a consistency issue.

Dammit, if I say "orl $5,%eax", I mean "orl $5,%eax", and if the assembler 
complains about it or claims it is the same as "orw $5,%ax", then the 
assembler is fundamentally BROKEN.

None of your arguments have in any way responded to this fact. 

If you think people should use just "mov", then fine, let people use 
"mov". That's their choice - the same way you can write just "or $5,%eax" 
and gas will pick the 32-bit version based on the register name, yes, you 
should be able to write just "mov %fs,mem", and gas will pick whatever 
version using its heuristics for the size (in this case the 32-bit, since 
it does the same thing and is smaller and faster).

And "mov" has always worked. The kernel just doesn't use it much, because 
the kernel - for good historical reasons - doesn't trust gas to pick sizes 
of instructions automagically.

And the fact that it is obvious that gas _should_ pick the 32-bit format
of the instruction when you do not specify a size does NOT MEAN that it's
wrong to specify the size explicitly.

And your arguments that there is no semantic difference between the 16-bit 
and the 32-bit version IS MEANINGLESS. An assembler shouldn't care. This 
is not an argument about semantic difference. This is an argument over a 
user wanting to make the size explicit, to DOCUMENT it.

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), then that is a GOOD THING. It means that the instruction is
well-defined to somebody who knows the x86 instruction set, and he never
needs to worry or use "objdump" to see if gas was being stupid and
generated the 16-bit version.

			Linus

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

* Re: i386/x86_64 segment register issuses (Re: PATCH: Fix x86 segment register access)
  2005-03-30 22:19             ` i386/x86_64 segment register issuses (Re: PATCH: Fix x86 segment register access) Linus Torvalds
@ 2005-03-30 23:24               ` linux-os
  2005-03-31 12:00                 ` H. J. Lu
  2005-03-31  8:55               ` H. J. Lu
  1 sibling, 1 reply; 12+ messages in thread
From: linux-os @ 2005-03-30 23:24 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: H. J. Lu, binutils, GNU C Library, Andi Kleen, linux kernel

On Wed, 30 Mar 2005, Linus Torvalds wrote:

>
> [ binutils and libc back in the discussion - I don't know why they got
>  dropped ]
>
> On Tue, 29 Mar 2005, H. J. Lu wrote:
>>
>> There is no such an instruction of "movl %ds,(%eax)". The old assembler
>> accepts it and turns it into "movw %ds,(%eax)".
>
> I disagree. Violently. As does the old assembler, which does not turn
> "mov" into "movw" as you say. AT ALL.
>
> 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!)
>
> "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.
>
> According to your logic, the assembler should disallow "orl $5,ax" because
> it does the same thing as "or $5,%eax" and "orw $5,%eax", and thus to
> "protect" the user, the user should not be able to say the size
> explicitly.
>
> The fact is, every single "mov" instruction takes the size hint, and it
> HAS MEANING, even if the meaning is only about performance, not about
> semantics. In other words, yes, in the specific case of "mov segment to
> memory", it ends up being only a performance hit, but as such IT DOES HAVE
> MEANING. And in fact, even if it didn't end up having any meaning at all,
> it's still a good idea as just a consistency issue.
>
> Dammit, if I say "orl $5,%eax", I mean "orl $5,%eax", and if the assembler
> complains about it or claims it is the same as "orw $5,%ax", then the
> assembler is fundamentally BROKEN.
>
> None of your arguments have in any way responded to this fact.
>
> If you think people should use just "mov", then fine, let people use
> "mov". That's their choice - the same way you can write just "or $5,%eax"
> and gas will pick the 32-bit version based on the register name, yes, you
> should be able to write just "mov %fs,mem", and gas will pick whatever
> version using its heuristics for the size (in this case the 32-bit, since
> it does the same thing and is smaller and faster).
>
> And "mov" has always worked. The kernel just doesn't use it much, because
> the kernel - for good historical reasons - doesn't trust gas to pick sizes
> of instructions automagically.
>
> And the fact that it is obvious that gas _should_ pick the 32-bit format
> of the instruction when you do not specify a size does NOT MEAN that it's
> wrong to specify the size explicitly.
>
> And your arguments that there is no semantic difference between the 16-bit
> and the 32-bit version IS MEANINGLESS. An assembler shouldn't care. This
> is not an argument about semantic difference. This is an argument over a
> user wanting to make the size explicit, to DOCUMENT it.
>
> 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), then that is a GOOD THING. It means that the instruction is
> well-defined to somebody who knows the x86 instruction set, and he never
> needs to worry or use "objdump" to see if gas was being stupid and
> generated the 16-bit version.
>
> 			Linus
> -


We went over this stuff when we first started using the
Intel 486. (Ref Intel 486 Microprocessor Programmers
reference manual, ISBN 1-55512-192-4)

Segment registers are really 32 bits in length. They
have a 'visible' part and an invisible part. The
visible part contains the 16-bit selector. The
invisible part contains the base address, limit,
etc., that was loaded from the GDT or the LDT.
(Ref. pp 5-9)

All access to these registers is 32 bits. If you
execute	'push ds' or 'pop ds' the stack-pointer
will move 4 bytes. An 0x66 override prefix is
ignored when accessing segment registers. It
should never be used. There is another override
prefix that can be used instead. The push ds
opcode is 0x1e and the pop ds opcode is 0x1f
if somebody wants to experiment.

Even a move from a CPU general purpose register
to a segment register is a 32-bit operation. If
you want to move the contents of a segment register
to memory or a register as a 16-bit action, for
instance not overwriting the high-word of a register,
the override prefix is 0x67, not 0x66. (Ref. pp 26-210)

This means that segment values stored in memory 
should really be aligned on 32-bit boundaries
so that extra clock-cycles are not wasted
accessing these registers. This also means
that they should be treated as (Posix) uint32_t
not uint16_t, even though the value will never
exceed 8192.

So if there are any "movw (mem), %ds" and
"movw %ds, (mem)" in the code. The sizeof(mem)
needs to be 32-bits and the 'w' needs to be removed.
Otherwise, we are wasting CPU cycles and/or fooling
ourselves. GAS needs to continue to generate whatever
it was fed, with appropriate diagnostics if it
is fed the wrong stuff.


Cheers,
Dick Johnson
Penguin : Linux version 2.6.11 on an i686 machine (5537.79 BogoMips).
  Notice : All mail here is now cached for review by Dictator Bush.
                  98.36% of all statistics are fiction.

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

* Re: i386/x86_64 segment register issuses (Re: PATCH: Fix x86 segment register access)
  2005-03-30 22:19             ` i386/x86_64 segment register issuses (Re: PATCH: Fix x86 segment register access) Linus Torvalds
  2005-03-30 23:24               ` linux-os
@ 2005-03-31  8:55               ` H. J. Lu
  2005-03-31 13:27                 ` Pau Aliagas
  1 sibling, 1 reply; 12+ messages in thread
From: H. J. Lu @ 2005-03-31  8:55 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: binutils, Andi Kleen, linux kernel

On Wed, Mar 30, 2005 at 07:57:28AM -0800, Linus Torvalds wrote:
> 
> [ binutils and libc back in the discussion - I don't know why they got 
>   dropped ]

Removing glibc since it accesses segment register with proper
instructions.

> 
> On Tue, 29 Mar 2005, H. J. Lu wrote:
> > 
> > There is no such an instruction of "movl %ds,(%eax)". The old assembler
> > accepts it and turns it into "movw %ds,(%eax)".
> 
> I disagree. Violently. As does the old assembler, which does not turn 
> "mov" into "movw" as you say. AT ALL.

I should have made myself clear. By "movw %ds,(%eax)", I meant:

	8c 18	movw   %ds,(%eax)

That is what the assembler generates, and should have generated, for
"movw %ds,(%eax)" since Nov. 4, 2004.

> 
> 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!)

This is a bug in asssembler and has been fixed on Nov. 4, 2004. If
you want the 0x66 prefix for "movw %ds,(%eax)", you need to use
"word movw %ds,(%eax)" with the new assembler.

> 
> The fact is, every single "mov" instruction takes the size hint, and it
> HAS MEANING, even if the meaning is only about performance, not about
> semantics. In other words, yes, in the specific case of "mov segment to
> memory", it ends up being only a performance hit, but as such IT DOES HAVE
> MEANING. And in fact, even if it didn't end up having any meaning at all, 
> it's still a good idea as just a consistency issue.

Accessing segment register is a very special case. It has been treated
differently by gas. Try "movw (%eax),%ds" with your gas. Gas doesn't
generate 0x66. The "movw %ds,(%eax)" bug was fixed last year.

> If you think people should use just "mov", then fine, let people use 

I only suggested "mov" for old assemblers.

> "mov". That's their choice - the same way you can write just "or $5,%eax" 
> and gas will pick the 32-bit version based on the register name, yes, you 
> should be able to write just "mov %fs,mem", and gas will pick whatever 
> version using its heuristics for the size (in this case the 32-bit, since 
> it does the same thing and is smaller and faster).
> 
> And "mov" has always worked. The kernel just doesn't use it much, because 
> the kernel - for good historical reasons - doesn't trust gas to pick sizes 
> of instructions automagically.
> 
> And the fact that it is obvious that gas _should_ pick the 32-bit format
> of the instruction when you do not specify a size does NOT MEAN that it's
> wrong to specify the size explicitly.
> 
> And your arguments that there is no semantic difference between the 16-bit 
> and the 32-bit version IS MEANINGLESS. An assembler shouldn't care. This 

For segment register access, there is no 16-bit nor 32-bit version.
There is only one version.

> is not an argument about semantic difference. This is an argument over a 
> user wanting to make the size explicit, to DOCUMENT it.

Are you suggesting that gas should put back 0x66 for both
"movw %ds,(%eax)" and "movw (%eax),%ds"?

> 
> 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), then that is a GOOD THING. It means that the instruction is
> well-defined to somebody who knows the x86 instruction set, and he never
> needs to worry or use "objdump" to see if gas was being stupid and
> generated the 16-bit version.

Allowing "movl %ds,(%eax)" has a possibilty that people assume it will
update 32bit memory location. That is how this issue was uncovered.
If you really don't like "mov %ds,(%eax)" and want to support the
old assembler, I can write a kernel patch to check asssembler to
use "movl" for the old asssembler and "movw" for the new assembler.

BTW, to report problems with assembler, there is

http://www.sourceware.org/bugzilla/

Or I can be reached at hjl@lucon.org.


H.J.

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

* Re: i386/x86_64 segment register issuses (Re: PATCH: Fix x86 segment register access)
  2005-03-30 23:24               ` linux-os
@ 2005-03-31 12:00                 ` H. J. Lu
  0 siblings, 0 replies; 12+ messages in thread
From: H. J. Lu @ 2005-03-31 12:00 UTC (permalink / raw)
  To: linux-os; +Cc: Linus Torvalds, binutils, Andi Kleen, linux kernel

On Wed, Mar 30, 2005 at 11:23:25AM -0500, linux-os wrote:
> 
> So if there are any "movw (mem), %ds" and
> "movw %ds, (mem)" in the code. The sizeof(mem)
> needs to be 32-bits and the 'w' needs to be removed.
> Otherwise, we are wasting CPU cycles and/or fooling
> ourselves. GAS needs to continue to generate whatever
> it was fed, with appropriate diagnostics if it
> is fed the wrong stuff.

FYI, gas hasn't generated 0x66 on "movw (%eax),%ds" for a long time
and started doing it on "movw %ds,(%eax)" since Nov. 4, 2004.


H.J.

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

* Re: i386/x86_64 segment register issuses (Re: PATCH: Fix x86 segment register access)
  2005-03-31  8:55               ` H. J. Lu
@ 2005-03-31 13:27                 ` Pau Aliagas
  2005-03-31 15:05                   ` H. J. Lu
  2005-03-31 15:37                   ` Andi Kleen
  0 siblings, 2 replies; 12+ messages in thread
From: Pau Aliagas @ 2005-03-31 13:27 UTC (permalink / raw)
  To: Andi Kleen, linux kernel; +Cc: binutils

On Wed, 30 Mar 2005, H. J. Lu wrote:

> On Wed, Mar 30, 2005 at 07:57:28AM -0800, Linus Torvalds wrote:

>>> There is no such an instruction of "movl %ds,(%eax)". The old assembler
>>> accepts it and turns it into "movw %ds,(%eax)".
>>
>> I disagree. Violently. As does the old assembler, which does not turn
>> "mov" into "movw" as you say. AT ALL.
>
> I should have made myself clear. By "movw %ds,(%eax)", I meant:
>
> 	8c 18	movw   %ds,(%eax)
>
> That is what the assembler generates, and should have generated, for
> "movw %ds,(%eax)" since Nov. 4, 2004.

Could this be the reason for the reported slowdown in the last six months?

-- 

Pau

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

* Re: i386/x86_64 segment register issuses (Re: PATCH: Fix x86 segment register access)
  2005-03-31 13:27                 ` Pau Aliagas
@ 2005-03-31 15:05                   ` H. J. Lu
  2005-03-31 15:05                     ` Pau Aliagas
  2005-03-31 15:37                   ` Andi Kleen
  1 sibling, 1 reply; 12+ messages in thread
From: H. J. Lu @ 2005-03-31 15:05 UTC (permalink / raw)
  To: Pau Aliagas; +Cc: Andi Kleen, linux kernel, binutils

On Thu, Mar 31, 2005 at 12:18:55AM +0200, Pau Aliagas wrote:
> On Wed, 30 Mar 2005, H. J. Lu wrote:
> 
> >On Wed, Mar 30, 2005 at 07:57:28AM -0800, Linus Torvalds wrote:
> 
> >>>There is no such an instruction of "movl %ds,(%eax)". The old assembler
> >>>accepts it and turns it into "movw %ds,(%eax)".
> >>
> >>I disagree. Violently. As does the old assembler, which does not turn
> >>"mov" into "movw" as you say. AT ALL.
> >
> >I should have made myself clear. By "movw %ds,(%eax)", I meant:
> >
> >	8c 18	movw   %ds,(%eax)
> >
> >That is what the assembler generates, and should have generated, for
> >"movw %ds,(%eax)" since Nov. 4, 2004.
> 
> Could this be the reason for the reported slowdown in the last six months?
> 

Can you elaborate?


H.J.

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

* Re: i386/x86_64 segment register issuses (Re: PATCH: Fix x86 segment register access)
  2005-03-31 15:05                   ` H. J. Lu
@ 2005-03-31 15:05                     ` Pau Aliagas
  2005-03-31 15:07                       ` H. J. Lu
  0 siblings, 1 reply; 12+ messages in thread
From: Pau Aliagas @ 2005-03-31 15:05 UTC (permalink / raw)
  To: lkml; +Cc: H. J. Lu, Andi Kleen, binutils

On Wed, 30 Mar 2005, H. J. Lu wrote:

>>> That is what the assembler generates, and should have generated, for
>>> "movw %ds,(%eax)" since Nov. 4, 2004.
>>
>> Could this be the reason for the reported slowdown in the last six months?
>
> Can you elaborate?

There's an unexplained slowdown of kernel 2.6 detailed in this thread:
http://kerneltrap.org/node/4940

I don't want at all to justify it with the change you talk about in gas, 
but maybe it is worth to check if it has anything to do with it. The 
slowdown happened in this last six months.

-- 

Pau

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

* Re: i386/x86_64 segment register issuses (Re: PATCH: Fix x86 segment register access)
  2005-03-31 15:05                     ` Pau Aliagas
@ 2005-03-31 15:07                       ` H. J. Lu
  0 siblings, 0 replies; 12+ messages in thread
From: H. J. Lu @ 2005-03-31 15:07 UTC (permalink / raw)
  To: Pau Aliagas; +Cc: lkml, Andi Kleen, binutils

On Thu, Mar 31, 2005 at 02:57:57AM +0200, Pau Aliagas wrote:
> On Wed, 30 Mar 2005, H. J. Lu wrote:
> 
> >>>That is what the assembler generates, and should have generated, for
> >>>"movw %ds,(%eax)" since Nov. 4, 2004.
> >>
> >>Could this be the reason for the reported slowdown in the last six months?
> >
> >Can you elaborate?
> 
> There's an unexplained slowdown of kernel 2.6 detailed in this thread:
> http://kerneltrap.org/node/4940
> 

It is dated as "November 13, 2002 - 13:58". The assembler change was
made on Nov. 4, 2004. I don't think they are related at all.

> I don't want at all to justify it with the change you talk about in gas, 
> but maybe it is worth to check if it has anything to do with it. The 
> slowdown happened in this last six months.


H.J.

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

* Re: i386/x86_64 segment register issuses (Re: PATCH: Fix x86 segment register access)
  2005-03-31 13:27                 ` Pau Aliagas
  2005-03-31 15:05                   ` H. J. Lu
@ 2005-03-31 15:37                   ` Andi Kleen
  1 sibling, 0 replies; 12+ messages in thread
From: Andi Kleen @ 2005-03-31 15:37 UTC (permalink / raw)
  To: Pau Aliagas; +Cc: linux kernel, binutils

> >That is what the assembler generates, and should have generated, for
> >"movw %ds,(%eax)" since Nov. 4, 2004.
> 
> Could this be the reason for the reported slowdown in the last six months?

No.

-Andi

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

end of thread, other threads:[~2005-03-31 10:23 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2005-03-26 23:31 PATCH: Fix x86 segment register access H. J. Lu
2005-03-28 10:21 ` i386/x86_64 segment register issuses (Re: PATCH: Fix x86 segment register access) H. J. Lu
2005-03-30  9:46   ` PATCH: i386/x86_64 segment register access update H. J. Lu
     [not found]   ` <m14qev3h8l.fsf@muc.de>
     [not found]     ` <Pine.LNX.4.58.0503291618520.6036@ppc970.osdl.org>
     [not found]       ` <20050330015312.GA27309@lucon.org>
     [not found]         ` <Pine.LNX.4.58.0503291815570.6036@ppc970.osdl.org>
     [not found]           ` <20050330040017.GA29523@lucon.org>
2005-03-30 22:19             ` i386/x86_64 segment register issuses (Re: PATCH: Fix x86 segment register access) Linus Torvalds
2005-03-30 23:24               ` linux-os
2005-03-31 12:00                 ` H. J. Lu
2005-03-31  8:55               ` H. J. Lu
2005-03-31 13:27                 ` Pau Aliagas
2005-03-31 15:05                   ` H. J. Lu
2005-03-31 15:05                     ` Pau Aliagas
2005-03-31 15:07                       ` H. J. Lu
2005-03-31 15:37                   ` Andi Kleen

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).