This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Alternative libio vtable hardening approach


I have implemented a completely different approach to vtable hardening.

The basic idea is to put all libc vtables into a single array, and then check whether the vtable pointer is within that array.

There is a new flag, IO_accept_foreign_vtables, which is initially false and set to true to indicate that vtables may have been defined outside of libc. This allows us to preserve full backwards compatibility.

The attached patch is not completely finished. We need to disable vtable validation on both sides of a static dlopen boundary because the vtables are not shared across the boundary. This is what causes dlfcn/tststatic2 to fail. We also may have to set the IO_accept_foreign_vtables flag for additional constructor functions (although _IO_file_init may be sufficient, based on what I have seen in GCC).

A future optimization would change the virtual function calls to compare the function pointer in the vtable against an expected function pointer. Only if that comparison fails, the vtable pointer is validated. This will allow us to inline parts of xsputn into vfprintf, especially if we change the various implementations to share more code.

At this point, I'm mainly interested in comments whether the use of the flag is acceptable from a security perspective. I expect that if you can set the flag and overwrite vtable pointers, you already have substantial control over what the process does. It is also likely that you would able to reset the pointer guard variable, disabling the hardening in Kees' patch.

Florian
diff --git a/debug/obprintf_chk.c b/debug/obprintf_chk.c
index 8469b5f..5e319ff 100644
--- a/debug/obprintf_chk.c
+++ b/debug/obprintf_chk.c
@@ -35,8 +35,6 @@ struct _IO_obstack_file
   struct obstack *obstack;
 };
 
-extern const struct _IO_jump_t _IO_obstack_jumps attribute_hidden;
-
 int
 __obstack_vprintf_chk (struct obstack *obstack, int flags, const char *format,
 		       va_list args)
@@ -54,7 +52,7 @@ __obstack_vprintf_chk (struct obstack *obstack, int flags, const char *format,
 #endif
 
   _IO_no_init (&new_f.ofile.file.file, _IO_USER_LOCK, -1, NULL, NULL);
-  _IO_JUMPS (&new_f.ofile.file) = &_IO_obstack_jumps;
+  _IO_JUMPS (&new_f.ofile.file) = &IO_vtables[IO_VTABLE_obstack];
   room = obstack_room (obstack);
   size = obstack_object_size (obstack) + room;
   if (size == 0)
diff --git a/debug/vasprintf_chk.c b/debug/vasprintf_chk.c
index cb1f74a..f512c17 100644
--- a/debug/vasprintf_chk.c
+++ b/debug/vasprintf_chk.c
@@ -52,7 +52,7 @@ __vasprintf_chk (char **result_ptr, int flags, const char *format,
   sf._sbf._f._lock = NULL;
 #endif
   _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
-  _IO_JUMPS (&sf._sbf) = &_IO_str_jumps;
+  _IO_JUMPS (&sf._sbf) = &IO_vtables[IO_VTABLE_str];
   _IO_str_init_static_internal (&sf, string, init_string_size, string);
   sf._sbf._f._flags &= ~_IO_USER_BUF;
   sf._s._allocate_buffer = (_IO_alloc_type) malloc;
diff --git a/debug/vdprintf_chk.c b/debug/vdprintf_chk.c
index 05d0bcd..73797e9 100644
--- a/debug/vdprintf_chk.c
+++ b/debug/vdprintf_chk.c
@@ -37,9 +37,10 @@ __vdprintf_chk (int d, int flags, const char *format, va_list arg)
 #ifdef _IO_MTSAFE_IO
   tmpfil.file._lock = NULL;
 #endif
-  _IO_no_init (&tmpfil.file, _IO_USER_LOCK, 0, &wd, &_IO_wfile_jumps);
-  _IO_JUMPS (&tmpfil) = &_IO_file_jumps;
-  _IO_file_init (&tmpfil);
+  _IO_no_init (&tmpfil.file, _IO_USER_LOCK, 0, &wd,
+	       &IO_vtables[IO_VTABLE_wfile]);
+  _IO_JUMPS (&tmpfil) = &IO_vtables[IO_VTABLE_file];
+  _IO_file_init_internal (&tmpfil);
 #if  !_IO_UNIFIED_JUMPTABLES
   tmpfil.vtable = NULL;
 #endif
diff --git a/debug/vsnprintf_chk.c b/debug/vsnprintf_chk.c
index cc559d2..f3cc332 100644
--- a/debug/vsnprintf_chk.c
+++ b/debug/vsnprintf_chk.c
@@ -20,8 +20,6 @@
 #include "../libio/libioP.h"
 #include "../libio/strfile.h"
 
-extern const struct _IO_jump_t _IO_strn_jumps attribute_hidden;
-
 /* Write formatted output into S, according to the format
    string FORMAT, writing no more than MAXLEN characters.  */
 /* VARARGS5 */
@@ -51,7 +49,7 @@ ___vsnprintf_chk (char *s, size_t maxlen, int flags, size_t slen,
     }
 
   _IO_no_init (&sf.f._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
-  _IO_JUMPS (&sf.f._sbf) = &_IO_strn_jumps;
+  _IO_JUMPS (&sf.f._sbf) = &IO_vtables[IO_VTABLE_strn];
   s[0] = '\0';
 
   /* For flags > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
diff --git a/debug/vsprintf_chk.c b/debug/vsprintf_chk.c
index aa1587c..e184ebd 100644
--- a/debug/vsprintf_chk.c
+++ b/debug/vsprintf_chk.c
@@ -20,10 +20,7 @@
 #include "../libio/libioP.h"
 #include "../libio/strfile.h"
 
-
-static int _IO_str_chk_overflow (_IO_FILE *fp, int c) __THROW;
-
-static int
+int
 _IO_str_chk_overflow (_IO_FILE *fp, int c)
 {
   /* When we come to here this means the user supplied buffer is
@@ -31,32 +28,6 @@ _IO_str_chk_overflow (_IO_FILE *fp, int c)
   __chk_fail ();
 }
 
-
-static const struct _IO_jump_t _IO_str_chk_jumps =
-{
-  JUMP_INIT_DUMMY,
-  JUMP_INIT(finish, _IO_str_finish),
-  JUMP_INIT(overflow, _IO_str_chk_overflow),
-  JUMP_INIT(underflow, _IO_str_underflow),
-  JUMP_INIT(uflow, _IO_default_uflow),
-  JUMP_INIT(pbackfail, _IO_str_pbackfail),
-  JUMP_INIT(xsputn, _IO_default_xsputn),
-  JUMP_INIT(xsgetn, _IO_default_xsgetn),
-  JUMP_INIT(seekoff, _IO_str_seekoff),
-  JUMP_INIT(seekpos, _IO_default_seekpos),
-  JUMP_INIT(setbuf, _IO_default_setbuf),
-  JUMP_INIT(sync, _IO_default_sync),
-  JUMP_INIT(doallocate, _IO_default_doallocate),
-  JUMP_INIT(read, _IO_default_read),
-  JUMP_INIT(write, _IO_default_write),
-  JUMP_INIT(seek, _IO_default_seek),
-  JUMP_INIT(close, _IO_default_close),
-  JUMP_INIT(stat, _IO_default_stat),
-  JUMP_INIT(showmanyc, _IO_default_showmanyc),
-  JUMP_INIT(imbue, _IO_default_imbue)
-};
-
-
 int
 ___vsprintf_chk (char *s, int flags, size_t slen, const char *format,
 		 va_list args)
@@ -71,7 +42,7 @@ ___vsprintf_chk (char *s, int flags, size_t slen, const char *format,
     __chk_fail ();
 
   _IO_no_init (&f._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
-  _IO_JUMPS (&f._sbf) = &_IO_str_chk_jumps;
+  _IO_JUMPS (&f._sbf) = &IO_vtables[IO_VTABLE_str_chk];
   s[0] = '\0';
   _IO_str_init_static_internal (&f, s, slen - 1, s);
 
diff --git a/debug/vswprintf_chk.c b/debug/vswprintf_chk.c
index 50bdb78..6bdb16f 100644
--- a/debug/vswprintf_chk.c
+++ b/debug/vswprintf_chk.c
@@ -49,7 +49,8 @@ __vswprintf_chk (wchar_t *s, size_t maxlen, int flags, size_t slen,
        length of zero always makes the function fail.  */
     return -1;
 
-  _IO_no_init (&sf.f._sbf._f, _IO_USER_LOCK, 0, &wd, &_IO_wstrn_jumps);
+  _IO_no_init (&sf.f._sbf._f, _IO_USER_LOCK, 0, &wd,
+	       &IO_vtables[IO_VTABLE_wstrn]);
   _IO_fwide (&sf.f._sbf._f, 1);
   s[0] = L'\0';
 
diff --git a/libio/Makefile b/libio/Makefile
index 4189bc4..12589f2 100644
--- a/libio/Makefile
+++ b/libio/Makefile
@@ -46,7 +46,7 @@ routines	:=							      \
 	__fbufsize __freading __fwriting __freadable __fwritable __flbf	      \
 	__fpurge __fpending __fsetlocking				      \
 									      \
-	libc_fatal fmemopen oldfmemopen
+	libc_fatal fmemopen oldfmemopen vtables
 
 tests = tst_swprintf tst_wprintf tst_swscanf tst_wscanf tst_getwc tst_putwc   \
 	tst_wprintf2 tst-widetext test-fmemopen tst-ext tst-ext2 \
diff --git a/libio/fileops.c b/libio/fileops.c
index 8e83b1c..4ccd3b7 100644
--- a/libio/fileops.c
+++ b/libio/fileops.c
@@ -140,7 +140,7 @@ extern struct __gconv_trans_data __libio_translit attribute_hidden;
 
 
 void
-_IO_new_file_init (struct _IO_FILE_plus *fp)
+_IO_file_init_internal (struct _IO_FILE_plus *fp)
 {
   /* POSIX.1 allows another file handle to be used to change the position
      of our file descriptor.  Hence we actually don't know the actual
@@ -151,7 +151,16 @@ _IO_new_file_init (struct _IO_FILE_plus *fp)
   _IO_link_in (fp);
   fp->file._fileno = -1;
 }
-libc_hidden_ver (_IO_new_file_init, _IO_file_init)
+
+/* Externally accessible constructor for _IO_FILE objects.  */
+void
+_IO_new_file_init (struct _IO_FILE_plus *fp)
+{
+  _IO_file_init_internal (fp);
+  /* The vtable is supplied by the caller, so we have to disable
+     validation.  */
+  IO_accept_foreign_vtables = true;
+}
 
 int
 _IO_new_file_close_it (_IO_FILE *fp)
@@ -466,8 +475,8 @@ _IO_file_setbuf_mmap (_IO_FILE *fp, char *p, _IO_ssize_t len)
   _IO_FILE *result;
 
   /* Change the function table.  */
-  _IO_JUMPS_FILE_plus (fp) = &_IO_file_jumps;
-  fp->_wide_data->_wide_vtable = &_IO_wfile_jumps;
+  _IO_JUMPS_FILE_plus (fp) = &IO_vtables[IO_VTABLE_file];
+  fp->_wide_data->_wide_vtable = &IO_vtables[IO_VTABLE_wfile];
 
   /* And perform the normal operation.  */
   result = _IO_new_file_setbuf (fp, p, len);
@@ -475,8 +484,8 @@ _IO_file_setbuf_mmap (_IO_FILE *fp, char *p, _IO_ssize_t len)
   /* If the call failed, restore to using mmap.  */
   if (result == NULL)
     {
-      _IO_JUMPS_FILE_plus (fp) = &_IO_file_jumps_mmap;
-      fp->_wide_data->_wide_vtable = &_IO_wfile_jumps_mmap;
+      _IO_JUMPS_FILE_plus (fp) = &IO_vtables[IO_VTABLE_file_mmap];
+      fp->_wide_data->_wide_vtable = &IO_vtables[IO_VTABLE_wfile_mmap];
     }
 
   return result;
@@ -703,10 +712,10 @@ mmap_remap_check (_IO_FILE *fp)
       fp->_IO_buf_base = fp->_IO_buf_end = NULL;
       _IO_setg (fp, NULL, NULL, NULL);
       if (fp->_mode <= 0)
-	_IO_JUMPS_FILE_plus (fp) = &_IO_file_jumps;
+	_IO_JUMPS_FILE_plus (fp) = &IO_vtables[IO_VTABLE_file];
       else
-	_IO_JUMPS_FILE_plus (fp) = &_IO_wfile_jumps;
-      fp->_wide_data->_wide_vtable = &_IO_wfile_jumps;
+	_IO_JUMPS_FILE_plus (fp) = &IO_vtables[IO_VTABLE_wfile];
+      fp->_wide_data->_wide_vtable = &IO_vtables[IO_VTABLE_wfile];
 
       return 1;
     }
@@ -773,10 +782,10 @@ decide_maybe_mmap (_IO_FILE *fp)
 	      fp->_offset = st.st_size;
 
 	      if (fp->_mode <= 0)
-		_IO_JUMPS_FILE_plus (fp) = &_IO_file_jumps_mmap;
+		_IO_JUMPS_FILE_plus (fp) = &IO_vtables[IO_VTABLE_file_mmap];
 	      else
-		_IO_JUMPS_FILE_plus (fp) = &_IO_wfile_jumps_mmap;
-	      fp->_wide_data->_wide_vtable = &_IO_wfile_jumps_mmap;
+		_IO_JUMPS_FILE_plus (fp) = &IO_vtables[IO_VTABLE_wfile_mmap];
+	      fp->_wide_data->_wide_vtable = &IO_vtables[IO_VTABLE_wfile_mmap];
 
 	      return;
 	    }
@@ -786,10 +795,10 @@ decide_maybe_mmap (_IO_FILE *fp)
   /* We couldn't use mmap, so revert to the vanilla file operations.  */
 
   if (fp->_mode <= 0)
-    _IO_JUMPS_FILE_plus (fp) = &_IO_file_jumps;
+    _IO_JUMPS_FILE_plus (fp) = &IO_vtables[IO_VTABLE_file];
   else
-    _IO_JUMPS_FILE_plus (fp) = &_IO_wfile_jumps;
-  fp->_wide_data->_wide_vtable = &_IO_wfile_jumps;
+    _IO_JUMPS_FILE_plus (fp) = &IO_vtables[IO_VTABLE_wfile];
+  fp->_wide_data->_wide_vtable = &IO_vtables[IO_VTABLE_wfile];
 }
 
 int
@@ -897,7 +906,7 @@ _IO_new_file_sync (_IO_FILE *fp)
 }
 libc_hidden_ver (_IO_new_file_sync, _IO_file_sync)
 
-static int
+int
 _IO_file_sync_mmap (_IO_FILE *fp)
 {
   if (fp->_IO_read_ptr != fp->_IO_read_end)
@@ -1192,7 +1201,7 @@ _IO_file_seekoff_mmap (_IO_FILE *fp, _IO_off64_t offset, int dir, int mode)
   return offset;
 }
 
-static _IO_off64_t
+_IO_off64_t
 _IO_file_seekoff_maybe_mmap (_IO_FILE *fp, _IO_off64_t offset, int dir,
 			     int mode)
 {
@@ -1453,7 +1462,7 @@ _IO_file_xsgetn (_IO_FILE *fp, void *data, _IO_size_t n)
 }
 libc_hidden_def (_IO_file_xsgetn)
 
-static _IO_size_t
+_IO_size_t
 _IO_file_xsgetn_mmap (_IO_FILE *fp, void *data, _IO_size_t n)
 {
   _IO_size_t have;
@@ -1508,7 +1517,7 @@ _IO_file_xsgetn_mmap (_IO_FILE *fp, void *data, _IO_size_t n)
   return s - (char *) data;
 }
 
-static _IO_size_t
+_IO_size_t
 _IO_file_xsgetn_maybe_mmap (_IO_FILE *fp, void *data, _IO_size_t n)
 {
   /* We only get here if this is the first attempt to read something.
@@ -1533,76 +1542,3 @@ versioned_symbol (libc, _IO_new_file_underflow, _IO_file_underflow, GLIBC_2_1);
 versioned_symbol (libc, _IO_new_file_write, _IO_file_write, GLIBC_2_1);
 versioned_symbol (libc, _IO_new_file_xsputn, _IO_file_xsputn, GLIBC_2_1);
 #endif
-
-const struct _IO_jump_t _IO_file_jumps =
-{
-  JUMP_INIT_DUMMY,
-  JUMP_INIT(finish, _IO_file_finish),
-  JUMP_INIT(overflow, _IO_file_overflow),
-  JUMP_INIT(underflow, _IO_file_underflow),
-  JUMP_INIT(uflow, _IO_default_uflow),
-  JUMP_INIT(pbackfail, _IO_default_pbackfail),
-  JUMP_INIT(xsputn, _IO_file_xsputn),
-  JUMP_INIT(xsgetn, _IO_file_xsgetn),
-  JUMP_INIT(seekoff, _IO_new_file_seekoff),
-  JUMP_INIT(seekpos, _IO_default_seekpos),
-  JUMP_INIT(setbuf, _IO_new_file_setbuf),
-  JUMP_INIT(sync, _IO_new_file_sync),
-  JUMP_INIT(doallocate, _IO_file_doallocate),
-  JUMP_INIT(read, _IO_file_read),
-  JUMP_INIT(write, _IO_new_file_write),
-  JUMP_INIT(seek, _IO_file_seek),
-  JUMP_INIT(close, _IO_file_close),
-  JUMP_INIT(stat, _IO_file_stat),
-  JUMP_INIT(showmanyc, _IO_default_showmanyc),
-  JUMP_INIT(imbue, _IO_default_imbue)
-};
-libc_hidden_data_def (_IO_file_jumps)
-
-const struct _IO_jump_t _IO_file_jumps_mmap =
-{
-  JUMP_INIT_DUMMY,
-  JUMP_INIT(finish, _IO_file_finish),
-  JUMP_INIT(overflow, _IO_file_overflow),
-  JUMP_INIT(underflow, _IO_file_underflow_mmap),
-  JUMP_INIT(uflow, _IO_default_uflow),
-  JUMP_INIT(pbackfail, _IO_default_pbackfail),
-  JUMP_INIT(xsputn, _IO_new_file_xsputn),
-  JUMP_INIT(xsgetn, _IO_file_xsgetn_mmap),
-  JUMP_INIT(seekoff, _IO_file_seekoff_mmap),
-  JUMP_INIT(seekpos, _IO_default_seekpos),
-  JUMP_INIT(setbuf, (_IO_setbuf_t) _IO_file_setbuf_mmap),
-  JUMP_INIT(sync, _IO_file_sync_mmap),
-  JUMP_INIT(doallocate, _IO_file_doallocate),
-  JUMP_INIT(read, _IO_file_read),
-  JUMP_INIT(write, _IO_new_file_write),
-  JUMP_INIT(seek, _IO_file_seek),
-  JUMP_INIT(close, _IO_file_close_mmap),
-  JUMP_INIT(stat, _IO_file_stat),
-  JUMP_INIT(showmanyc, _IO_default_showmanyc),
-  JUMP_INIT(imbue, _IO_default_imbue)
-};
-
-const struct _IO_jump_t _IO_file_jumps_maybe_mmap =
-{
-  JUMP_INIT_DUMMY,
-  JUMP_INIT(finish, _IO_file_finish),
-  JUMP_INIT(overflow, _IO_file_overflow),
-  JUMP_INIT(underflow, _IO_file_underflow_maybe_mmap),
-  JUMP_INIT(uflow, _IO_default_uflow),
-  JUMP_INIT(pbackfail, _IO_default_pbackfail),
-  JUMP_INIT(xsputn, _IO_new_file_xsputn),
-  JUMP_INIT(xsgetn, _IO_file_xsgetn_maybe_mmap),
-  JUMP_INIT(seekoff, _IO_file_seekoff_maybe_mmap),
-  JUMP_INIT(seekpos, _IO_default_seekpos),
-  JUMP_INIT(setbuf, (_IO_setbuf_t) _IO_file_setbuf_mmap),
-  JUMP_INIT(sync, _IO_new_file_sync),
-  JUMP_INIT(doallocate, _IO_file_doallocate),
-  JUMP_INIT(read, _IO_file_read),
-  JUMP_INIT(write, _IO_new_file_write),
-  JUMP_INIT(seek, _IO_file_seek),
-  JUMP_INIT(close, _IO_file_close),
-  JUMP_INIT(stat, _IO_file_stat),
-  JUMP_INIT(showmanyc, _IO_default_showmanyc),
-  JUMP_INIT(imbue, _IO_default_imbue)
-};
diff --git a/libio/freopen.c b/libio/freopen.c
index 8a2a417..7aed1d7 100644
--- a/libio/freopen.c
+++ b/libio/freopen.c
@@ -56,16 +56,16 @@ freopen (const char *filename, const char *mode, FILE *fp)
 	 to the old libio may be passed into shared C library and wind
 	 up here. */
       _IO_old_file_close_it (fp);
-      _IO_JUMPS_FILE_plus (fp) = &_IO_old_file_jumps;
+      _IO_JUMPS_FILE_plus (fp) = &IO_vtables[IO_VTABLE_old_file];
       result = _IO_old_file_fopen (fp, gfilename, mode);
     }
   else
 #endif
     {
       _IO_file_close_it (fp);
-      _IO_JUMPS_FILE_plus (fp) = &_IO_file_jumps;
+      _IO_JUMPS_FILE_plus (fp) = &IO_vtables[IO_VTABLE_file];
       if (_IO_vtable_offset (fp) == 0 && fp->_wide_data != NULL)
-	fp->_wide_data->_wide_vtable = &_IO_wfile_jumps;
+	fp->_wide_data->_wide_vtable = &IO_vtables[IO_VTABLE_wfile];
       result = _IO_file_fopen (fp, gfilename, mode, 1);
       if (result != NULL)
 	result = __fopen_maybe_mmap (result);
diff --git a/libio/freopen64.c b/libio/freopen64.c
index ba85c3e..cca4edf 100644
--- a/libio/freopen64.c
+++ b/libio/freopen64.c
@@ -47,9 +47,9 @@ freopen64 (const char *filename, const char *mode, FILE *fp)
 			   ? fd_to_filename (fd) : filename);
   fp->_flags2 |= _IO_FLAGS2_NOCLOSE;
   _IO_file_close_it (fp);
-  _IO_JUMPS_FILE_plus (fp) = &_IO_file_jumps;
+  _IO_JUMPS_FILE_plus (fp) = &IO_vtables[IO_VTABLE_file];
   if (_IO_vtable_offset (fp) == 0 && fp->_wide_data != NULL)
-    fp->_wide_data->_wide_vtable = &_IO_wfile_jumps;
+    fp->_wide_data->_wide_vtable = &IO_vtables[IO_VTABLE_wfile];
   result = _IO_file_fopen (fp, gfilename, mode, 0);
   fp->_flags2 &= ~_IO_FLAGS2_NOCLOSE;
   if (result != NULL)
diff --git a/libio/iofdopen.c b/libio/iofdopen.c
index e00f337..743c1d1 100644
--- a/libio/iofdopen.c
+++ b/libio/iofdopen.c
@@ -145,23 +145,24 @@ _IO_new_fdopen (int fd, const char *mode)
   _IO_no_init (&new_f->fp.file, 0, 0, &new_f->wd,
 #ifdef _G_HAVE_MMAP
 	       (use_mmap && (read_write & _IO_NO_WRITES))
-	       ? &_IO_wfile_jumps_maybe_mmap :
+	       ? &IO_vtables[IO_VTABLE_wfile_maybe_mmap] :
 #endif
-	       &_IO_wfile_jumps);
+	       &IO_vtables[IO_VTABLE_wfile]);
   _IO_JUMPS (&new_f->fp) =
 #ifdef _G_HAVE_MMAP
-    (use_mmap && (read_write & _IO_NO_WRITES)) ? &_IO_file_jumps_maybe_mmap :
+    (use_mmap && (read_write & _IO_NO_WRITES))
+      ? &IO_vtables[IO_VTABLE_file_maybe_mmap] :
 #endif
-      &_IO_file_jumps;
-  _IO_file_init (&new_f->fp);
+      &IO_vtables[IO_VTABLE_file];
+  _IO_file_init_internal (&new_f->fp);
 #if  !_IO_UNIFIED_JUMPTABLES
   new_f->fp.vtable = NULL;
 #endif
-  /* We only need to record the fd because _IO_file_init will have unset the
-     offset.  It is important to unset the cached offset because the real
-     offset in the file could change between now and when the handle is
-     activated and we would then mislead ftell into believing that we have a
-     valid offset.  */
+  /* We only need to record the fd because _IO_file_init_internal will
+     have unset the offset.  It is important to unset the cached
+     offset because the real offset in the file could change between
+     now and when the handle is activated and we would then mislead
+     ftell into believing that we have a valid offset.  */
   new_f->fp.file._fileno = fd;
   new_f->fp.file._flags &= ~_IO_DELETE_DONT_CLOSE;
 
diff --git a/libio/iofopen.c b/libio/iofopen.c
index 13e3910..85d7e1a 100644
--- a/libio/iofopen.c
+++ b/libio/iofopen.c
@@ -46,10 +46,10 @@ __fopen_maybe_mmap (_IO_FILE *fp)
 	 vanilla file operations and reset the jump table accordingly.  */
 
       if (fp->_mode <= 0)
-	_IO_JUMPS_FILE_plus (fp) = &_IO_file_jumps_maybe_mmap;
+	_IO_JUMPS_FILE_plus (fp) = &IO_vtables[IO_VTABLE_file_maybe_mmap];
       else
-	_IO_JUMPS_FILE_plus (fp) = &_IO_wfile_jumps_maybe_mmap;
-      fp->_wide_data->_wide_vtable = &_IO_wfile_jumps_maybe_mmap;
+	_IO_JUMPS_FILE_plus (fp) = &IO_vtables[IO_VTABLE_wfile_maybe_mmap];
+      fp->_wide_data->_wide_vtable = &IO_vtables[IO_VTABLE_wfile_maybe_mmap];
     }
 #endif
   return fp;
@@ -74,12 +74,13 @@ __fopen_internal (const char *filename, const char *mode, int is32)
   new_f->fp.file._lock = &new_f->lock;
 #endif
 #if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T
-  _IO_no_init (&new_f->fp.file, 0, 0, &new_f->wd, &_IO_wfile_jumps);
+  _IO_no_init (&new_f->fp.file, 0, 0, &new_f->wd,
+	       &IO_vtables[IO_VTABLE_wfile]);
 #else
   _IO_no_init (&new_f->fp.file, 1, 0, NULL, NULL);
 #endif
-  _IO_JUMPS (&new_f->fp) = &_IO_file_jumps;
-  _IO_file_init (&new_f->fp);
+  _IO_JUMPS (&new_f->fp) = &IO_vtables[IO_VTABLE_file];
+  _IO_file_init_internal (&new_f->fp);
 #if  !_IO_UNIFIED_JUMPTABLES
   new_f->fp.vtable = NULL;
 #endif
diff --git a/libio/iofopncook.c b/libio/iofopncook.c
index 9eda7c1..2caae08 100644
--- a/libio/iofopncook.c
+++ b/libio/iofopncook.c
@@ -29,17 +29,7 @@
 #include <stdlib.h>
 #include <shlib-compat.h>
 
-/* Prototyped for local functions.  */
-static _IO_ssize_t _IO_cookie_read (_IO_FILE* fp, void* buf,
-				    _IO_ssize_t size);
-static _IO_ssize_t _IO_cookie_write (_IO_FILE* fp,
-				     const void* buf, _IO_ssize_t size);
-static _IO_off64_t _IO_cookie_seek (_IO_FILE *fp, _IO_off64_t offset, int dir);
-static _IO_off64_t _IO_cookie_seekoff (_IO_FILE *fp, _IO_off64_t offset,
-				       int dir, int mode);
-static int _IO_cookie_close (_IO_FILE* fp);
-
-static _IO_ssize_t
+_IO_ssize_t
 _IO_cookie_read (_IO_FILE *fp, void *buf, _IO_ssize_t size)
 {
   struct _IO_cookie_file *cfile = (struct _IO_cookie_file *) fp;
@@ -50,7 +40,7 @@ _IO_cookie_read (_IO_FILE *fp, void *buf, _IO_ssize_t size)
   return cfile->__io_functions.read (cfile->__cookie, buf, size);
 }
 
-static _IO_ssize_t
+_IO_ssize_t
 _IO_cookie_write (_IO_FILE *fp, const void *buf, _IO_ssize_t size)
 {
   struct _IO_cookie_file *cfile = (struct _IO_cookie_file *) fp;
@@ -68,7 +58,7 @@ _IO_cookie_write (_IO_FILE *fp, const void *buf, _IO_ssize_t size)
   return n;
 }
 
-static _IO_off64_t
+_IO_off64_t
 _IO_cookie_seek (_IO_FILE *fp, _IO_off64_t offset, int dir)
 {
   struct _IO_cookie_file *cfile = (struct _IO_cookie_file *) fp;
@@ -80,7 +70,7 @@ _IO_cookie_seek (_IO_FILE *fp, _IO_off64_t offset, int dir)
 	  ? _IO_pos_BAD : offset);
 }
 
-static int
+int
 _IO_cookie_close (_IO_FILE *fp)
 {
   struct _IO_cookie_file *cfile = (struct _IO_cookie_file *) fp;
@@ -92,7 +82,7 @@ _IO_cookie_close (_IO_FILE *fp)
 }
 
 
-static _IO_off64_t
+_IO_off64_t
 _IO_cookie_seekoff (_IO_FILE *fp, _IO_off64_t offset, int dir, int mode)
 {
   /* We must force the fileops code to always use seek to determine
@@ -102,41 +92,17 @@ _IO_cookie_seekoff (_IO_FILE *fp, _IO_off64_t offset, int dir, int mode)
 }
 
 
-static const struct _IO_jump_t _IO_cookie_jumps = {
-  JUMP_INIT_DUMMY,
-  JUMP_INIT(finish, _IO_file_finish),
-  JUMP_INIT(overflow, _IO_file_overflow),
-  JUMP_INIT(underflow, _IO_file_underflow),
-  JUMP_INIT(uflow, _IO_default_uflow),
-  JUMP_INIT(pbackfail, _IO_default_pbackfail),
-  JUMP_INIT(xsputn, _IO_file_xsputn),
-  JUMP_INIT(xsgetn, _IO_default_xsgetn),
-  JUMP_INIT(seekoff, _IO_cookie_seekoff),
-  JUMP_INIT(seekpos, _IO_default_seekpos),
-  JUMP_INIT(setbuf, _IO_file_setbuf),
-  JUMP_INIT(sync, _IO_file_sync),
-  JUMP_INIT(doallocate, _IO_file_doallocate),
-  JUMP_INIT(read, _IO_cookie_read),
-  JUMP_INIT(write, _IO_cookie_write),
-  JUMP_INIT(seek, _IO_cookie_seek),
-  JUMP_INIT(close, _IO_cookie_close),
-  JUMP_INIT(stat, _IO_default_stat),
-  JUMP_INIT(showmanyc, _IO_default_showmanyc),
-  JUMP_INIT(imbue, _IO_default_imbue),
-};
-
-
 void
 _IO_cookie_init (struct _IO_cookie_file *cfile, int read_write,
 		 void *cookie, _IO_cookie_io_functions_t io_functions)
 {
   _IO_init (&cfile->__fp.file, 0);
-  _IO_JUMPS (&cfile->__fp) = &_IO_cookie_jumps;
+  _IO_JUMPS (&cfile->__fp) = &IO_vtables[IO_VTABLE_cookie];
 
   cfile->__cookie = cookie;
   cfile->__io_functions = io_functions;
 
-  _IO_file_init (&cfile->__fp);
+  _IO_file_init_internal (&cfile->__fp);
 
   _IO_mask_flags (&cfile->__fp.file, read_write,
 		  _IO_NO_READS+_IO_NO_WRITES+_IO_IS_APPENDING);
@@ -217,29 +183,6 @@ _IO_old_cookie_seek (_IO_FILE *fp, _IO_off64_t offset, int dir)
   return (ret == -1) ? _IO_pos_BAD : ret;
 }
 
-static const struct _IO_jump_t _IO_old_cookie_jumps = {
-  JUMP_INIT_DUMMY,
-  JUMP_INIT(finish, _IO_file_finish),
-  JUMP_INIT(overflow, _IO_file_overflow),
-  JUMP_INIT(underflow, _IO_file_underflow),
-  JUMP_INIT(uflow, _IO_default_uflow),
-  JUMP_INIT(pbackfail, _IO_default_pbackfail),
-  JUMP_INIT(xsputn, _IO_file_xsputn),
-  JUMP_INIT(xsgetn, _IO_default_xsgetn),
-  JUMP_INIT(seekoff, _IO_cookie_seekoff),
-  JUMP_INIT(seekpos, _IO_default_seekpos),
-  JUMP_INIT(setbuf, _IO_file_setbuf),
-  JUMP_INIT(sync, _IO_file_sync),
-  JUMP_INIT(doallocate, _IO_file_doallocate),
-  JUMP_INIT(read, _IO_cookie_read),
-  JUMP_INIT(write, _IO_cookie_write),
-  JUMP_INIT(seek, _IO_old_cookie_seek),
-  JUMP_INIT(close, _IO_cookie_close),
-  JUMP_INIT(stat, _IO_default_stat),
-  JUMP_INIT(showmanyc, _IO_default_showmanyc),
-  JUMP_INIT(imbue, _IO_default_imbue),
-};
-
 _IO_FILE *
 attribute_compat_text_section
 _IO_old_fopencookie (void *cookie, const char *mode,
@@ -249,7 +192,7 @@ _IO_old_fopencookie (void *cookie, const char *mode,
 
   ret = _IO_fopencookie (cookie, mode, io_functions);
   if (ret != NULL)
-    _IO_JUMPS_FILE_plus (ret) = &_IO_old_cookie_jumps;
+    _IO_JUMPS_FILE_plus (ret) = &IO_vtables[IO_VTABLE_old_cookie];
 
   return ret;
 }
diff --git a/libio/iopopen.c b/libio/iopopen.c
index 9ddde23..2a17b0e 100644
--- a/libio/iopopen.c
+++ b/libio/iopopen.c
@@ -91,8 +91,6 @@ struct _IO_proc_file
 };
 typedef struct _IO_proc_file _IO_proc_file;
 
-static const struct _IO_jump_t _IO_proc_jumps;
-
 static struct _IO_proc_file *proc_file_chain;
 
 #ifdef _IO_MTSAFE_IO
@@ -288,7 +286,7 @@ _IO_new_popen (const char *command, const char *mode)
 #endif
   fp = &new_f->fpx.file.file;
   _IO_init (fp, 0);
-  _IO_JUMPS (&new_f->fpx.file) = &_IO_proc_jumps;
+  _IO_JUMPS (&new_f->fpx.file) = &IO_vtables[IO_VTABLE_proc];
   _IO_new_file_init (&new_f->fpx.file);
 #if  !_IO_UNIFIED_JUMPTABLES
   new_f->fpx.file.vtable = NULL;
@@ -344,29 +342,6 @@ _IO_new_proc_close (_IO_FILE *fp)
   return wstatus;
 }
 
-static const struct _IO_jump_t _IO_proc_jumps = {
-  JUMP_INIT_DUMMY,
-  JUMP_INIT(finish, _IO_new_file_finish),
-  JUMP_INIT(overflow, _IO_new_file_overflow),
-  JUMP_INIT(underflow, _IO_new_file_underflow),
-  JUMP_INIT(uflow, _IO_default_uflow),
-  JUMP_INIT(pbackfail, _IO_default_pbackfail),
-  JUMP_INIT(xsputn, _IO_new_file_xsputn),
-  JUMP_INIT(xsgetn, _IO_default_xsgetn),
-  JUMP_INIT(seekoff, _IO_new_file_seekoff),
-  JUMP_INIT(seekpos, _IO_default_seekpos),
-  JUMP_INIT(setbuf, _IO_new_file_setbuf),
-  JUMP_INIT(sync, _IO_new_file_sync),
-  JUMP_INIT(doallocate, _IO_file_doallocate),
-  JUMP_INIT(read, _IO_file_read),
-  JUMP_INIT(write, _IO_new_file_write),
-  JUMP_INIT(seek, _IO_file_seek),
-  JUMP_INIT(close, _IO_new_proc_close),
-  JUMP_INIT(stat, _IO_file_stat),
-  JUMP_INIT(showmanyc, _IO_default_showmanyc),
-  JUMP_INIT(imbue, _IO_default_imbue)
-};
-
 strong_alias (_IO_new_popen, __new_popen)
 versioned_symbol (libc, _IO_new_popen, _IO_popen, GLIBC_2_1);
 versioned_symbol (libc, __new_popen, popen, GLIBC_2_1);
diff --git a/libio/iovdprintf.c b/libio/iovdprintf.c
index 8ca55fc..40fa098 100644
--- a/libio/iovdprintf.c
+++ b/libio/iovdprintf.c
@@ -37,9 +37,10 @@ _IO_vdprintf (int d, const char *format, _IO_va_list arg)
 #ifdef _IO_MTSAFE_IO
   tmpfil.file._lock = NULL;
 #endif
-  _IO_no_init (&tmpfil.file, _IO_USER_LOCK, 0, &wd, &_IO_wfile_jumps);
-  _IO_JUMPS (&tmpfil) = &_IO_file_jumps;
-  _IO_file_init (&tmpfil);
+  _IO_no_init (&tmpfil.file, _IO_USER_LOCK, 0, &wd,
+	       &IO_vtables[IO_VTABLE_wfile]);
+  _IO_JUMPS (&tmpfil) = &IO_vtables[IO_VTABLE_file];
+  _IO_file_init_internal (&tmpfil);
 #if  !_IO_UNIFIED_JUMPTABLES
   tmpfil.vtable = NULL;
 #endif
diff --git a/libio/iovsprintf.c b/libio/iovsprintf.c
index 712d178..8d35a02 100644
--- a/libio/iovsprintf.c
+++ b/libio/iovsprintf.c
@@ -37,7 +37,7 @@ __IO_vsprintf (char *string, const char *format, _IO_va_list args)
   sf._sbf._f._lock = NULL;
 #endif
   _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
-  _IO_JUMPS (&sf._sbf) = &_IO_str_jumps;
+  _IO_JUMPS (&sf._sbf) = &IO_vtables[IO_VTABLE_str];
   _IO_str_init_static_internal (&sf, string, -1, string);
   ret = _IO_vfprintf (&sf._sbf._f, format, args);
   _IO_putc_unlocked ('\0', &sf._sbf._f);
diff --git a/libio/iovsscanf.c b/libio/iovsscanf.c
index 18d9aaa..0b2f64e 100644
--- a/libio/iovsscanf.c
+++ b/libio/iovsscanf.c
@@ -36,7 +36,7 @@ _IO_vsscanf (const char *string, const char *format, _IO_va_list args)
   sf._sbf._f._lock = NULL;
 #endif
   _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
-  _IO_JUMPS (&sf._sbf) = &_IO_str_jumps;
+  _IO_JUMPS (&sf._sbf) = &IO_vtables[IO_VTABLE_str];
   _IO_str_init_static_internal (&sf, (char*)string, 0, NULL);
   ret = _IO_vfscanf (&sf._sbf._f, format, args, NULL);
   return ret;
diff --git a/libio/iovswscanf.c b/libio/iovswscanf.c
index ff36069..3852438 100644
--- a/libio/iovswscanf.c
+++ b/libio/iovswscanf.c
@@ -37,7 +37,8 @@ __vswscanf (const wchar_t *string, const wchar_t *format, _IO_va_list args)
 #ifdef _IO_MTSAFE_IO
   sf._sbf._f._lock = NULL;
 #endif
-  _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, 0, &wd, &_IO_wstr_jumps);
+  _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, 0, &wd,
+               &IO_vtables[IO_VTABLE_wstr]);
   _IO_fwide (&sf._sbf._f, 1);
   _IO_wstr_init_static (&sf._sbf._f, (wchar_t *)string, 0, NULL);
   ret = _IO_vfwscanf ((_IO_FILE *) &sf._sbf, format, args, NULL);
diff --git a/libio/libioP.h b/libio/libioP.h
index a75522b..335ff4a 100644
--- a/libio/libioP.h
+++ b/libio/libioP.h
@@ -125,11 +125,12 @@ extern "C" {
 
 #if _IO_JUMPS_OFFSET
 # define _IO_JUMPS_FUNC(THIS) \
- (*(struct _IO_jump_t **) ((void *) &_IO_JUMPS_FILE_plus (THIS) \
-			   + (THIS)->_vtable_offset))
+  (IO_validate_vtable							\
+   ((*(struct _IO_jump_t **) ((void *) &_IO_JUMPS_FILE_plus (THIS)	\
+			      + (THIS)->_vtable_offset))
 # define _IO_vtable_offset(THIS) (THIS)->_vtable_offset
 #else
-# define _IO_JUMPS_FUNC(THIS) _IO_JUMPS_FILE_plus (THIS)
+# define _IO_JUMPS_FUNC(THIS) (IO_validate_vtable (_IO_JUMPS_FILE_plus (THIS)))
 # define _IO_vtable_offset(THIS) 0
 #endif
 #define _IO_WIDE_JUMPS_FUNC(THIS) _IO_WIDE_JUMPS(THIS)
@@ -481,19 +482,6 @@ extern int _IO_default_sync (_IO_FILE *) __THROW;
 extern int _IO_default_showmanyc (_IO_FILE *) __THROW;
 extern void _IO_default_imbue (_IO_FILE *, void *) __THROW;
 
-extern const struct _IO_jump_t _IO_file_jumps;
-libc_hidden_proto (_IO_file_jumps)
-extern const struct _IO_jump_t _IO_file_jumps_mmap attribute_hidden;
-extern const struct _IO_jump_t _IO_file_jumps_maybe_mmap attribute_hidden;
-extern const struct _IO_jump_t _IO_wfile_jumps;
-libc_hidden_proto (_IO_wfile_jumps)
-extern const struct _IO_jump_t _IO_wfile_jumps_mmap attribute_hidden;
-extern const struct _IO_jump_t _IO_wfile_jumps_maybe_mmap attribute_hidden;
-extern const struct _IO_jump_t _IO_old_file_jumps attribute_hidden;
-extern const struct _IO_jump_t _IO_streambuf_jumps;
-extern const struct _IO_jump_t _IO_old_proc_jumps attribute_hidden;
-extern const struct _IO_jump_t _IO_str_jumps attribute_hidden;
-extern const struct _IO_jump_t _IO_wstr_jumps attribute_hidden;
 extern const struct _IO_codecvt __libio_codecvt attribute_hidden;
 extern int _IO_do_write (_IO_FILE *, const char *, _IO_size_t);
 libc_hidden_proto (_IO_do_write)
@@ -583,8 +571,7 @@ extern int _IO_file_underflow_maybe_mmap (_IO_FILE *);
 extern int _IO_file_overflow (_IO_FILE *, int);
 libc_hidden_proto (_IO_file_overflow)
 #define _IO_file_is_open(__fp) ((__fp)->_fileno != -1)
-extern void _IO_file_init (struct _IO_FILE_plus *) __THROW;
-libc_hidden_proto (_IO_file_init)
+extern void _IO_file_init_internal (struct _IO_FILE_plus *) attribute_hidden;
 extern _IO_FILE* _IO_file_attach (_IO_FILE *, int);
 libc_hidden_proto (_IO_file_attach)
 extern _IO_FILE* _IO_file_open (_IO_FILE *, const char *, int, int, int, int);
@@ -886,3 +873,100 @@ _IO_acquire_lock_clear_flags2_fct (_IO_FILE **p)
                                           | _IO_FLAGS2_SCANF_STD);	      \
   } while (0)
 #endif
+
+/* Index into array of jump tables IO_vtables.  */
+enum
+{
+  IO_VTABLE_file,
+  IO_VTABLE_file_mmap,
+  IO_VTABLE_file_maybe_mmap,
+  IO_VTABLE_wfile,
+  IO_VTABLE_wfile_mmap,
+  IO_VTABLE_wfile_maybe_mmap,
+  IO_VTABLE_mem,
+  IO_VTABLE_wmem,
+  IO_VTABLE_proc,
+  IO_VTABLE_str,
+  IO_VTABLE_str_chk,
+  IO_VTABLE_strn,
+  IO_VTABLE_wstr,
+  IO_VTABLE_wstrn,
+  IO_VTABLE_cookie,
+  IO_VTABLE_obstack,
+
+  /* Used in the implementation of vprintf.   */
+  IO_VTABLE_printf_helper,
+  IO_VTABLE_wprintf_helper,
+
+  /* Obsolete vtables. */
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1)
+  IO_VTABLE_old_file,
+  IO_VTABLE_old_proc,
+  IO_VTABLE_old_cookie,
+#endif
+
+  /* Number of vtable array elements.  */
+  IO_VTABLE_COUNT
+};
+
+extern const struct _IO_jump_t IO_vtables[IO_VTABLE_COUNT] attribute_hidden;
+
+/* If true, unknown vtable pointers are valid.  */
+extern bool IO_accept_foreign_vtables attribute_hidden;
+
+/* Check that IO_accept_foreign_vtables is true; otherwise, terminate
+   the process.  */
+void IO_vtable_check (void) attribute_hidden;
+
+/* Perform vtable pointer validation.  If validation fails, terminate
+   the process.  */
+static inline const struct _IO_jump_t *
+IO_validate_vtable (const struct _IO_jump_t *vtable)
+{
+  if (!__glibc_likely (&IO_vtables[0] <= vtable
+		       && vtable < &IO_vtables[IO_VTABLE_COUNT]))
+    IO_vtable_check ();
+  return vtable;
+}
+
+/* Prototypes for functions used in vtables.  */
+
+int _IO_file_sync_mmap (_IO_FILE *fp) attribute_hidden;
+_IO_size_t _IO_file_xsgetn_mmap (_IO_FILE *fp, void *data, _IO_size_t n)
+  attribute_hidden;
+_IO_size_t _IO_file_xsgetn_maybe_mmap (_IO_FILE *fp, void *data, _IO_size_t n)
+  attribute_hidden;
+_IO_off64_t _IO_file_seekoff_maybe_mmap
+ (_IO_FILE *fp, _IO_off64_t offset, int dir, int mode) attribute_hidden;
+
+wint_t _IO_wfile_underflow_mmap (_IO_FILE *fp) attribute_hidden;
+wint_t _IO_wfile_underflow_maybe_mmap (_IO_FILE *fp) attribute_hidden;
+
+int _IO_mem_sync (_IO_FILE* fp) attribute_hidden;
+void _IO_mem_finish (_IO_FILE* fp, int) attribute_hidden;
+
+int _IO_wmem_sync (_IO_FILE* fp) attribute_hidden;
+void _IO_wmem_finish (_IO_FILE* fp, int) attribute_hidden;
+
+int _IO_str_chk_overflow (_IO_FILE *fp, int c) attribute_hidden;
+
+int _IO_strn_overflow (_IO_FILE *fp, int c) attribute_hidden;
+
+wint_t _IO_wstrn_overflow (_IO_FILE *fp, wint_t c) attribute_hidden;
+
+_IO_ssize_t _IO_cookie_read (_IO_FILE* fp, void* buf, _IO_ssize_t size)
+  attribute_hidden;
+_IO_ssize_t _IO_cookie_write (_IO_FILE* fp, const void* buf, _IO_ssize_t size)
+  attribute_hidden;
+_IO_off64_t _IO_cookie_seek (_IO_FILE *fp, _IO_off64_t offset, int dir)
+  attribute_hidden;
+_IO_off64_t _IO_cookie_seekoff (_IO_FILE *fp, _IO_off64_t offset,
+				int dir, int mode) attribute_hidden;
+int _IO_cookie_close (_IO_FILE* fp) attribute_hidden;
+
+int _IO_obstack_overflow (_IO_FILE *fp, int c) attribute_hidden;
+_IO_size_t _IO_obstack_xsputn (_IO_FILE *fp, const void *data, _IO_size_t n)
+  attribute_hidden;
+
+int _IO_printf_helper_overflow (_IO_FILE *s, int c) attribute_hidden;
+int _IO_wprintf_helper_overflow (_IO_FILE *s, int c) attribute_hidden;
diff --git a/libio/memstream.c b/libio/memstream.c
index 7fa5245..7f53c83 100644
--- a/libio/memstream.c
+++ b/libio/memstream.c
@@ -29,34 +29,6 @@ struct _IO_FILE_memstream
 };
 
 
-static int _IO_mem_sync (_IO_FILE* fp) __THROW;
-static void _IO_mem_finish (_IO_FILE* fp, int) __THROW;
-
-
-static const struct _IO_jump_t _IO_mem_jumps =
-{
-  JUMP_INIT_DUMMY,
-  JUMP_INIT (finish, _IO_mem_finish),
-  JUMP_INIT (overflow, _IO_str_overflow),
-  JUMP_INIT (underflow, _IO_str_underflow),
-  JUMP_INIT (uflow, _IO_default_uflow),
-  JUMP_INIT (pbackfail, _IO_str_pbackfail),
-  JUMP_INIT (xsputn, _IO_default_xsputn),
-  JUMP_INIT (xsgetn, _IO_default_xsgetn),
-  JUMP_INIT (seekoff, _IO_str_seekoff),
-  JUMP_INIT (seekpos, _IO_default_seekpos),
-  JUMP_INIT (setbuf, _IO_default_setbuf),
-  JUMP_INIT (sync, _IO_mem_sync),
-  JUMP_INIT (doallocate, _IO_default_doallocate),
-  JUMP_INIT (read, _IO_default_read),
-  JUMP_INIT (write, _IO_default_write),
-  JUMP_INIT (seek, _IO_default_seek),
-  JUMP_INIT (close, _IO_default_close),
-  JUMP_INIT (stat, _IO_default_stat),
-  JUMP_INIT(showmanyc, _IO_default_showmanyc),
-  JUMP_INIT(imbue, _IO_default_imbue)
-};
-
 /* Open a stream that writes into a malloc'd buffer that is expanded as
    necessary.  *BUFLOC and *SIZELOC are updated with the buffer's location
    and the number of characters written on fflush or fclose.  */
@@ -87,7 +59,7 @@ __open_memstream (char **bufloc, _IO_size_t *sizeloc)
       return NULL;
     }
   _IO_init (&new_f->fp._sf._sbf._f, 0);
-  _IO_JUMPS_FILE_plus (&new_f->fp._sf._sbf) = &_IO_mem_jumps;
+  _IO_JUMPS_FILE_plus (&new_f->fp._sf._sbf) = &IO_vtables[IO_VTABLE_mem];
   _IO_str_init_static_internal (&new_f->fp._sf, buf, _IO_BUFSIZ, buf);
   new_f->fp._sf._sbf._f._flags &= ~_IO_USER_BUF;
   new_f->fp._sf._s._allocate_buffer = (_IO_alloc_type) malloc;
@@ -101,8 +73,7 @@ __open_memstream (char **bufloc, _IO_size_t *sizeloc)
 libc_hidden_def (__open_memstream)
 weak_alias (__open_memstream, open_memstream)
 
-
-static int
+int
 _IO_mem_sync (_IO_FILE *fp)
 {
   struct _IO_FILE_memstream *mp = (struct _IO_FILE_memstream *) fp;
@@ -121,8 +92,7 @@ _IO_mem_sync (_IO_FILE *fp)
   return 0;
 }
 
-
-static void
+void
 _IO_mem_finish (_IO_FILE *fp, int dummy)
 {
   struct _IO_FILE_memstream *mp = (struct _IO_FILE_memstream *) fp;
diff --git a/libio/obprintf.c b/libio/obprintf.c
index aa17b46..62917f3 100644
--- a/libio/obprintf.c
+++ b/libio/obprintf.c
@@ -36,7 +36,7 @@ struct _IO_obstack_file
 };
 
 
-static int
+int
 _IO_obstack_overflow (_IO_FILE *fp, int c)
 {
   struct obstack *obstack = ((struct _IO_obstack_file *) fp)->obstack;
@@ -59,7 +59,7 @@ _IO_obstack_overflow (_IO_FILE *fp, int c)
 }
 
 
-static _IO_size_t
+_IO_size_t
 _IO_obstack_xsputn (_IO_FILE *fp, const void *data, _IO_size_t n)
 {
   struct obstack *obstack = ((struct _IO_obstack_file *) fp)->obstack;
@@ -89,33 +89,6 @@ _IO_obstack_xsputn (_IO_FILE *fp, const void *data, _IO_size_t n)
   return n;
 }
 
-
-/* the jump table.  */
-const struct _IO_jump_t _IO_obstack_jumps attribute_hidden =
-{
-  JUMP_INIT_DUMMY,
-  JUMP_INIT(finish, NULL),
-  JUMP_INIT(overflow, _IO_obstack_overflow),
-  JUMP_INIT(underflow, NULL),
-  JUMP_INIT(uflow, NULL),
-  JUMP_INIT(pbackfail, NULL),
-  JUMP_INIT(xsputn, _IO_obstack_xsputn),
-  JUMP_INIT(xsgetn, NULL),
-  JUMP_INIT(seekoff, NULL),
-  JUMP_INIT(seekpos, NULL),
-  JUMP_INIT(setbuf, NULL),
-  JUMP_INIT(sync, NULL),
-  JUMP_INIT(doallocate, NULL),
-  JUMP_INIT(read, NULL),
-  JUMP_INIT(write, NULL),
-  JUMP_INIT(seek, NULL),
-  JUMP_INIT(close, NULL),
-  JUMP_INIT(stat, NULL),
-  JUMP_INIT(showmanyc, NULL),
-  JUMP_INIT(imbue, NULL)
-};
-
-
 int
 _IO_obstack_vprintf (struct obstack *obstack, const char *format, va_list args)
 {
@@ -132,7 +105,7 @@ _IO_obstack_vprintf (struct obstack *obstack, const char *format, va_list args)
 #endif
 
   _IO_no_init (&new_f.ofile.file.file, _IO_USER_LOCK, -1, NULL, NULL);
-  _IO_JUMPS (&new_f.ofile.file) = &_IO_obstack_jumps;
+  _IO_JUMPS (&new_f.ofile.file) = &IO_vtables[IO_VTABLE_obstack];
   room = obstack_room (obstack);
   size = obstack_object_size (obstack) + room;
   if (size == 0)
diff --git a/libio/oldfileops.c b/libio/oldfileops.c
index 4f3bdfe..3916d3b 100644
--- a/libio/oldfileops.c
+++ b/libio/oldfileops.c
@@ -744,29 +744,6 @@ _IO_old_file_xsputn (_IO_FILE *f, const void *data, _IO_size_t n)
   return n - to_do;
 }
 
-
-const struct _IO_jump_t _IO_old_file_jumps =
-{
-  JUMP_INIT_DUMMY,
-  JUMP_INIT(finish, _IO_old_file_finish),
-  JUMP_INIT(overflow, _IO_old_file_overflow),
-  JUMP_INIT(underflow, _IO_old_file_underflow),
-  JUMP_INIT(uflow, _IO_default_uflow),
-  JUMP_INIT(pbackfail, _IO_default_pbackfail),
-  JUMP_INIT(xsputn, _IO_old_file_xsputn),
-  JUMP_INIT(xsgetn, _IO_default_xsgetn),
-  JUMP_INIT(seekoff, _IO_old_file_seekoff),
-  JUMP_INIT(seekpos, _IO_default_seekpos),
-  JUMP_INIT(setbuf, _IO_old_file_setbuf),
-  JUMP_INIT(sync, _IO_old_file_sync),
-  JUMP_INIT(doallocate, _IO_file_doallocate),
-  JUMP_INIT(read, _IO_file_read),
-  JUMP_INIT(write, _IO_old_file_write),
-  JUMP_INIT(seek, _IO_file_seek),
-  JUMP_INIT(close, _IO_file_close),
-  JUMP_INIT(stat, _IO_file_stat)
-};
-
 compat_symbol (libc, _IO_old_do_write, _IO_do_write, GLIBC_2_0);
 compat_symbol (libc, _IO_old_file_attach, _IO_file_attach, GLIBC_2_0);
 compat_symbol (libc, _IO_old_file_close_it, _IO_file_close_it, GLIBC_2_0);
diff --git a/libio/oldiofdopen.c b/libio/oldiofdopen.c
index 33406ff..64ae0df 100644
--- a/libio/oldiofdopen.c
+++ b/libio/oldiofdopen.c
@@ -111,7 +111,7 @@ _IO_old_fdopen (int fd, const char *mode)
   new_f->fp.file._file._lock = &new_f->lock;
 #endif
   _IO_old_init (&new_f->fp.file._file, 0);
-  _IO_JUMPS_FILE_plus (&new_f->fp) = &_IO_old_file_jumps;
+  _IO_JUMPS_FILE_plus (&new_f->fp) = &IO_vtables[IO_VTABLE_old_file];
   _IO_old_file_init ((struct _IO_FILE_plus *) &new_f->fp);
 #if  !_IO_UNIFIED_JUMPTABLES
   new_f->fp.vtable = NULL;
diff --git a/libio/oldiofopen.c b/libio/oldiofopen.c
index cc7c342..3ab6a8a 100644
--- a/libio/oldiofopen.c
+++ b/libio/oldiofopen.c
@@ -50,7 +50,7 @@ _IO_old_fopen (const char *filename, const char *mode)
   new_f->fp.file._file._lock = &new_f->lock;
 #endif
   _IO_old_init (&new_f->fp.file._file, 0);
-  _IO_JUMPS_FILE_plus (&new_f->fp) = &_IO_old_file_jumps;
+  _IO_JUMPS_FILE_plus (&new_f->fp) = &IO_vtables[IO_VTABLE_old_file];
   _IO_old_file_init ((struct _IO_FILE_plus *) &new_f->fp);
 #if  !_IO_UNIFIED_JUMPTABLES
   new_f->fp.vtable = NULL;
diff --git a/libio/oldiopopen.c b/libio/oldiopopen.c
index ea75b4f..0682c27 100644
--- a/libio/oldiopopen.c
+++ b/libio/oldiopopen.c
@@ -210,7 +210,7 @@ _IO_old_popen (const char *command, const char *mode)
 #endif
   fp = &new_f->fpx.file.file._file;
   _IO_old_init (fp, 0);
-  _IO_JUMPS_FILE_plus (&new_f->fpx.file) = &_IO_old_proc_jumps;
+  _IO_JUMPS_FILE_plus (&new_f->fpx.file) = &IO_vtables[IO_VTABLE_old_proc];
   _IO_old_file_init ((struct _IO_FILE_plus *) &new_f->fpx.file);
 #if  !_IO_UNIFIED_JUMPTABLES
   new_f->fpx.file.vtable = NULL;
@@ -267,29 +267,6 @@ _IO_old_proc_close (_IO_FILE *fp)
   return wstatus;
 }
 
-const struct _IO_jump_t _IO_old_proc_jumps = {
-  JUMP_INIT_DUMMY,
-  JUMP_INIT(finish, _IO_old_file_finish),
-  JUMP_INIT(overflow, _IO_old_file_overflow),
-  JUMP_INIT(underflow, _IO_old_file_underflow),
-  JUMP_INIT(uflow, _IO_default_uflow),
-  JUMP_INIT(pbackfail, _IO_default_pbackfail),
-  JUMP_INIT(xsputn, _IO_old_file_xsputn),
-  JUMP_INIT(xsgetn, _IO_default_xsgetn),
-  JUMP_INIT(seekoff, _IO_old_file_seekoff),
-  JUMP_INIT(seekpos, _IO_default_seekpos),
-  JUMP_INIT(setbuf, _IO_old_file_setbuf),
-  JUMP_INIT(sync, _IO_old_file_sync),
-  JUMP_INIT(doallocate, _IO_file_doallocate),
-  JUMP_INIT(read, _IO_file_read),
-  JUMP_INIT(write, _IO_old_file_write),
-  JUMP_INIT(seek, _IO_file_seek),
-  JUMP_INIT(close, _IO_old_proc_close),
-  JUMP_INIT(stat, _IO_file_stat),
-  JUMP_INIT(showmanyc, _IO_default_showmanyc),
-  JUMP_INIT(imbue, _IO_default_imbue)
-};
-
 strong_alias (_IO_old_popen, __old_popen)
 compat_symbol (libc, _IO_old_popen, _IO_popen, GLIBC_2_0);
 compat_symbol (libc, __old_popen, popen, GLIBC_2_0);
diff --git a/libio/oldstdfiles.c b/libio/oldstdfiles.c
index 609b7d9..86e9ded 100644
--- a/libio/oldstdfiles.c
+++ b/libio/oldstdfiles.c
@@ -40,11 +40,13 @@
 #define DEF_STDFILE(NAME, FD, CHAIN, FLAGS) \
   static _IO_lock_t _IO_stdfile_##FD##_lock = _IO_lock_initializer; \
   struct _IO_FILE_plus NAME \
-    = {FILEBUF_LITERAL(CHAIN, FLAGS, FD, NULL), &_IO_old_file_jumps};
+    = {FILEBUF_LITERAL(CHAIN, FLAGS, FD, NULL),
+       &IO_vtables[IO_VTABLE_old_file]};
 #else
 #define DEF_STDFILE(NAME, FD, CHAIN, FLAGS) \
   struct _IO_FILE_plus NAME \
-    = {FILEBUF_LITERAL(CHAIN, FLAGS, FD, NULL), &_IO_old_file_jumps};
+    = {FILEBUF_LITERAL(CHAIN, FLAGS, FD, NULL),
+       &IO_vtables[IO_VTABLE_old_file]};
 #endif
 
 DEF_STDFILE(_IO_stdin_, 0, 0, _IO_NO_WRITES);
diff --git a/libio/stdfiles.c b/libio/stdfiles.c
index 1f583ed..7dca8f9 100644
--- a/libio/stdfiles.c
+++ b/libio/stdfiles.c
@@ -38,30 +38,30 @@
 #  define DEF_STDFILE(NAME, FD, CHAIN, FLAGS) \
   static _IO_lock_t _IO_stdfile_##FD##_lock = _IO_lock_initializer; \
   static struct _IO_wide_data _IO_wide_data_##FD \
-    = { ._wide_vtable = &_IO_wfile_jumps }; \
+    = { ._wide_vtable = &IO_vtables[IO_VTABLE_wfile] }; \
   struct _IO_FILE_plus NAME \
     = {FILEBUF_LITERAL(CHAIN, FLAGS, FD, &_IO_wide_data_##FD), \
-       &_IO_file_jumps};
+       &IO_vtables[IO_VTABLE_file]};
 # else
 #  define DEF_STDFILE(NAME, FD, CHAIN, FLAGS) \
   static _IO_lock_t _IO_stdfile_##FD##_lock = _IO_lock_initializer; \
   struct _IO_FILE_plus NAME \
     = {FILEBUF_LITERAL(CHAIN, FLAGS, FD, NULL), \
-       &_IO_file_jumps};
+       &IO_vtables[IO_VTABLE_file]};
 # endif
 #else
 # if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T
 #  define DEF_STDFILE(NAME, FD, CHAIN, FLAGS) \
   static struct _IO_wide_data _IO_wide_data_##FD \
-    = { ._wide_vtable = &_IO_wfile_jumps }; \
+    = { ._wide_vtable = &IO_vtables[IO_VTABLE_wfile] }; \
   struct _IO_FILE_plus NAME \
     = {FILEBUF_LITERAL(CHAIN, FLAGS, FD, &_IO_wide_data_##FD), \
-       &_IO_file_jumps};
+       &IO_vtables[IO_VTABLE_file]};
 # else
 #  define DEF_STDFILE(NAME, FD, CHAIN, FLAGS) \
   struct _IO_FILE_plus NAME \
     = {FILEBUF_LITERAL(CHAIN, FLAGS, FD, NULL), \
-       &_IO_file_jumps};
+       &IO_vtables[IO_VTABLE_file]};
 # endif
 #endif
 
diff --git a/libio/strfile.h b/libio/strfile.h
index f7ada8e..bd588d1 100644
--- a/libio/strfile.h
+++ b/libio/strfile.h
@@ -71,9 +71,6 @@ typedef struct
   char overflow_buf[64];
 } _IO_strnfile;
 
-extern const struct _IO_jump_t _IO_strn_jumps attribute_hidden;
-
-
 typedef struct
 {
   _IO_strfile f;
@@ -81,5 +78,3 @@ typedef struct
      provided by the user.  */
   wchar_t overflow_buf[64];
 } _IO_wstrnfile;
-
-extern const struct _IO_jump_t _IO_wstrn_jumps attribute_hidden;
diff --git a/libio/strops.c b/libio/strops.c
index 0932d4c..8b68bff 100644
--- a/libio/strops.c
+++ b/libio/strops.c
@@ -322,27 +322,3 @@ _IO_str_finish (_IO_FILE *fp, int dummy)
 
   _IO_default_finish (fp, 0);
 }
-
-const struct _IO_jump_t _IO_str_jumps =
-{
-  JUMP_INIT_DUMMY,
-  JUMP_INIT(finish, _IO_str_finish),
-  JUMP_INIT(overflow, _IO_str_overflow),
-  JUMP_INIT(underflow, _IO_str_underflow),
-  JUMP_INIT(uflow, _IO_default_uflow),
-  JUMP_INIT(pbackfail, _IO_str_pbackfail),
-  JUMP_INIT(xsputn, _IO_default_xsputn),
-  JUMP_INIT(xsgetn, _IO_default_xsgetn),
-  JUMP_INIT(seekoff, _IO_str_seekoff),
-  JUMP_INIT(seekpos, _IO_default_seekpos),
-  JUMP_INIT(setbuf, _IO_default_setbuf),
-  JUMP_INIT(sync, _IO_default_sync),
-  JUMP_INIT(doallocate, _IO_default_doallocate),
-  JUMP_INIT(read, _IO_default_read),
-  JUMP_INIT(write, _IO_default_write),
-  JUMP_INIT(seek, _IO_default_seek),
-  JUMP_INIT(close, _IO_default_close),
-  JUMP_INIT(stat, _IO_default_stat),
-  JUMP_INIT(showmanyc, _IO_default_showmanyc),
-  JUMP_INIT(imbue, _IO_default_imbue)
-};
diff --git a/libio/vasprintf.c b/libio/vasprintf.c
index 7460f1e..6a18c68 100644
--- a/libio/vasprintf.c
+++ b/libio/vasprintf.c
@@ -51,7 +51,7 @@ _IO_vasprintf (char **result_ptr, const char *format, _IO_va_list args)
   sf._sbf._f._lock = NULL;
 #endif
   _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
-  _IO_JUMPS (&sf._sbf) = &_IO_str_jumps;
+  _IO_JUMPS (&sf._sbf) = &IO_vtables[IO_VTABLE_str];
   _IO_str_init_static_internal (&sf, string, init_string_size, string);
   sf._sbf._f._flags &= ~_IO_USER_BUF;
   sf._s._allocate_buffer = (_IO_alloc_type) malloc;
diff --git a/libio/vsnprintf.c b/libio/vsnprintf.c
index f1063a1..c3c6370 100644
--- a/libio/vsnprintf.c
+++ b/libio/vsnprintf.c
@@ -27,9 +27,7 @@
 #include "libioP.h"
 #include "strfile.h"
 
-static int _IO_strn_overflow (_IO_FILE *fp, int c) __THROW;
-
-static int
+int
 _IO_strn_overflow (_IO_FILE *fp, int c)
 {
   /* When we come to here this means the user supplied buffer is
@@ -63,32 +61,6 @@ _IO_strn_overflow (_IO_FILE *fp, int c)
   return c;
 }
 
-
-const struct _IO_jump_t _IO_strn_jumps attribute_hidden =
-{
-  JUMP_INIT_DUMMY,
-  JUMP_INIT(finish, _IO_str_finish),
-  JUMP_INIT(overflow, _IO_strn_overflow),
-  JUMP_INIT(underflow, _IO_str_underflow),
-  JUMP_INIT(uflow, _IO_default_uflow),
-  JUMP_INIT(pbackfail, _IO_str_pbackfail),
-  JUMP_INIT(xsputn, _IO_default_xsputn),
-  JUMP_INIT(xsgetn, _IO_default_xsgetn),
-  JUMP_INIT(seekoff, _IO_str_seekoff),
-  JUMP_INIT(seekpos, _IO_default_seekpos),
-  JUMP_INIT(setbuf, _IO_default_setbuf),
-  JUMP_INIT(sync, _IO_default_sync),
-  JUMP_INIT(doallocate, _IO_default_doallocate),
-  JUMP_INIT(read, _IO_default_read),
-  JUMP_INIT(write, _IO_default_write),
-  JUMP_INIT(seek, _IO_default_seek),
-  JUMP_INIT(close, _IO_default_close),
-  JUMP_INIT(stat, _IO_default_stat),
-  JUMP_INIT(showmanyc, _IO_default_showmanyc),
-  JUMP_INIT(imbue, _IO_default_imbue)
-};
-
-
 int
 _IO_vsnprintf (char *string, _IO_size_t maxlen, const char *format,
 	       _IO_va_list args)
@@ -108,7 +80,7 @@ _IO_vsnprintf (char *string, _IO_size_t maxlen, const char *format,
     }
 
   _IO_no_init (&sf.f._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
-  _IO_JUMPS (&sf.f._sbf) = &_IO_strn_jumps;
+  _IO_JUMPS (&sf.f._sbf) = &IO_vtables[IO_VTABLE_strn];
   string[0] = '\0';
   _IO_str_init_static_internal (&sf.f, string, maxlen - 1, string);
   ret = _IO_vfprintf (&sf.f._sbf._f, format, args);
diff --git a/libio/vswprintf.c b/libio/vswprintf.c
index b90441a..3b00824 100644
--- a/libio/vswprintf.c
+++ b/libio/vswprintf.c
@@ -27,10 +27,7 @@
 #include "libioP.h"
 #include "strfile.h"
 
-
-static wint_t _IO_wstrn_overflow (_IO_FILE *fp, wint_t c) __THROW;
-
-static wint_t
+wint_t
 _IO_wstrn_overflow (_IO_FILE *fp, wint_t c)
 {
   /* When we come to here this means the user supplied buffer is
@@ -62,32 +59,6 @@ _IO_wstrn_overflow (_IO_FILE *fp, wint_t c)
   return c;
 }
 
-
-const struct _IO_jump_t _IO_wstrn_jumps attribute_hidden =
-{
-  JUMP_INIT_DUMMY,
-  JUMP_INIT(finish, _IO_wstr_finish),
-  JUMP_INIT(overflow, (_IO_overflow_t) _IO_wstrn_overflow),
-  JUMP_INIT(underflow, (_IO_underflow_t) _IO_wstr_underflow),
-  JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
-  JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wstr_pbackfail),
-  JUMP_INIT(xsputn, _IO_wdefault_xsputn),
-  JUMP_INIT(xsgetn, _IO_wdefault_xsgetn),
-  JUMP_INIT(seekoff, _IO_wstr_seekoff),
-  JUMP_INIT(seekpos, _IO_default_seekpos),
-  JUMP_INIT(setbuf, _IO_default_setbuf),
-  JUMP_INIT(sync, _IO_default_sync),
-  JUMP_INIT(doallocate, _IO_wdefault_doallocate),
-  JUMP_INIT(read, _IO_default_read),
-  JUMP_INIT(write, _IO_default_write),
-  JUMP_INIT(seek, _IO_default_seek),
-  JUMP_INIT(close, _IO_default_close),
-  JUMP_INIT(stat, _IO_default_stat),
-  JUMP_INIT(showmanyc, _IO_default_showmanyc),
-  JUMP_INIT(imbue, _IO_default_imbue)
-};
-
-
 int
 _IO_vswprintf (wchar_t *string, _IO_size_t maxlen, const wchar_t *format,
 	       _IO_va_list args)
@@ -104,7 +75,8 @@ _IO_vswprintf (wchar_t *string, _IO_size_t maxlen, const wchar_t *format,
        length of zero always makes the function fail.  */
     return -1;
 
-  _IO_no_init (&sf.f._sbf._f, _IO_USER_LOCK, 0, &wd, &_IO_wstrn_jumps);
+  _IO_no_init (&sf.f._sbf._f, _IO_USER_LOCK, 0, &wd,
+	       &IO_vtables[IO_VTABLE_wstrn]);
   _IO_fwide (&sf.f._sbf._f, 1);
   string[0] = L'\0';
   _IO_wstr_init_static (&sf.f._sbf._f, string, maxlen - 1, string);
diff --git a/libio/vtables.c b/libio/vtables.c
new file mode 100644
index 0000000..0c72e01
--- /dev/null
+++ b/libio/vtables.c
@@ -0,0 +1,597 @@
+/* Central definition of libio jump tables.
+   Copyright (C) 1993-2016 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.
+
+   As a special exception, if you link the code in this file with
+   files compiled with a GNU compiler to produce an executable,
+   that does not cause the resulting executable to be covered by
+   the GNU Lesser General Public License.  This exception does not
+   however invalidate any other reasons why the executable file
+   might be covered by the GNU Lesser General Public License.
+   This exception applies to code released by its copyright holders
+   in files containing the exception.  */
+
+#include "libioP.h"
+#include <stdio.h>
+
+/* We keep all jump tables in an array, so that we can verify jump
+   table pointers easily.  */
+
+const struct _IO_jump_t IO_vtables[] =
+  {
+    [IO_VTABLE_file] =
+    {
+      JUMP_INIT_DUMMY,
+      JUMP_INIT(finish, _IO_file_finish),
+      JUMP_INIT(overflow, _IO_file_overflow),
+      JUMP_INIT(underflow, _IO_file_underflow),
+      JUMP_INIT(uflow, _IO_default_uflow),
+      JUMP_INIT(pbackfail, _IO_default_pbackfail),
+      JUMP_INIT(xsputn, _IO_file_xsputn),
+      JUMP_INIT(xsgetn, _IO_file_xsgetn),
+      JUMP_INIT(seekoff, _IO_new_file_seekoff),
+      JUMP_INIT(seekpos, _IO_default_seekpos),
+      JUMP_INIT(setbuf, _IO_new_file_setbuf),
+      JUMP_INIT(sync, _IO_new_file_sync),
+      JUMP_INIT(doallocate, _IO_file_doallocate),
+      JUMP_INIT(read, _IO_file_read),
+      JUMP_INIT(write, _IO_new_file_write),
+      JUMP_INIT(seek, _IO_file_seek),
+      JUMP_INIT(close, _IO_file_close),
+      JUMP_INIT(stat, _IO_file_stat),
+      JUMP_INIT(showmanyc, _IO_default_showmanyc),
+      JUMP_INIT(imbue, _IO_default_imbue)
+    },
+
+    [IO_VTABLE_file_mmap] =
+    {
+      JUMP_INIT_DUMMY,
+      JUMP_INIT(finish, _IO_file_finish),
+      JUMP_INIT(overflow, _IO_file_overflow),
+      JUMP_INIT(underflow, _IO_file_underflow_mmap),
+      JUMP_INIT(uflow, _IO_default_uflow),
+      JUMP_INIT(pbackfail, _IO_default_pbackfail),
+      JUMP_INIT(xsputn, _IO_new_file_xsputn),
+      JUMP_INIT(xsgetn, _IO_file_xsgetn_mmap),
+      JUMP_INIT(seekoff, _IO_file_seekoff_mmap),
+      JUMP_INIT(seekpos, _IO_default_seekpos),
+      JUMP_INIT(setbuf, (_IO_setbuf_t) _IO_file_setbuf_mmap),
+      JUMP_INIT(sync, _IO_file_sync_mmap),
+      JUMP_INIT(doallocate, _IO_file_doallocate),
+      JUMP_INIT(read, _IO_file_read),
+      JUMP_INIT(write, _IO_new_file_write),
+      JUMP_INIT(seek, _IO_file_seek),
+      JUMP_INIT(close, _IO_file_close_mmap),
+      JUMP_INIT(stat, _IO_file_stat),
+      JUMP_INIT(showmanyc, _IO_default_showmanyc),
+      JUMP_INIT(imbue, _IO_default_imbue)
+    },
+
+    [IO_VTABLE_file_maybe_mmap] =
+    {
+      JUMP_INIT_DUMMY,
+      JUMP_INIT(finish, _IO_file_finish),
+      JUMP_INIT(overflow, _IO_file_overflow),
+      JUMP_INIT(underflow, _IO_file_underflow_maybe_mmap),
+      JUMP_INIT(uflow, _IO_default_uflow),
+      JUMP_INIT(pbackfail, _IO_default_pbackfail),
+      JUMP_INIT(xsputn, _IO_new_file_xsputn),
+      JUMP_INIT(xsgetn, _IO_file_xsgetn_maybe_mmap),
+      JUMP_INIT(seekoff, _IO_file_seekoff_maybe_mmap),
+      JUMP_INIT(seekpos, _IO_default_seekpos),
+      JUMP_INIT(setbuf, (_IO_setbuf_t) _IO_file_setbuf_mmap),
+      JUMP_INIT(sync, _IO_new_file_sync),
+      JUMP_INIT(doallocate, _IO_file_doallocate),
+      JUMP_INIT(read, _IO_file_read),
+      JUMP_INIT(write, _IO_new_file_write),
+      JUMP_INIT(seek, _IO_file_seek),
+      JUMP_INIT(close, _IO_file_close),
+      JUMP_INIT(stat, _IO_file_stat),
+      JUMP_INIT(showmanyc, _IO_default_showmanyc),
+      JUMP_INIT(imbue, _IO_default_imbue)
+    },
+
+    [IO_VTABLE_wfile] =
+    {
+      JUMP_INIT_DUMMY,
+      JUMP_INIT(finish, _IO_new_file_finish),
+      JUMP_INIT(overflow, (_IO_overflow_t) _IO_wfile_overflow),
+      JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow),
+      JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
+      JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail),
+      JUMP_INIT(xsputn, _IO_wfile_xsputn),
+      JUMP_INIT(xsgetn, _IO_file_xsgetn),
+      JUMP_INIT(seekoff, _IO_wfile_seekoff),
+      JUMP_INIT(seekpos, _IO_default_seekpos),
+      JUMP_INIT(setbuf, _IO_new_file_setbuf),
+      JUMP_INIT(sync, (_IO_sync_t) _IO_wfile_sync),
+      JUMP_INIT(doallocate, _IO_wfile_doallocate),
+      JUMP_INIT(read, _IO_file_read),
+      JUMP_INIT(write, _IO_new_file_write),
+      JUMP_INIT(seek, _IO_file_seek),
+      JUMP_INIT(close, _IO_file_close),
+      JUMP_INIT(stat, _IO_file_stat),
+      JUMP_INIT(showmanyc, _IO_default_showmanyc),
+      JUMP_INIT(imbue, _IO_default_imbue)
+    },
+
+    [IO_VTABLE_wfile_mmap] =
+    {
+      JUMP_INIT_DUMMY,
+      JUMP_INIT(finish, _IO_new_file_finish),
+      JUMP_INIT(overflow, (_IO_overflow_t) _IO_wfile_overflow),
+      JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow_mmap),
+      JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
+      JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail),
+      JUMP_INIT(xsputn, _IO_wfile_xsputn),
+      JUMP_INIT(xsgetn, _IO_file_xsgetn),
+      JUMP_INIT(seekoff, _IO_wfile_seekoff),
+      JUMP_INIT(seekpos, _IO_default_seekpos),
+      JUMP_INIT(setbuf, _IO_file_setbuf_mmap),
+      JUMP_INIT(sync, (_IO_sync_t) _IO_wfile_sync),
+      JUMP_INIT(doallocate, _IO_wfile_doallocate),
+      JUMP_INIT(read, _IO_file_read),
+      JUMP_INIT(write, _IO_new_file_write),
+      JUMP_INIT(seek, _IO_file_seek),
+      JUMP_INIT(close, _IO_file_close_mmap),
+      JUMP_INIT(stat, _IO_file_stat),
+      JUMP_INIT(showmanyc, _IO_default_showmanyc),
+      JUMP_INIT(imbue, _IO_default_imbue)
+    },
+
+    [IO_VTABLE_wfile_maybe_mmap] =
+    {
+      JUMP_INIT_DUMMY,
+      JUMP_INIT(finish, _IO_new_file_finish),
+      JUMP_INIT(overflow, (_IO_overflow_t) _IO_wfile_overflow),
+      JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow_maybe_mmap),
+      JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
+      JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail),
+      JUMP_INIT(xsputn, _IO_wfile_xsputn),
+      JUMP_INIT(xsgetn, _IO_file_xsgetn),
+      JUMP_INIT(seekoff, _IO_wfile_seekoff),
+      JUMP_INIT(seekpos, _IO_default_seekpos),
+      JUMP_INIT(setbuf, _IO_file_setbuf_mmap),
+      JUMP_INIT(sync, (_IO_sync_t) _IO_wfile_sync),
+      JUMP_INIT(doallocate, _IO_wfile_doallocate),
+      JUMP_INIT(read, _IO_file_read),
+      JUMP_INIT(write, _IO_new_file_write),
+      JUMP_INIT(seek, _IO_file_seek),
+      JUMP_INIT(close, _IO_file_close),
+      JUMP_INIT(stat, _IO_file_stat),
+      JUMP_INIT(showmanyc, _IO_default_showmanyc),
+      JUMP_INIT(imbue, _IO_default_imbue)
+    },
+
+    [IO_VTABLE_mem] =
+    {
+      JUMP_INIT_DUMMY,
+      JUMP_INIT (finish, _IO_mem_finish),
+      JUMP_INIT (overflow, _IO_str_overflow),
+      JUMP_INIT (underflow, _IO_str_underflow),
+      JUMP_INIT (uflow, _IO_default_uflow),
+      JUMP_INIT (pbackfail, _IO_str_pbackfail),
+      JUMP_INIT (xsputn, _IO_default_xsputn),
+      JUMP_INIT (xsgetn, _IO_default_xsgetn),
+      JUMP_INIT (seekoff, _IO_str_seekoff),
+      JUMP_INIT (seekpos, _IO_default_seekpos),
+      JUMP_INIT (setbuf, _IO_default_setbuf),
+      JUMP_INIT (sync, _IO_mem_sync),
+      JUMP_INIT (doallocate, _IO_default_doallocate),
+      JUMP_INIT (read, _IO_default_read),
+      JUMP_INIT (write, _IO_default_write),
+      JUMP_INIT (seek, _IO_default_seek),
+      JUMP_INIT (close, _IO_default_close),
+      JUMP_INIT (stat, _IO_default_stat),
+      JUMP_INIT(showmanyc, _IO_default_showmanyc),
+      JUMP_INIT(imbue, _IO_default_imbue)
+    },
+
+    [IO_VTABLE_wmem] =
+    {
+      JUMP_INIT_DUMMY,
+      JUMP_INIT (finish, _IO_wmem_finish),
+      JUMP_INIT (overflow, (_IO_overflow_t) _IO_wstr_overflow),
+      JUMP_INIT (underflow, (_IO_underflow_t) _IO_wstr_underflow),
+      JUMP_INIT (uflow, (_IO_underflow_t) _IO_wdefault_uflow),
+      JUMP_INIT (pbackfail, (_IO_pbackfail_t) _IO_wstr_pbackfail),
+      JUMP_INIT (xsputn, _IO_wdefault_xsputn),
+      JUMP_INIT (xsgetn, _IO_wdefault_xsgetn),
+      JUMP_INIT (seekoff, _IO_wstr_seekoff),
+      JUMP_INIT (seekpos, _IO_default_seekpos),
+      JUMP_INIT (setbuf, _IO_default_setbuf),
+      JUMP_INIT (sync, _IO_wmem_sync),
+      JUMP_INIT (doallocate, _IO_wdefault_doallocate),
+      JUMP_INIT (read, _IO_default_read),
+      JUMP_INIT (write, _IO_default_write),
+      JUMP_INIT (seek, _IO_default_seek),
+      JUMP_INIT (close, _IO_default_close),
+      JUMP_INIT (stat, _IO_default_stat),
+      JUMP_INIT (showmanyc, _IO_default_showmanyc),
+      JUMP_INIT (imbue, _IO_default_imbue)
+    },
+
+    [IO_VTABLE_proc] =
+    {
+      JUMP_INIT_DUMMY,
+      JUMP_INIT(finish, _IO_new_file_finish),
+      JUMP_INIT(overflow, _IO_new_file_overflow),
+      JUMP_INIT(underflow, _IO_new_file_underflow),
+      JUMP_INIT(uflow, _IO_default_uflow),
+      JUMP_INIT(pbackfail, _IO_default_pbackfail),
+      JUMP_INIT(xsputn, _IO_new_file_xsputn),
+      JUMP_INIT(xsgetn, _IO_default_xsgetn),
+      JUMP_INIT(seekoff, _IO_new_file_seekoff),
+      JUMP_INIT(seekpos, _IO_default_seekpos),
+      JUMP_INIT(setbuf, _IO_new_file_setbuf),
+      JUMP_INIT(sync, _IO_new_file_sync),
+      JUMP_INIT(doallocate, _IO_file_doallocate),
+      JUMP_INIT(read, _IO_file_read),
+      JUMP_INIT(write, _IO_new_file_write),
+      JUMP_INIT(seek, _IO_file_seek),
+      JUMP_INIT(close, _IO_new_proc_close),
+      JUMP_INIT(stat, _IO_file_stat),
+      JUMP_INIT(showmanyc, _IO_default_showmanyc),
+      JUMP_INIT(imbue, _IO_default_imbue)
+    },
+
+    [IO_VTABLE_str] =
+    {
+      JUMP_INIT_DUMMY,
+      JUMP_INIT(finish, _IO_str_finish),
+      JUMP_INIT(overflow, _IO_str_overflow),
+      JUMP_INIT(underflow, _IO_str_underflow),
+      JUMP_INIT(uflow, _IO_default_uflow),
+      JUMP_INIT(pbackfail, _IO_str_pbackfail),
+      JUMP_INIT(xsputn, _IO_default_xsputn),
+      JUMP_INIT(xsgetn, _IO_default_xsgetn),
+      JUMP_INIT(seekoff, _IO_str_seekoff),
+      JUMP_INIT(seekpos, _IO_default_seekpos),
+      JUMP_INIT(setbuf, _IO_default_setbuf),
+      JUMP_INIT(sync, _IO_default_sync),
+      JUMP_INIT(doallocate, _IO_default_doallocate),
+      JUMP_INIT(read, _IO_default_read),
+      JUMP_INIT(write, _IO_default_write),
+      JUMP_INIT(seek, _IO_default_seek),
+      JUMP_INIT(close, _IO_default_close),
+      JUMP_INIT(stat, _IO_default_stat),
+      JUMP_INIT(showmanyc, _IO_default_showmanyc),
+      JUMP_INIT(imbue, _IO_default_imbue)
+    },
+
+    [IO_VTABLE_str_chk] =
+    {
+      JUMP_INIT_DUMMY,
+      JUMP_INIT(finish, _IO_str_finish),
+      JUMP_INIT(overflow, _IO_str_chk_overflow),
+      JUMP_INIT(underflow, _IO_str_underflow),
+      JUMP_INIT(uflow, _IO_default_uflow),
+      JUMP_INIT(pbackfail, _IO_str_pbackfail),
+      JUMP_INIT(xsputn, _IO_default_xsputn),
+      JUMP_INIT(xsgetn, _IO_default_xsgetn),
+      JUMP_INIT(seekoff, _IO_str_seekoff),
+      JUMP_INIT(seekpos, _IO_default_seekpos),
+      JUMP_INIT(setbuf, _IO_default_setbuf),
+      JUMP_INIT(sync, _IO_default_sync),
+      JUMP_INIT(doallocate, _IO_default_doallocate),
+      JUMP_INIT(read, _IO_default_read),
+      JUMP_INIT(write, _IO_default_write),
+      JUMP_INIT(seek, _IO_default_seek),
+      JUMP_INIT(close, _IO_default_close),
+      JUMP_INIT(stat, _IO_default_stat),
+      JUMP_INIT(showmanyc, _IO_default_showmanyc),
+      JUMP_INIT(imbue, _IO_default_imbue)
+    },
+
+    [IO_VTABLE_strn] =
+    {
+      JUMP_INIT_DUMMY,
+      JUMP_INIT(finish, _IO_str_finish),
+      JUMP_INIT(overflow, _IO_strn_overflow),
+      JUMP_INIT(underflow, _IO_str_underflow),
+      JUMP_INIT(uflow, _IO_default_uflow),
+      JUMP_INIT(pbackfail, _IO_str_pbackfail),
+      JUMP_INIT(xsputn, _IO_default_xsputn),
+      JUMP_INIT(xsgetn, _IO_default_xsgetn),
+      JUMP_INIT(seekoff, _IO_str_seekoff),
+      JUMP_INIT(seekpos, _IO_default_seekpos),
+      JUMP_INIT(setbuf, _IO_default_setbuf),
+      JUMP_INIT(sync, _IO_default_sync),
+      JUMP_INIT(doallocate, _IO_default_doallocate),
+      JUMP_INIT(read, _IO_default_read),
+      JUMP_INIT(write, _IO_default_write),
+      JUMP_INIT(seek, _IO_default_seek),
+      JUMP_INIT(close, _IO_default_close),
+      JUMP_INIT(stat, _IO_default_stat),
+      JUMP_INIT(showmanyc, _IO_default_showmanyc),
+      JUMP_INIT(imbue, _IO_default_imbue)
+    },
+
+    [IO_VTABLE_wstr] =
+    {
+      JUMP_INIT_DUMMY,
+      JUMP_INIT(finish, _IO_wstr_finish),
+      JUMP_INIT(overflow, (_IO_overflow_t) _IO_wstr_overflow),
+      JUMP_INIT(underflow, (_IO_underflow_t) _IO_wstr_underflow),
+      JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
+      JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wstr_pbackfail),
+      JUMP_INIT(xsputn, _IO_wdefault_xsputn),
+      JUMP_INIT(xsgetn, _IO_wdefault_xsgetn),
+      JUMP_INIT(seekoff, _IO_wstr_seekoff),
+      JUMP_INIT(seekpos, _IO_default_seekpos),
+      JUMP_INIT(setbuf, _IO_default_setbuf),
+      JUMP_INIT(sync, _IO_default_sync),
+      JUMP_INIT(doallocate, _IO_wdefault_doallocate),
+      JUMP_INIT(read, _IO_default_read),
+      JUMP_INIT(write, _IO_default_write),
+      JUMP_INIT(seek, _IO_default_seek),
+      JUMP_INIT(close, _IO_default_close),
+      JUMP_INIT(stat, _IO_default_stat),
+      JUMP_INIT(showmanyc, _IO_default_showmanyc),
+      JUMP_INIT(imbue, _IO_default_imbue)
+    },
+
+    [IO_VTABLE_wstrn] =
+    {
+      JUMP_INIT_DUMMY,
+      JUMP_INIT(finish, _IO_wstr_finish),
+      JUMP_INIT(overflow, (_IO_overflow_t) _IO_wstrn_overflow),
+      JUMP_INIT(underflow, (_IO_underflow_t) _IO_wstr_underflow),
+      JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
+      JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wstr_pbackfail),
+      JUMP_INIT(xsputn, _IO_wdefault_xsputn),
+      JUMP_INIT(xsgetn, _IO_wdefault_xsgetn),
+      JUMP_INIT(seekoff, _IO_wstr_seekoff),
+      JUMP_INIT(seekpos, _IO_default_seekpos),
+      JUMP_INIT(setbuf, _IO_default_setbuf),
+      JUMP_INIT(sync, _IO_default_sync),
+      JUMP_INIT(doallocate, _IO_wdefault_doallocate),
+      JUMP_INIT(read, _IO_default_read),
+      JUMP_INIT(write, _IO_default_write),
+      JUMP_INIT(seek, _IO_default_seek),
+      JUMP_INIT(close, _IO_default_close),
+      JUMP_INIT(stat, _IO_default_stat),
+      JUMP_INIT(showmanyc, _IO_default_showmanyc),
+      JUMP_INIT(imbue, _IO_default_imbue)
+    },
+
+    [IO_VTABLE_cookie] =
+    {
+      JUMP_INIT_DUMMY,
+      JUMP_INIT(finish, _IO_file_finish),
+      JUMP_INIT(overflow, _IO_file_overflow),
+      JUMP_INIT(underflow, _IO_file_underflow),
+      JUMP_INIT(uflow, _IO_default_uflow),
+      JUMP_INIT(pbackfail, _IO_default_pbackfail),
+      JUMP_INIT(xsputn, _IO_file_xsputn),
+      JUMP_INIT(xsgetn, _IO_default_xsgetn),
+      JUMP_INIT(seekoff, _IO_cookie_seekoff),
+      JUMP_INIT(seekpos, _IO_default_seekpos),
+      JUMP_INIT(setbuf, _IO_file_setbuf),
+      JUMP_INIT(sync, _IO_file_sync),
+      JUMP_INIT(doallocate, _IO_file_doallocate),
+      JUMP_INIT(read, _IO_cookie_read),
+      JUMP_INIT(write, _IO_cookie_write),
+      JUMP_INIT(seek, _IO_cookie_seek),
+      JUMP_INIT(close, _IO_cookie_close),
+      JUMP_INIT(stat, _IO_default_stat),
+      JUMP_INIT(showmanyc, _IO_default_showmanyc),
+      JUMP_INIT(imbue, _IO_default_imbue),
+    },
+
+    [IO_VTABLE_obstack] =
+    {
+      JUMP_INIT_DUMMY,
+      JUMP_INIT(finish, NULL),
+      JUMP_INIT(overflow, _IO_obstack_overflow),
+      JUMP_INIT(underflow, NULL),
+      JUMP_INIT(uflow, NULL),
+      JUMP_INIT(pbackfail, NULL),
+      JUMP_INIT(xsputn, _IO_obstack_xsputn),
+      JUMP_INIT(xsgetn, NULL),
+      JUMP_INIT(seekoff, NULL),
+      JUMP_INIT(seekpos, NULL),
+      JUMP_INIT(setbuf, NULL),
+      JUMP_INIT(sync, NULL),
+      JUMP_INIT(doallocate, NULL),
+      JUMP_INIT(read, NULL),
+      JUMP_INIT(write, NULL),
+      JUMP_INIT(seek, NULL),
+      JUMP_INIT(close, NULL),
+      JUMP_INIT(stat, NULL),
+      JUMP_INIT(showmanyc, NULL),
+      JUMP_INIT(imbue, NULL)
+    },
+
+    [IO_VTABLE_printf_helper] =
+    {
+      JUMP_INIT_DUMMY,
+      JUMP_INIT (finish, _IO_default_finish),
+      JUMP_INIT (overflow, _IO_printf_helper_overflow),
+      JUMP_INIT (underflow, _IO_default_underflow),
+      JUMP_INIT (uflow, _IO_default_uflow),
+      JUMP_INIT (pbackfail, _IO_default_pbackfail),
+      JUMP_INIT (xsputn, _IO_default_xsputn),
+      JUMP_INIT (xsgetn, _IO_default_xsgetn),
+      JUMP_INIT (seekoff, _IO_default_seekoff),
+      JUMP_INIT (seekpos, _IO_default_seekpos),
+      JUMP_INIT (setbuf, _IO_default_setbuf),
+      JUMP_INIT (sync, _IO_default_sync),
+      JUMP_INIT (doallocate, _IO_default_doallocate),
+      JUMP_INIT (read, _IO_default_read),
+      JUMP_INIT (write, _IO_default_write),
+      JUMP_INIT (seek, _IO_default_seek),
+      JUMP_INIT (close, _IO_default_close),
+      JUMP_INIT (stat, _IO_default_stat)
+    },
+
+    [IO_VTABLE_wprintf_helper] =
+    {
+      JUMP_INIT_DUMMY,
+      JUMP_INIT (finish, _IO_wdefault_finish),
+      JUMP_INIT (overflow, _IO_wprintf_helper_overflow),
+      JUMP_INIT (underflow, _IO_default_underflow),
+      JUMP_INIT (uflow, _IO_default_uflow),
+      JUMP_INIT (pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail),
+      JUMP_INIT (xsputn, _IO_wdefault_xsputn),
+      JUMP_INIT (xsgetn, _IO_wdefault_xsgetn),
+      JUMP_INIT (seekoff, _IO_default_seekoff),
+      JUMP_INIT (seekpos, _IO_default_seekpos),
+      JUMP_INIT (setbuf, _IO_default_setbuf),
+      JUMP_INIT (sync, _IO_default_sync),
+      JUMP_INIT (doallocate, _IO_wdefault_doallocate),
+      JUMP_INIT (read, _IO_default_read),
+      JUMP_INIT (write, _IO_default_write),
+      JUMP_INIT (seek, _IO_default_seek),
+      JUMP_INIT (close, _IO_default_close),
+      JUMP_INIT (stat, _IO_default_stat)
+    },
+
+    /* Obsolete vtables.  */
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1)
+    [IO_VTABLE_old_file] =
+    {
+      JUMP_INIT_DUMMY,
+      JUMP_INIT(finish, _IO_old_file_finish),
+      JUMP_INIT(overflow, _IO_old_file_overflow),
+      JUMP_INIT(underflow, _IO_old_file_underflow),
+      JUMP_INIT(uflow, _IO_default_uflow),
+      JUMP_INIT(pbackfail, _IO_default_pbackfail),
+      JUMP_INIT(xsputn, _IO_old_file_xsputn),
+      JUMP_INIT(xsgetn, _IO_default_xsgetn),
+      JUMP_INIT(seekoff, _IO_old_file_seekoff),
+      JUMP_INIT(seekpos, _IO_default_seekpos),
+      JUMP_INIT(setbuf, _IO_old_file_setbuf),
+      JUMP_INIT(sync, _IO_old_file_sync),
+      JUMP_INIT(doallocate, _IO_file_doallocate),
+      JUMP_INIT(read, _IO_file_read),
+      JUMP_INIT(write, _IO_old_file_write),
+      JUMP_INIT(seek, _IO_file_seek),
+      JUMP_INIT(close, _IO_file_close),
+      JUMP_INIT(stat, _IO_file_stat)
+    },
+
+    [IO_VTABLE_old_proc] =
+    {
+      JUMP_INIT_DUMMY,
+      JUMP_INIT(finish, _IO_old_file_finish),
+      JUMP_INIT(overflow, _IO_old_file_overflow),
+      JUMP_INIT(underflow, _IO_old_file_underflow),
+      JUMP_INIT(uflow, _IO_default_uflow),
+      JUMP_INIT(pbackfail, _IO_default_pbackfail),
+      JUMP_INIT(xsputn, _IO_old_file_xsputn),
+      JUMP_INIT(xsgetn, _IO_default_xsgetn),
+      JUMP_INIT(seekoff, _IO_old_file_seekoff),
+      JUMP_INIT(seekpos, _IO_default_seekpos),
+      JUMP_INIT(setbuf, _IO_old_file_setbuf),
+      JUMP_INIT(sync, _IO_old_file_sync),
+      JUMP_INIT(doallocate, _IO_file_doallocate),
+      JUMP_INIT(read, _IO_file_read),
+      JUMP_INIT(write, _IO_old_file_write),
+      JUMP_INIT(seek, _IO_file_seek),
+      JUMP_INIT(close, _IO_old_proc_close),
+      JUMP_INIT(stat, _IO_file_stat),
+      JUMP_INIT(showmanyc, _IO_default_showmanyc),
+      JUMP_INIT(imbue, _IO_default_imbue)
+    },
+
+    [IO_VTABLE_old_cookie] =
+    {
+      JUMP_INIT_DUMMY,
+      JUMP_INIT(finish, _IO_file_finish),
+      JUMP_INIT(overflow, _IO_file_overflow),
+      JUMP_INIT(underflow, _IO_file_underflow),
+      JUMP_INIT(uflow, _IO_default_uflow),
+      JUMP_INIT(pbackfail, _IO_default_pbackfail),
+      JUMP_INIT(xsputn, _IO_file_xsputn),
+      JUMP_INIT(xsgetn, _IO_default_xsgetn),
+      JUMP_INIT(seekoff, _IO_cookie_seekoff),
+      JUMP_INIT(seekpos, _IO_default_seekpos),
+      JUMP_INIT(setbuf, _IO_file_setbuf),
+      JUMP_INIT(sync, _IO_file_sync),
+      JUMP_INIT(doallocate, _IO_file_doallocate),
+      JUMP_INIT(read, _IO_cookie_read),
+      JUMP_INIT(write, _IO_cookie_write),
+      JUMP_INIT(seek, _IO_old_cookie_seek),
+      JUMP_INIT(close, _IO_cookie_close),
+      JUMP_INIT(stat, _IO_default_stat),
+      JUMP_INIT(showmanyc, _IO_default_showmanyc),
+      JUMP_INIT(imbue, _IO_default_imbue),
+    },
+#endif
+  };
+
+
+/* These symbols need to be exported for backwards compatibility.
+   They are no longer used by glibc itself.  */
+
+const struct _IO_jump_t _IO_file_jumps =
+{
+  JUMP_INIT_DUMMY,
+  JUMP_INIT(finish, _IO_file_finish),
+  JUMP_INIT(overflow, _IO_file_overflow),
+  JUMP_INIT(underflow, _IO_file_underflow),
+  JUMP_INIT(uflow, _IO_default_uflow),
+  JUMP_INIT(pbackfail, _IO_default_pbackfail),
+  JUMP_INIT(xsputn, _IO_file_xsputn),
+  JUMP_INIT(xsgetn, _IO_file_xsgetn),
+  JUMP_INIT(seekoff, _IO_new_file_seekoff),
+  JUMP_INIT(seekpos, _IO_default_seekpos),
+  JUMP_INIT(setbuf, _IO_new_file_setbuf),
+  JUMP_INIT(sync, _IO_new_file_sync),
+  JUMP_INIT(doallocate, _IO_file_doallocate),
+  JUMP_INIT(read, _IO_file_read),
+  JUMP_INIT(write, _IO_new_file_write),
+  JUMP_INIT(seek, _IO_file_seek),
+  JUMP_INIT(close, _IO_file_close),
+  JUMP_INIT(stat, _IO_file_stat),
+  JUMP_INIT(showmanyc, _IO_default_showmanyc),
+  JUMP_INIT(imbue, _IO_default_imbue)
+};
+
+const struct _IO_jump_t _IO_wfile_jumps =
+{
+  JUMP_INIT_DUMMY,
+  JUMP_INIT(finish, _IO_new_file_finish),
+  JUMP_INIT(overflow, (_IO_overflow_t) _IO_wfile_overflow),
+  JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow),
+  JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
+  JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail),
+  JUMP_INIT(xsputn, _IO_wfile_xsputn),
+  JUMP_INIT(xsgetn, _IO_file_xsgetn),
+  JUMP_INIT(seekoff, _IO_wfile_seekoff),
+  JUMP_INIT(seekpos, _IO_default_seekpos),
+  JUMP_INIT(setbuf, _IO_new_file_setbuf),
+  JUMP_INIT(sync, (_IO_sync_t) _IO_wfile_sync),
+  JUMP_INIT(doallocate, _IO_wfile_doallocate),
+  JUMP_INIT(read, _IO_file_read),
+  JUMP_INIT(write, _IO_new_file_write),
+  JUMP_INIT(seek, _IO_file_seek),
+  JUMP_INIT(close, _IO_file_close),
+  JUMP_INIT(stat, _IO_file_stat),
+  JUMP_INIT(showmanyc, _IO_default_showmanyc),
+  JUMP_INIT(imbue, _IO_default_imbue)
+};
+
+bool IO_accept_foreign_vtables attribute_hidden;
+
+void attribute_hidden
+IO_vtable_check (void)
+{
+  if (!IO_accept_foreign_vtables)
+    __libc_fatal ("invalid stdio vtable pointer detected\n");
+}
diff --git a/libio/wfileops.c b/libio/wfileops.c
index df1fbda..13cded4 100644
--- a/libio/wfileops.c
+++ b/libio/wfileops.c
@@ -349,7 +349,7 @@ _IO_wfile_underflow (_IO_FILE *fp)
 libc_hidden_def (_IO_wfile_underflow)
 
 
-static wint_t
+wint_t
 _IO_wfile_underflow_mmap (_IO_FILE *fp)
 {
   struct _IO_codecvt *cd;
@@ -410,7 +410,7 @@ _IO_wfile_underflow_mmap (_IO_FILE *fp)
   return WEOF;
 }
 
-static wint_t
+wint_t
 _IO_wfile_underflow_maybe_mmap (_IO_FILE *fp)
 {
   /* This is the first read attempt.  Doing the underflow will choose mmap
@@ -1040,78 +1040,3 @@ _IO_wfile_xsputn (_IO_FILE *f, const void *data, _IO_size_t n)
   return n - to_do;
 }
 libc_hidden_def (_IO_wfile_xsputn)
-
-
-const struct _IO_jump_t _IO_wfile_jumps =
-{
-  JUMP_INIT_DUMMY,
-  JUMP_INIT(finish, _IO_new_file_finish),
-  JUMP_INIT(overflow, (_IO_overflow_t) _IO_wfile_overflow),
-  JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow),
-  JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
-  JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail),
-  JUMP_INIT(xsputn, _IO_wfile_xsputn),
-  JUMP_INIT(xsgetn, _IO_file_xsgetn),
-  JUMP_INIT(seekoff, _IO_wfile_seekoff),
-  JUMP_INIT(seekpos, _IO_default_seekpos),
-  JUMP_INIT(setbuf, _IO_new_file_setbuf),
-  JUMP_INIT(sync, (_IO_sync_t) _IO_wfile_sync),
-  JUMP_INIT(doallocate, _IO_wfile_doallocate),
-  JUMP_INIT(read, _IO_file_read),
-  JUMP_INIT(write, _IO_new_file_write),
-  JUMP_INIT(seek, _IO_file_seek),
-  JUMP_INIT(close, _IO_file_close),
-  JUMP_INIT(stat, _IO_file_stat),
-  JUMP_INIT(showmanyc, _IO_default_showmanyc),
-  JUMP_INIT(imbue, _IO_default_imbue)
-};
-libc_hidden_data_def (_IO_wfile_jumps)
-
-
-const struct _IO_jump_t _IO_wfile_jumps_mmap =
-{
-  JUMP_INIT_DUMMY,
-  JUMP_INIT(finish, _IO_new_file_finish),
-  JUMP_INIT(overflow, (_IO_overflow_t) _IO_wfile_overflow),
-  JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow_mmap),
-  JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
-  JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail),
-  JUMP_INIT(xsputn, _IO_wfile_xsputn),
-  JUMP_INIT(xsgetn, _IO_file_xsgetn),
-  JUMP_INIT(seekoff, _IO_wfile_seekoff),
-  JUMP_INIT(seekpos, _IO_default_seekpos),
-  JUMP_INIT(setbuf, _IO_file_setbuf_mmap),
-  JUMP_INIT(sync, (_IO_sync_t) _IO_wfile_sync),
-  JUMP_INIT(doallocate, _IO_wfile_doallocate),
-  JUMP_INIT(read, _IO_file_read),
-  JUMP_INIT(write, _IO_new_file_write),
-  JUMP_INIT(seek, _IO_file_seek),
-  JUMP_INIT(close, _IO_file_close_mmap),
-  JUMP_INIT(stat, _IO_file_stat),
-  JUMP_INIT(showmanyc, _IO_default_showmanyc),
-  JUMP_INIT(imbue, _IO_default_imbue)
-};
-
-const struct _IO_jump_t _IO_wfile_jumps_maybe_mmap =
-{
-  JUMP_INIT_DUMMY,
-  JUMP_INIT(finish, _IO_new_file_finish),
-  JUMP_INIT(overflow, (_IO_overflow_t) _IO_wfile_overflow),
-  JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow_maybe_mmap),
-  JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
-  JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail),
-  JUMP_INIT(xsputn, _IO_wfile_xsputn),
-  JUMP_INIT(xsgetn, _IO_file_xsgetn),
-  JUMP_INIT(seekoff, _IO_wfile_seekoff),
-  JUMP_INIT(seekpos, _IO_default_seekpos),
-  JUMP_INIT(setbuf, _IO_file_setbuf_mmap),
-  JUMP_INIT(sync, (_IO_sync_t) _IO_wfile_sync),
-  JUMP_INIT(doallocate, _IO_wfile_doallocate),
-  JUMP_INIT(read, _IO_file_read),
-  JUMP_INIT(write, _IO_new_file_write),
-  JUMP_INIT(seek, _IO_file_seek),
-  JUMP_INIT(close, _IO_file_close),
-  JUMP_INIT(stat, _IO_file_stat),
-  JUMP_INIT(showmanyc, _IO_default_showmanyc),
-  JUMP_INIT(imbue, _IO_default_imbue)
-};
diff --git a/libio/wmemstream.c b/libio/wmemstream.c
index 1bdbae9..ccdf2da 100644
--- a/libio/wmemstream.c
+++ b/libio/wmemstream.c
@@ -30,34 +30,6 @@ struct _IO_FILE_wmemstream
 };
 
 
-static int _IO_wmem_sync (_IO_FILE* fp) __THROW;
-static void _IO_wmem_finish (_IO_FILE* fp, int) __THROW;
-
-
-static const struct _IO_jump_t _IO_wmem_jumps =
-{
-  JUMP_INIT_DUMMY,
-  JUMP_INIT (finish, _IO_wmem_finish),
-  JUMP_INIT (overflow, (_IO_overflow_t) _IO_wstr_overflow),
-  JUMP_INIT (underflow, (_IO_underflow_t) _IO_wstr_underflow),
-  JUMP_INIT (uflow, (_IO_underflow_t) _IO_wdefault_uflow),
-  JUMP_INIT (pbackfail, (_IO_pbackfail_t) _IO_wstr_pbackfail),
-  JUMP_INIT (xsputn, _IO_wdefault_xsputn),
-  JUMP_INIT (xsgetn, _IO_wdefault_xsgetn),
-  JUMP_INIT (seekoff, _IO_wstr_seekoff),
-  JUMP_INIT (seekpos, _IO_default_seekpos),
-  JUMP_INIT (setbuf, _IO_default_setbuf),
-  JUMP_INIT (sync, _IO_wmem_sync),
-  JUMP_INIT (doallocate, _IO_wdefault_doallocate),
-  JUMP_INIT (read, _IO_default_read),
-  JUMP_INIT (write, _IO_default_write),
-  JUMP_INIT (seek, _IO_default_seek),
-  JUMP_INIT (close, _IO_default_close),
-  JUMP_INIT (stat, _IO_default_stat),
-  JUMP_INIT (showmanyc, _IO_default_showmanyc),
-  JUMP_INIT (imbue, _IO_default_imbue)
-};
-
 /* Open a stream that writes into a malloc'd buffer that is expanded as
    necessary.  *BUFLOC and *SIZELOC are updated with the buffer's location
    and the number of characters written on fflush or fclose.  */
@@ -87,7 +59,8 @@ open_wmemstream (wchar_t **bufloc, _IO_size_t *sizeloc)
       free (new_f);
       return NULL;
     }
-  _IO_no_init (&new_f->fp._sf._sbf._f, 0, 0, &new_f->wd, &_IO_wmem_jumps);
+  _IO_no_init (&new_f->fp._sf._sbf._f, 0, 0, &new_f->wd,
+	       &IO_vtables[IO_VTABLE_wmem]);
   _IO_fwide (&new_f->fp._sf._sbf._f, 1);
   _IO_wstr_init_static (&new_f->fp._sf._sbf._f, buf,
 			_IO_BUFSIZ / sizeof (wchar_t), buf);
@@ -101,8 +74,7 @@ open_wmemstream (wchar_t **bufloc, _IO_size_t *sizeloc)
   return (_IO_FILE *) &new_f->fp._sf._sbf;
 }
 
-
-static int
+int
 _IO_wmem_sync (_IO_FILE *fp)
 {
   struct _IO_FILE_wmemstream *mp = (struct _IO_FILE_wmemstream *) fp;
@@ -123,7 +95,7 @@ _IO_wmem_sync (_IO_FILE *fp)
 }
 
 
-static void
+void
 _IO_wmem_finish (_IO_FILE *fp, int dummy)
 {
   struct _IO_FILE_wmemstream *mp = (struct _IO_FILE_wmemstream *) fp;
diff --git a/libio/wstrops.c b/libio/wstrops.c
index 2b9d036..c3d5b32 100644
--- a/libio/wstrops.c
+++ b/libio/wstrops.c
@@ -331,27 +331,3 @@ _IO_wstr_finish (_IO_FILE *fp, int dummy)
 
   _IO_wdefault_finish (fp, 0);
 }
-
-const struct _IO_jump_t _IO_wstr_jumps =
-{
-  JUMP_INIT_DUMMY,
-  JUMP_INIT(finish, _IO_wstr_finish),
-  JUMP_INIT(overflow, (_IO_overflow_t) _IO_wstr_overflow),
-  JUMP_INIT(underflow, (_IO_underflow_t) _IO_wstr_underflow),
-  JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
-  JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wstr_pbackfail),
-  JUMP_INIT(xsputn, _IO_wdefault_xsputn),
-  JUMP_INIT(xsgetn, _IO_wdefault_xsgetn),
-  JUMP_INIT(seekoff, _IO_wstr_seekoff),
-  JUMP_INIT(seekpos, _IO_default_seekpos),
-  JUMP_INIT(setbuf, _IO_default_setbuf),
-  JUMP_INIT(sync, _IO_default_sync),
-  JUMP_INIT(doallocate, _IO_wdefault_doallocate),
-  JUMP_INIT(read, _IO_default_read),
-  JUMP_INIT(write, _IO_default_write),
-  JUMP_INIT(seek, _IO_default_seek),
-  JUMP_INIT(close, _IO_default_close),
-  JUMP_INIT(stat, _IO_default_stat),
-  JUMP_INIT(showmanyc, _IO_default_showmanyc),
-  JUMP_INIT(imbue, _IO_default_imbue)
-};
diff --git a/stdio-common/isoc99_vsscanf.c b/stdio-common/isoc99_vsscanf.c
index 720f122..6968db9 100644
--- a/stdio-common/isoc99_vsscanf.c
+++ b/stdio-common/isoc99_vsscanf.c
@@ -37,7 +37,7 @@ __isoc99_vsscanf (const char *string, const char *format, _IO_va_list args)
   sf._sbf._f._lock = NULL;
 #endif
   _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
-  _IO_JUMPS (&sf._sbf) = &_IO_str_jumps;
+  _IO_JUMPS (&sf._sbf) = &IO_vtables[IO_VTABLE_str];
   _IO_str_init_static_internal (&sf, (char*)string, 0, NULL);
   sf._sbf._f._flags2 |= _IO_FLAGS2_SCANF_STD;
   ret = _IO_vfscanf (&sf._sbf._f, format, args, NULL);
diff --git a/stdio-common/vfprintf.c b/stdio-common/vfprintf.c
index f24020a..794e770 100644
--- a/stdio-common/vfprintf.c
+++ b/stdio-common/vfprintf.c
@@ -2207,11 +2207,11 @@ struct helper_file
 #endif
   };
 
-static int
-_IO_helper_overflow (_IO_FILE *s, int c)
+#ifdef COMPILE_WPRINTF
+int
+_IO_wprintf_helper_overflow (_IO_FILE *s, int c)
 {
   _IO_FILE *target = ((struct helper_file*) s)->_put_stream;
-#ifdef COMPILE_WPRINTF
   int used = s->_wide_data->_IO_write_ptr - s->_wide_data->_IO_write_base;
   if (used)
     {
@@ -2224,7 +2224,13 @@ _IO_helper_overflow (_IO_FILE *s, int c)
 		  used - written);
       s->_wide_data->_IO_write_ptr -= written;
     }
+  return PUTC (c, s);
+}
 #else
+int
+_IO_printf_helper_overflow (_IO_FILE *s, int c)
+{
+  _IO_FILE *target = ((struct helper_file*) s)->_put_stream;
   int used = s->_IO_write_ptr - s->_IO_write_base;
   if (used)
     {
@@ -2235,54 +2241,8 @@ _IO_helper_overflow (_IO_FILE *s, int c)
 	       used - written);
       s->_IO_write_ptr -= written;
     }
-#endif
   return PUTC (c, s);
 }
-
-#ifdef COMPILE_WPRINTF
-static const struct _IO_jump_t _IO_helper_jumps =
-{
-  JUMP_INIT_DUMMY,
-  JUMP_INIT (finish, _IO_wdefault_finish),
-  JUMP_INIT (overflow, _IO_helper_overflow),
-  JUMP_INIT (underflow, _IO_default_underflow),
-  JUMP_INIT (uflow, _IO_default_uflow),
-  JUMP_INIT (pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail),
-  JUMP_INIT (xsputn, _IO_wdefault_xsputn),
-  JUMP_INIT (xsgetn, _IO_wdefault_xsgetn),
-  JUMP_INIT (seekoff, _IO_default_seekoff),
-  JUMP_INIT (seekpos, _IO_default_seekpos),
-  JUMP_INIT (setbuf, _IO_default_setbuf),
-  JUMP_INIT (sync, _IO_default_sync),
-  JUMP_INIT (doallocate, _IO_wdefault_doallocate),
-  JUMP_INIT (read, _IO_default_read),
-  JUMP_INIT (write, _IO_default_write),
-  JUMP_INIT (seek, _IO_default_seek),
-  JUMP_INIT (close, _IO_default_close),
-  JUMP_INIT (stat, _IO_default_stat)
-};
-#else
-static const struct _IO_jump_t _IO_helper_jumps =
-{
-  JUMP_INIT_DUMMY,
-  JUMP_INIT (finish, _IO_default_finish),
-  JUMP_INIT (overflow, _IO_helper_overflow),
-  JUMP_INIT (underflow, _IO_default_underflow),
-  JUMP_INIT (uflow, _IO_default_uflow),
-  JUMP_INIT (pbackfail, _IO_default_pbackfail),
-  JUMP_INIT (xsputn, _IO_default_xsputn),
-  JUMP_INIT (xsgetn, _IO_default_xsgetn),
-  JUMP_INIT (seekoff, _IO_default_seekoff),
-  JUMP_INIT (seekpos, _IO_default_seekpos),
-  JUMP_INIT (setbuf, _IO_default_setbuf),
-  JUMP_INIT (sync, _IO_default_sync),
-  JUMP_INIT (doallocate, _IO_default_doallocate),
-  JUMP_INIT (read, _IO_default_read),
-  JUMP_INIT (write, _IO_default_write),
-  JUMP_INIT (seek, _IO_default_seek),
-  JUMP_INIT (close, _IO_default_close),
-  JUMP_INIT (stat, _IO_default_stat)
-};
 #endif
 
 static int
@@ -2318,7 +2278,11 @@ buffered_vfprintf (_IO_FILE *s, const CHAR_T *format,
   hp->_lock = NULL;
 #endif
   hp->_flags2 = s->_flags2;
-  _IO_JUMPS (&helper._f) = (struct _IO_jump_t *) &_IO_helper_jumps;
+#ifndef COMPILE_WPRINTF
+  _IO_JUMPS (&helper._f) = &IO_vtables[IO_VTABLE_printf_helper];
+#else
+  _IO_JUMPS (&helper._f) = &IO_vtables[IO_VTABLE_wprintf_helper];
+#endif
 
   /* Now print to helper instead.  */
 #ifndef COMPILE_WPRINTF
diff --git a/stdlib/strfmon_l.c b/stdlib/strfmon_l.c
index 5851a5b..7d2302e 100644
--- a/stdlib/strfmon_l.c
+++ b/stdlib/strfmon_l.c
@@ -513,7 +513,7 @@ __vstrfmon_l (char *s, size_t maxsize, __locale_t loc, const char *format,
       f._sbf._f._lock = NULL;
 #endif
       _IO_init (&f._sbf._f, 0);
-      _IO_JUMPS (&f._sbf) = &_IO_str_jumps;
+      _IO_JUMPS (&f._sbf) = &IO_vtables[IO_VTABLE_str];
       _IO_str_init_static_internal (&f, dest, (s + maxsize) - dest, dest);
       /* We clear the last available byte so we can find out whether
 	 the numeric representation is too long.  */
diff --git a/wcsmbs/isoc99_vswscanf.c b/wcsmbs/isoc99_vswscanf.c
index b7effb0..3eb51f1 100644
--- a/wcsmbs/isoc99_vswscanf.c
+++ b/wcsmbs/isoc99_vswscanf.c
@@ -38,7 +38,8 @@ __isoc99_vswscanf (const wchar_t *string, const wchar_t *format,
 #ifdef _IO_MTSAFE_IO
   sf._sbf._f._lock = NULL;
 #endif
-  _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, 0, &wd, &_IO_wstr_jumps);
+  _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, 0, &wd,
+	       &IO_vtables[IO_VTABLE_wstr]);
   _IO_fwide (&sf._sbf._f, 1);
   _IO_wstr_init_static (&sf._sbf._f, (wchar_t *)string, 0, NULL);
   sf._sbf._f._flags2 |= _IO_FLAGS2_SCANF_STD;

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]