Add support for 16 bit pushes and pops of segment registers to
fix bug #76762.


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@2288 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/vg_to_ucode.c b/coregrind/vg_to_ucode.c
index 91f9514..7feaf7d 100644
--- a/coregrind/vg_to_ucode.c
+++ b/coregrind/vg_to_ucode.c
@@ -3745,11 +3745,11 @@
 void dis_push_segreg ( UCodeBlock* cb, UInt sreg, Int sz )
 {
     Int t1 = newTemp(cb), t2 = newTemp(cb);
-    vg_assert(sz == 4);
+    vg_assert(sz == 2 || sz == 4);
     uInstr2(cb, GETSEG, 2, ArchRegS, sreg,  TempReg, t1);
     uInstr2(cb, GET,    4, ArchReg,  R_ESP, TempReg, t2);
     uInstr2(cb, SUB,    4, Literal,  0,     TempReg, t2);
-    uLiteral(cb, 4);
+    uLiteral(cb, sz);
     uInstr2(cb, PUT,    4, TempReg,  t2,    ArchReg, R_ESP);
     uInstr2(cb, STORE,  2, TempReg,  t1,    TempReg, t2);
     DIP("push %s\n", VG_(name_of_seg_reg)(sreg));
@@ -3759,7 +3759,7 @@
 void dis_pop_segreg ( UCodeBlock* cb, UInt sreg, Int sz )
 {
    Int t1 = newTemp(cb), t2 = newTemp(cb);
-   vg_assert(sz == 4);
+   vg_assert(sz == 2 || sz == 4);
    uInstr2(cb, GET,    4, ArchReg, R_ESP,    TempReg,  t2);
    uInstr2(cb, LOAD,   2, TempReg, t2,       TempReg,  t1);
    uInstr2(cb, ADD,    4, Literal, 0,        TempReg,  t2);
diff --git a/none/tests/.cvsignore b/none/tests/.cvsignore
index 30e56fb..97a4e6e 100644
--- a/none/tests/.cvsignore
+++ b/none/tests/.cvsignore
@@ -56,6 +56,7 @@
 pth_simple_threads
 pth_specific
 pth_yield
+pushpopseg
 *.stdout.diff
 *.stderr.diff
 *.stdout.out
diff --git a/none/tests/Makefile.am b/none/tests/Makefile.am
index 6eafdc8..6709261 100644
--- a/none/tests/Makefile.am
+++ b/none/tests/Makefile.am
@@ -36,6 +36,7 @@
 	munmap_exe.stderr.exp munmap_exe.vgtest \
 	pth_blockedsig.stderr.exp \
 	pth_blockedsig.stdout.exp pth_blockedsig.vgtest \
+	pushpopseg.stderr.exp pushpopseg.stdout.exp pushpopseg.vgtest \
 	rcl_assert.stderr.exp rcl_assert.vgtest \
 	rcrl.stderr.exp rcrl.stdout.exp rcrl.vgtest \
 	readline1.stderr.exp readline1.stdout.exp \
@@ -59,7 +60,7 @@
 	fucomip insn_basic insn_cmov insn_mmx insn_mmxext insn_sse insn_sse2 \
 	munmap_exe map_unmap mremap rcl_assert \
 	rcrl readline1 resolv seg_override sha1_test shortpush shorts smc1 \
-	pth_blockedsig \
+	pth_blockedsig pushpopseg \
 	syscall-restart1 syscall-restart2 system \
 	coolo_sigaction gxx304 yield
 
@@ -97,6 +98,7 @@
 map_unmap_SOURCES	= map_unmap.c
 mremap_SOURCES		= mremap.c
 munmap_exe_SOURCES 	= munmap_exe.c
+pushpopseg_SOURCES	= pushpopseg.c
 rcl_assert_SOURCES 	= rcl_assert.S
 rcrl_SOURCES 		= rcrl.c
 readline1_SOURCES 	= readline1.c
diff --git a/none/tests/pushpopseg.c b/none/tests/pushpopseg.c
new file mode 100644
index 0000000..b79066a
--- /dev/null
+++ b/none/tests/pushpopseg.c
@@ -0,0 +1,47 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char **argv)
+{
+  unsigned long  sp1;
+  unsigned long  sp2;
+  unsigned long  sp3;
+  unsigned short fs1;
+  unsigned short fs2;
+
+  fs1 = 0x0003;
+  
+  asm("movw %4, %%fs\n"
+      "movl %%esp, %0\n"
+      "pushw %%fs\n"
+      "movl %%esp, %1\n"
+      "popw %%fs\n"
+      "movl %%esp, %2\n"
+      "movw %%fs, %3\n"
+      : "=m" (sp1), "=m" (sp2), "=m" (sp3), "=m" (fs2)
+      : "m" (fs1)
+      : "ax"
+      );
+
+  printf("sp change after push = %d\n", sp2 - sp1);
+  printf("sp change after pop = %d\n", sp3 - sp2);
+  printf("fs after push and pop = %04x\n", fs1);
+   
+  asm("movw %4, %%fs\n"
+      "movl %%esp, %0\n"
+      "pushl %%fs\n"
+      "movl %%esp, %1\n"
+      "popl %%fs\n"
+      "movl %%esp, %2\n"
+      "movw %%fs, %3\n"
+      : "=m" (sp1), "=m" (sp2), "=m" (sp3), "=m" (fs2)
+      : "m" (fs1)
+      : "ax"
+      );
+
+  printf("sp change after push = %d\n", sp2 - sp1);
+  printf("sp change after pop = %d\n", sp3 - sp2);
+  printf("fs after push and pop = %04x\n", fs1);
+ 
+  exit(0);
+}
diff --git a/none/tests/pushpopseg.stderr.exp b/none/tests/pushpopseg.stderr.exp
new file mode 100644
index 0000000..139597f
--- /dev/null
+++ b/none/tests/pushpopseg.stderr.exp
@@ -0,0 +1,2 @@
+
+
diff --git a/none/tests/pushpopseg.stdout.exp b/none/tests/pushpopseg.stdout.exp
new file mode 100644
index 0000000..d1cffa5
--- /dev/null
+++ b/none/tests/pushpopseg.stdout.exp
@@ -0,0 +1,6 @@
+sp change after push = -2
+sp change after pop = 2
+fs after push and pop = 0003
+sp change after push = -4
+sp change after pop = 4
+fs after push and pop = 0003
diff --git a/none/tests/pushpopseg.vgtest b/none/tests/pushpopseg.vgtest
new file mode 100644
index 0000000..976bc27
--- /dev/null
+++ b/none/tests/pushpopseg.vgtest
@@ -0,0 +1 @@
+prog: pushpopseg