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]

Re: Alternative libio vtable hardening approach


On 06/01/2016 08:16 PM, Florian Weimer wrote:

I have to use weak references anyway to avoid linknamespace issues, and
we can add more if the current approach pulls in too much additional code.

Just saving the patch—the method elimination is now so aggressive that required implementations are not pulled into static links.

Real patch forthcoming.

Florian

libio: Consolidate vtable definitions in a single file

This will allow us to efficiently validate vtable pointers.

Due to the use of weak symbols in the vtable array, the size
impact on static linking is very modest. The numbers below
are for x86_64, with GCC 6 and the default flags.

Before:

   text    data     bss     dec     hex filename
 694942    7276    5816  708034   acdc2 elf/sln
 861436    7536    6760  875732   d5cd4 elf/ldconfig

After:

 695550    7276    5816  708642   ad022 elf/sln
 861916    7536    6760  876212   d5eb4 elf/ldconfig

2016-06-02  Florian Weimer  <fweimer@redhat.com>

	Consolidate libio vtables in a single file.
	* libio/vtables.c: New file.  Define jump tables with designated
	initializers instead of JUMP_INIT.
	* libio/libioP.h (JUMP_INIT, JUMP_INIT_DUMMY): Remove macros.
	(_IO_file_jumps, _IO_file_jumps_mmap, _IO_file_jumps_maybe_mmap)
	(_IO_wfile_jumps, _IO_wfile_jumps_mmap)
	(_IO_wfile_jumps_maybe_mmap, _IO_old_file_jumps)
	(_IO_streambuf_jumps, _IO_old_proc_jumps, _IO_str_jumps)
	(_IO_wstr_jumps): Remove declarations.
	(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, IO_VTABLE_printf_helper)
	(IO_VTABLE_wprintf_helper, IO_VTABLE_old_file, IO_VTABLE_old_proc)
	(IO_VTABLE_old_cookie): New enum constants.
	(_IO_vtables): New array of vtables.
	(_IO_file_sync_mmap, _IO_file_xsgetn_mmap)
	(_IO_file_xsgetn_maybe_mmap, _IO_file_seekoff_maybe_mmap)
	(_IO_wfile_underflow_mmap, _IO_wfile_underflow_maybe_mmap)
	(_IO_mem_sync, _IO_mem_finish, _IO_wmem_sync, _IO_wmem_finish)
	(_IO_str_chk_overflow, _IO_strn_overflow, _IO_wstrn_overflow)
	(_IO_cookie_read, _IO_cookie_write, _IO_cookie_seek)
	(_IO_cookie_seekoff, _IO_cookie_close, _IO_obstack_overflow)
	(_IO_obstack_xsputn, _IO_printf_helper_overflow)
	(_IO_wprintf_helper_overflow, _IO_old_cookie_seek): Declare
	functions used in vtables.
	* libio/vtables-weak.awk: New file.
	* libio/Makefile (routines): Add vtables.
	(generated): Add vtables-weak.h.
	(before-compile): Likewise.
	(vtables-weak.h): Build using libio/vtables-weak.awk.
	* debug/obprintf_chk.c (_IO_obstack_jumps): Remove declaration.
	(__obstack_vprintf_chk): Use IO_VTABLE_obstack.
	* debug/vasprintf_chk.c (__vasprintf_chk): Use IO_VTABLE_str.
	* debug/vdprintf_chk.c (__vdprintf_chk): Use IO_VTABLE_wfile,
	IO_VTABLE_file.
	* debug/vsnprintf_chk.c (_IO_strn_jumps): Remove declaration.
	(___vsnprintf_chk): Use IO_VTABLE_strn.
	* debug/vsprintf_chk.c (_IO_str_chk_overflow): Export.
	(_IO_str_chk_jumps): Remove.
	(___vsprintf_chk): Use IO_VTABLE_str_chk.
	* debug/vswprintf_chk.c (__vswprintf_chk): Use IO_VTABLE_wstrn.
	* libio/fileops.c (_IO_file_setbuf_mmap): Use IO_VTABLE_file,
	IO_VTABLE_wfile, IO_VTABLE_file_mmap, IO_VTABLE_wfile_mmap.
	(mmap_remap_check): Use IO_VTABLE_file, IO_VTABLE_wfile.
	(decide_maybe_mmap): Use IO_VTABLE_file_mmap,
	IO_VTABLE_wfile_mmap, IO_VTABLE_file, IO_VTABLE_wfile.
	(_IO_file_sync_mmap, _IO_file_seekoff_maybe_mmap)
	(_IO_file_xsgetn_mmap, _IO_file_xsgetn_maybe_mmap): Export.
	(_IO_file_jumps, _IO_file_jumps_mmap, _IO_file_jumps_maybe_mmap):
	Remove.
	* libio/freopen.c (freopen): Use IO_VTABLE_old_file,
	IO_VTABLE_file, IO_VTABLE_wfile.
	* libio/libio/freopen64.c (freopen64): Use IO_VTABLE_file,
	IO_VTABLE_wfile.
	* libio/iofdopen.c (_IO_new_fdopen): Use
	IO_VTABLE_wfile_maybe_mmap, IO_VTABLE_wfile,
	IO_VTABLE_file_maybe_mmap, IO_VTABLE_file.
	* libio/iofopen.c (__fopen_maybe_mmap): Use
	IO_VTABLE_file_maybe_mmap, IO_VTABLE_wfile_maybe_mmap.
	(__fopen_internal): Use IO_VTABLE_wfile, IO_VTABLE_file.
	* libio/iofopncook.c (_IO_cookie_read, _IO_cookie_write)
	(_IO_cookie_seek, _IO_cookie_close, _IO_cookie_seekoff): Export.
	(_IO_cookie_jumps): Remove.
	(_IO_cookie_init): Use IO_VTABLE_cookie.
	(_IO_old_cookie_jumps): Remove.
	(_IO_old_fopencookie): Use IO_VTABLE_old_cookie.
	* libio/iopopen.c (_IO_proc_jumps): Remove.
	(_IO_new_popen): Use IO_VTABLE_proc.
	* libio/iovdprintf.c (_IO_vdprintf): Use IO_VTABLE_wfile,
	IO_VTABLE_file.
	* libio/iovsprintf.c (__IO_vsprintf): Use IO_VTABLE_str.
	* libio/iovsscanf.c (_IO_vsscanf): Use IO_VTABLE_str.
	* libio/iovswscanf.c (__vswscanf): Use IO_VTABLE_wstr.
	* libio/memstream.c (_IO_mem_sync, _IO_mem_finish): Export.
	(_IO_mem_jumps): Remove.
	(__open_memstream): Use IO_VTABLE_mem.
	* libio/obprintf.c (_IO_obstack_overflow, _IO_obstack_xsputn):
	Export.
	(_IO_obstack_jumps): Remove.
	(_IO_obstack_vprintf): Use IO_VTABLE_obstack.
	* libio/oldfileops.c (_IO_old_file_jumps): Remove.
	* libio/oldiofdopen.c (_IO_old_fdopen): Use IO_VTABLE_old_file.
	* libio/oldiofopen.c (_IO_old_fopen): Use IO_VTABLE_old_file.
	* libio/oldiopopen.c (_IO_old_popen): Use IO_VTABLE_old_proc.
	(_IO_old_proc_jumps): Remove.
	* libio/oldstdfiles.c (DEF_STDFILE): Use IO_VTABLE_old_file.
	* libio/stdfiles.c (DEF_STDFILE): Use IO_VTABLE_wfile,
	IO_VTABLE_file.
	* libio/strfile.h (_IO_strn_jumps, _IO_wstrn_jumps): Remove
	declarations.
	* libio/strops.c (_IO_str_jumps): Remove.
	* libio/vasprintf.c (_IO_vasprintf): Use IO_VTABLE_str.
	* libio/vsnprintf.c (_IO_strn_overflow): Export.
	(_IO_strn_jumps): Remove.
	(_IO_vsnprintf): Use IO_VTABLE_strn.
	* libio/vswprintf.c (_IO_wstrn_overflow): Export.
	(_IO_wstrn_jumps): Remove.
	(_IO_vswprintf): Use IO_VTABLE_wstrn.
	* libio/wfileops.c (_IO_wfile_underflow_mmap)
	(_IO_wfile_underflow_maybe_mmap): Export.
	(_IO_wfile_jumps, _IO_wfile_jumps_mmap)
	(_IO_wfile_jumps_maybe_mmap): Remove.
	* libio/wmemstream.c (_IO_wmem_sync, _IO_wmem_finish): Export.
	(_IO_wmem_jumps): Remove.
	(open_wmemstream): Use IO_VTABLE_wmem.
	* libio/wstrops.c (_IO_wstr_jumps): Remove.
	* stdio-common/isoc99_vsscanf.c (__isoc99_vsscanf): Use
	IO_VTABLE_str.
	* stdio-common/vfprintf.c (_IO_wprintf_helper_overflow)
	(_IO_printf_helper_overflow): Split, rename and export.
	(_IO_helper_jumps, _IO_helper_jumps): Remove.
	(buffered_vfprintf): Use IO_VTABLE_printf_helper,
	IO_VTABLE_wprintf_helper
	* stdlib/strfmon_l.c (__vstrfmon_l): Use IO_VTABLE_str.
	* wcsmbs/isoc99_vswscanf.c (__isoc99_vswscanf): Use
	IO_VTABLE_wstr.

diff --git a/debug/obprintf_chk.c b/debug/obprintf_chk.c
index 8469b5f..e458655 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..235db0b 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..6efe9ee 100644
--- a/debug/vdprintf_chk.c
+++ b/debug/vdprintf_chk.c
@@ -37,8 +37,9 @@ __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_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 (&tmpfil);
 #if  !_IO_UNIFIED_JUMPTABLES
   tmpfil.vtable = NULL;
diff --git a/debug/vsnprintf_chk.c b/debug/vsnprintf_chk.c
index cc559d2..a682fae 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..71ff17c 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..1479439 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..131007a 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 \
@@ -154,6 +154,8 @@ tst-fopenloc-ENV = MALLOC_TRACE=$(objpfx)tst-fopenloc.mtrace
 generated += test-fmemopen.mtrace test-fmemopen.check
 generated += tst-fopenloc.mtrace tst-fopenloc.check
 
+generated += vtables-weak.h
+
 aux	:= fileops genops stdfiles stdio strops
 
 ifeq ($(build-shared),yes)
@@ -176,6 +178,12 @@ endif
 
 include ../Rules
 
+# Auto-generated #pragma weak directives for optimizing static
+# linking of vtables.
+$(objpfx)vtables-weak.h: vtables-weak.awk vtables.c
+	$(AWK) -f $^ | sort -u > $@
+$(objpfx)vtables.os: vtables-weak.h
+
 ifeq ($(run-built-tests),yes)
 LOCALES := de_DE.ISO-8859-1 de_DE.UTF-8 en_US.ISO-8859-1 en_US.UTF-8 \
 	   ja_JP.EUC-JP ja_JP.UTF-8
diff --git a/libio/fileops.c b/libio/fileops.c
index 8e83b1c..110d7c9 100644
--- a/libio/fileops.c
+++ b/libio/fileops.c
@@ -466,8 +466,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 +475,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 +703,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 +773,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 +786,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 +897,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 +1192,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 +1453,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 +1508,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 +1533,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..d7d1e71 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..760ebc9 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..2bcd21a 100644
--- a/libio/iofdopen.c
+++ b/libio/iofdopen.c
@@ -145,14 +145,15 @@ _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_vtables[IO_VTABLE_file];
   _IO_file_init (&new_f->fp);
 #if  !_IO_UNIFIED_JUMPTABLES
   new_f->fp.vtable = NULL;
diff --git a/libio/iofopen.c b/libio/iofopen.c
index 13e3910..3510e8d 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,11 +74,12 @@ __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_JUMPS (&new_f->fp) = &_IO_vtables[IO_VTABLE_file];
   _IO_file_init (&new_f->fp);
 #if  !_IO_UNIFIED_JUMPTABLES
   new_f->fp.vtable = NULL;
diff --git a/libio/iofopncook.c b/libio/iofopncook.c
index 9eda7c1..62d79ec 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,36 +92,12 @@ _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;
@@ -195,12 +161,10 @@ versioned_symbol (libc, _IO_fopencookie, fopencookie, GLIBC_2_2);
 
 #if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_2)
 
-static _IO_off64_t _IO_old_cookie_seek (_IO_FILE *fp, _IO_off64_t offset,
-					int dir);
 _IO_FILE * _IO_old_fopencookie (void *cookie, const char *mode,
 				_IO_cookie_io_functions_t io_functions);
 
-static _IO_off64_t
+_IO_off64_t
 attribute_compat_text_section
 _IO_old_cookie_seek (_IO_FILE *fp, _IO_off64_t offset, int dir)
 {
@@ -217,29 +181,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 +190,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..671e398 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..7f0fdd3 100644
--- a/libio/iovdprintf.c
+++ b/libio/iovdprintf.c
@@ -37,8 +37,9 @@ _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_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 (&tmpfil);
 #if  !_IO_UNIFIED_JUMPTABLES
   tmpfil.vtable = NULL;
diff --git a/libio/iovsprintf.c b/libio/iovsprintf.c
index 712d178..f1dec0d 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..11b16dd 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..2839b9d 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 8706af2..5322a84 100644
--- a/libio/libioP.h
+++ b/libio/libioP.h
@@ -138,8 +138,6 @@ extern "C" {
 #define JUMP1(FUNC, THIS, X1) (_IO_JUMPS_FUNC(THIS)->FUNC) (THIS, X1)
 #define JUMP2(FUNC, THIS, X1, X2) (_IO_JUMPS_FUNC(THIS)->FUNC) (THIS, X1, X2)
 #define JUMP3(FUNC, THIS, X1,X2,X3) (_IO_JUMPS_FUNC(THIS)->FUNC) (THIS, X1,X2, X3)
-#define JUMP_INIT(NAME, VALUE) VALUE
-#define JUMP_INIT_DUMMY JUMP_INIT(dummy, 0), JUMP_INIT (dummy2, 0)
 
 #define WJUMP0(FUNC, THIS) (_IO_WIDE_JUMPS_FUNC(THIS)->FUNC) (THIS)
 #define WJUMP1(FUNC, THIS, X1) (_IO_WIDE_JUMPS_FUNC(THIS)->FUNC) (THIS, X1)
@@ -485,19 +483,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)
@@ -890,3 +875,87 @@ _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;
+
+/* 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;
+
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1)
+_IO_off64_t _IO_old_cookie_seek (_IO_FILE *fp, _IO_off64_t offset,
+				 int dir) attribute_hidden;
+#endif
diff --git a/libio/memstream.c b/libio/memstream.c
index 7fa5245..42034fe 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..104dd61 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..e7cf76d 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..4db8f90 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..2d8b9d4 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..b3845c7 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..a4bafd6 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..f7517e6 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..4cad77d 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..91e24db 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-weak.awk b/libio/vtables-weak.awk
new file mode 100644
index 0000000..c01852e
--- /dev/null
+++ b/libio/vtables-weak.awk
@@ -0,0 +1,28 @@
+# Generate #pragma weak directives from vtables.c
+# Copyright (C) 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/>.
+
+# Match a designated initializer and emit #pragma weak for the
+# identifier which is used in the initialization.
+
+/^ +\.__/ {
+    fn = $(NF);
+    gsub (/,/, "", fn);
+    if (fn != "NULL") {
+        print "#pragma weak " fn;
+    }
+}
diff --git a/libio/vtables.c b/libio/vtables.c
new file mode 100644
index 0000000..ac274f8
--- /dev/null
+++ b/libio/vtables.c
@@ -0,0 +1,573 @@
+/* Central definition of libio jump tables.
+   Copyright (C) 1995-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"
+
+/* When linking statically, do not pull in the funcationality we do
+   not need.  vtables-weak.h is generated from the contents of the
+   initializers in this file.  */
+#ifndef SHARED
+# include "vtables-weak.h"
+#endif
+
+/* 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] =
+    {
+      .__finish = _IO_file_finish,
+      .__overflow = _IO_file_overflow,
+      .__underflow = _IO_file_underflow,
+      .__uflow = _IO_default_uflow,
+      .__pbackfail = _IO_default_pbackfail,
+      .__xsputn = _IO_file_xsputn,
+      .__xsgetn = _IO_file_xsgetn,
+      .__seekoff = _IO_new_file_seekoff,
+      .__seekpos = _IO_default_seekpos,
+      .__setbuf = _IO_new_file_setbuf,
+      .__sync = _IO_new_file_sync,
+      .__doallocate = _IO_file_doallocate,
+      .__read = _IO_file_read,
+      .__write = _IO_new_file_write,
+      .__seek = _IO_file_seek,
+      .__close = _IO_file_close,
+      .__stat = _IO_file_stat,
+      .__showmanyc = _IO_default_showmanyc,
+      .__imbue = _IO_default_imbue
+    },
+
+    [IO_VTABLE_file_mmap] =
+    {
+      .__finish = _IO_file_finish,
+      .__overflow = _IO_file_overflow,
+      .__underflow = _IO_file_underflow_mmap,
+      .__uflow = _IO_default_uflow,
+      .__pbackfail = _IO_default_pbackfail,
+      .__xsputn = _IO_new_file_xsputn,
+      .__xsgetn = _IO_file_xsgetn_mmap,
+      .__seekoff = _IO_file_seekoff_mmap,
+      .__seekpos = _IO_default_seekpos,
+      .__setbuf = (_IO_setbuf_t) _IO_file_setbuf_mmap,
+      .__sync = _IO_file_sync_mmap,
+      .__doallocate = _IO_file_doallocate,
+      .__read = _IO_file_read,
+      .__write = _IO_new_file_write,
+      .__seek = _IO_file_seek,
+      .__close = _IO_file_close_mmap,
+      .__stat = _IO_file_stat,
+      .__showmanyc = _IO_default_showmanyc,
+      .__imbue = _IO_default_imbue
+    },
+
+    [IO_VTABLE_file_maybe_mmap] =
+    {
+      .__finish = _IO_file_finish,
+      .__overflow = _IO_file_overflow,
+      .__underflow = _IO_file_underflow_maybe_mmap,
+      .__uflow = _IO_default_uflow,
+      .__pbackfail = _IO_default_pbackfail,
+      .__xsputn = _IO_new_file_xsputn,
+      .__xsgetn = _IO_file_xsgetn_maybe_mmap,
+      .__seekoff = _IO_file_seekoff_maybe_mmap,
+      .__seekpos = _IO_default_seekpos,
+      .__setbuf = (_IO_setbuf_t) _IO_file_setbuf_mmap,
+      .__sync = _IO_new_file_sync,
+      .__doallocate = _IO_file_doallocate,
+      .__read = _IO_file_read,
+      .__write = _IO_new_file_write,
+      .__seek = _IO_file_seek,
+      .__close = _IO_file_close,
+      .__stat = _IO_file_stat,
+      .__showmanyc = _IO_default_showmanyc,
+      .__imbue = _IO_default_imbue
+    },
+
+    [IO_VTABLE_wfile] =
+    {
+      .__finish = _IO_new_file_finish,
+      .__overflow = (_IO_overflow_t) _IO_wfile_overflow,
+      .__underflow = (_IO_underflow_t) _IO_wfile_underflow,
+      .__uflow = (_IO_underflow_t) _IO_wdefault_uflow,
+      .__pbackfail = (_IO_pbackfail_t) _IO_wdefault_pbackfail,
+      .__xsputn = _IO_wfile_xsputn,
+      .__xsgetn = _IO_file_xsgetn,
+      .__seekoff = _IO_wfile_seekoff,
+      .__seekpos = _IO_default_seekpos,
+      .__setbuf = _IO_new_file_setbuf,
+      .__sync = (_IO_sync_t) _IO_wfile_sync,
+      .__doallocate = _IO_wfile_doallocate,
+      .__read = _IO_file_read,
+      .__write = _IO_new_file_write,
+      .__seek = _IO_file_seek,
+      .__close = _IO_file_close,
+      .__stat = _IO_file_stat,
+      .__showmanyc = _IO_default_showmanyc,
+      .__imbue = _IO_default_imbue
+    },
+
+    [IO_VTABLE_wfile_mmap] =
+    {
+      .__finish = _IO_new_file_finish,
+      .__overflow = (_IO_overflow_t) _IO_wfile_overflow,
+      .__underflow = (_IO_underflow_t) _IO_wfile_underflow_mmap,
+      .__uflow = (_IO_underflow_t) _IO_wdefault_uflow,
+      .__pbackfail = (_IO_pbackfail_t) _IO_wdefault_pbackfail,
+      .__xsputn = _IO_wfile_xsputn,
+      .__xsgetn = _IO_file_xsgetn,
+      .__seekoff = _IO_wfile_seekoff,
+      .__seekpos = _IO_default_seekpos,
+      .__setbuf = _IO_file_setbuf_mmap,
+      .__sync = (_IO_sync_t) _IO_wfile_sync,
+      .__doallocate = _IO_wfile_doallocate,
+      .__read = _IO_file_read,
+      .__write = _IO_new_file_write,
+      .__seek = _IO_file_seek,
+      .__close = _IO_file_close_mmap,
+      .__stat = _IO_file_stat,
+      .__showmanyc = _IO_default_showmanyc,
+      .__imbue = _IO_default_imbue
+    },
+
+    [IO_VTABLE_wfile_maybe_mmap] =
+    {
+      .__finish = _IO_new_file_finish,
+      .__overflow = (_IO_overflow_t) _IO_wfile_overflow,
+      .__underflow = (_IO_underflow_t) _IO_wfile_underflow_maybe_mmap,
+      .__uflow = (_IO_underflow_t) _IO_wdefault_uflow,
+      .__pbackfail = (_IO_pbackfail_t) _IO_wdefault_pbackfail,
+      .__xsputn = _IO_wfile_xsputn,
+      .__xsgetn = _IO_file_xsgetn,
+      .__seekoff = _IO_wfile_seekoff,
+      .__seekpos = _IO_default_seekpos,
+      .__setbuf = _IO_file_setbuf_mmap,
+      .__sync = (_IO_sync_t) _IO_wfile_sync,
+      .__doallocate = _IO_wfile_doallocate,
+      .__read = _IO_file_read,
+      .__write = _IO_new_file_write,
+      .__seek = _IO_file_seek,
+      .__close = _IO_file_close,
+      .__stat = _IO_file_stat,
+      .__showmanyc = _IO_default_showmanyc,
+      .__imbue = _IO_default_imbue
+    },
+
+    [IO_VTABLE_mem] =
+    {
+      .__finish = _IO_mem_finish,
+      .__overflow = _IO_str_overflow,
+      .__underflow = _IO_str_underflow,
+      .__uflow = _IO_default_uflow,
+      .__pbackfail = _IO_str_pbackfail,
+      .__xsputn = _IO_default_xsputn,
+      .__xsgetn = _IO_default_xsgetn,
+      .__seekoff = _IO_str_seekoff,
+      .__seekpos = _IO_default_seekpos,
+      .__setbuf = _IO_default_setbuf,
+      .__sync = _IO_mem_sync,
+      .__doallocate = _IO_default_doallocate,
+      .__read = _IO_default_read,
+      .__write = _IO_default_write,
+      .__seek = _IO_default_seek,
+      .__close = _IO_default_close,
+      .__stat = _IO_default_stat,
+      .__showmanyc = _IO_default_showmanyc,
+      .__imbue = _IO_default_imbue
+    },
+
+    [IO_VTABLE_wmem] =
+    {
+      .__finish = _IO_wmem_finish,
+      .__overflow = (_IO_overflow_t) _IO_wstr_overflow,
+      .__underflow = (_IO_underflow_t) _IO_wstr_underflow,
+      .__uflow = (_IO_underflow_t) _IO_wdefault_uflow,
+      .__pbackfail = (_IO_pbackfail_t) _IO_wstr_pbackfail,
+      .__xsputn = _IO_wdefault_xsputn,
+      .__xsgetn = _IO_wdefault_xsgetn,
+      .__seekoff = _IO_wstr_seekoff,
+      .__seekpos = _IO_default_seekpos,
+      .__setbuf = _IO_default_setbuf,
+      .__sync = _IO_wmem_sync,
+      .__doallocate = _IO_wdefault_doallocate,
+      .__read = _IO_default_read,
+      .__write = _IO_default_write,
+      .__seek = _IO_default_seek,
+      .__close = _IO_default_close,
+      .__stat = _IO_default_stat,
+      .__showmanyc = _IO_default_showmanyc,
+      .__imbue = _IO_default_imbue
+    },
+
+    [IO_VTABLE_proc] =
+    {
+      .__finish = _IO_new_file_finish,
+      .__overflow = _IO_new_file_overflow,
+      .__underflow = _IO_new_file_underflow,
+      .__uflow = _IO_default_uflow,
+      .__pbackfail = _IO_default_pbackfail,
+      .__xsputn = _IO_new_file_xsputn,
+      .__xsgetn = _IO_default_xsgetn,
+      .__seekoff = _IO_new_file_seekoff,
+      .__seekpos = _IO_default_seekpos,
+      .__setbuf = _IO_new_file_setbuf,
+      .__sync = _IO_new_file_sync,
+      .__doallocate = _IO_file_doallocate,
+      .__read = _IO_file_read,
+      .__write = _IO_new_file_write,
+      .__seek = _IO_file_seek,
+      .__close = _IO_new_proc_close,
+      .__stat = _IO_file_stat,
+      .__showmanyc = _IO_default_showmanyc,
+      .__imbue = _IO_default_imbue
+    },
+
+    [IO_VTABLE_str] =
+    {
+      .__finish = _IO_str_finish,
+      .__overflow = _IO_str_overflow,
+      .__underflow = _IO_str_underflow,
+      .__uflow = _IO_default_uflow,
+      .__pbackfail = _IO_str_pbackfail,
+      .__xsputn = _IO_default_xsputn,
+      .__xsgetn = _IO_default_xsgetn,
+      .__seekoff = _IO_str_seekoff,
+      .__seekpos = _IO_default_seekpos,
+      .__setbuf = _IO_default_setbuf,
+      .__sync = _IO_default_sync,
+      .__doallocate = _IO_default_doallocate,
+      .__read = _IO_default_read,
+      .__write = _IO_default_write,
+      .__seek = _IO_default_seek,
+      .__close = _IO_default_close,
+      .__stat = _IO_default_stat,
+      .__showmanyc = _IO_default_showmanyc,
+      .__imbue = _IO_default_imbue
+    },
+
+    [IO_VTABLE_str_chk] =
+    {
+      .__finish = _IO_str_finish,
+      .__overflow = _IO_str_chk_overflow,
+      .__underflow = _IO_str_underflow,
+      .__uflow = _IO_default_uflow,
+      .__pbackfail = _IO_str_pbackfail,
+      .__xsputn = _IO_default_xsputn,
+      .__xsgetn = _IO_default_xsgetn,
+      .__seekoff = _IO_str_seekoff,
+      .__seekpos = _IO_default_seekpos,
+      .__setbuf = _IO_default_setbuf,
+      .__sync = _IO_default_sync,
+      .__doallocate = _IO_default_doallocate,
+      .__read = _IO_default_read,
+      .__write = _IO_default_write,
+      .__seek = _IO_default_seek,
+      .__close = _IO_default_close,
+      .__stat = _IO_default_stat,
+      .__showmanyc = _IO_default_showmanyc,
+      .__imbue = _IO_default_imbue
+    },
+
+    [IO_VTABLE_strn] =
+    {
+      .__finish = _IO_str_finish,
+      .__overflow = _IO_strn_overflow,
+      .__underflow = _IO_str_underflow,
+      .__uflow = _IO_default_uflow,
+      .__pbackfail = _IO_str_pbackfail,
+      .__xsputn = _IO_default_xsputn,
+      .__xsgetn = _IO_default_xsgetn,
+      .__seekoff = _IO_str_seekoff,
+      .__seekpos = _IO_default_seekpos,
+      .__setbuf = _IO_default_setbuf,
+      .__sync = _IO_default_sync,
+      .__doallocate = _IO_default_doallocate,
+      .__read = _IO_default_read,
+      .__write = _IO_default_write,
+      .__seek = _IO_default_seek,
+      .__close = _IO_default_close,
+      .__stat = _IO_default_stat,
+      .__showmanyc = _IO_default_showmanyc,
+      .__imbue = _IO_default_imbue
+    },
+
+    [IO_VTABLE_wstr] =
+    {
+      .__finish = _IO_wstr_finish,
+      .__overflow = (_IO_overflow_t) _IO_wstr_overflow,
+      .__underflow = (_IO_underflow_t) _IO_wstr_underflow,
+      .__uflow = (_IO_underflow_t) _IO_wdefault_uflow,
+      .__pbackfail = (_IO_pbackfail_t) _IO_wstr_pbackfail,
+      .__xsputn = _IO_wdefault_xsputn,
+      .__xsgetn = _IO_wdefault_xsgetn,
+      .__seekoff = _IO_wstr_seekoff,
+      .__seekpos = _IO_default_seekpos,
+      .__setbuf = _IO_default_setbuf,
+      .__sync = _IO_default_sync,
+      .__doallocate = _IO_wdefault_doallocate,
+      .__read = _IO_default_read,
+      .__write = _IO_default_write,
+      .__seek = _IO_default_seek,
+      .__close = _IO_default_close,
+      .__stat = _IO_default_stat,
+      .__showmanyc = _IO_default_showmanyc,
+      .__imbue = _IO_default_imbue
+    },
+
+    [IO_VTABLE_wstrn] =
+    {
+      .__finish = _IO_wstr_finish,
+      .__overflow = (_IO_overflow_t) _IO_wstrn_overflow,
+      .__underflow = (_IO_underflow_t) _IO_wstr_underflow,
+      .__uflow = (_IO_underflow_t) _IO_wdefault_uflow,
+      .__pbackfail = (_IO_pbackfail_t) _IO_wstr_pbackfail,
+      .__xsputn = _IO_wdefault_xsputn,
+      .__xsgetn = _IO_wdefault_xsgetn,
+      .__seekoff = _IO_wstr_seekoff,
+      .__seekpos = _IO_default_seekpos,
+      .__setbuf = _IO_default_setbuf,
+      .__sync = _IO_default_sync,
+      .__doallocate = _IO_wdefault_doallocate,
+      .__read = _IO_default_read,
+      .__write = _IO_default_write,
+      .__seek = _IO_default_seek,
+      .__close = _IO_default_close,
+      .__stat = _IO_default_stat,
+      .__showmanyc = _IO_default_showmanyc,
+      .__imbue = _IO_default_imbue
+    },
+
+    [IO_VTABLE_cookie] =
+    {
+      .__finish = _IO_file_finish,
+      .__overflow = _IO_file_overflow,
+      .__underflow = _IO_file_underflow,
+      .__uflow = _IO_default_uflow,
+      .__pbackfail = _IO_default_pbackfail,
+      .__xsputn = _IO_file_xsputn,
+      .__xsgetn = _IO_default_xsgetn,
+      .__seekoff = _IO_cookie_seekoff,
+      .__seekpos = _IO_default_seekpos,
+      .__setbuf = _IO_file_setbuf,
+      .__sync = _IO_file_sync,
+      .__doallocate = _IO_file_doallocate,
+      .__read = _IO_cookie_read,
+      .__write = _IO_cookie_write,
+      .__seek = _IO_cookie_seek,
+      .__close = _IO_cookie_close,
+      .__stat = _IO_default_stat,
+      .__showmanyc = _IO_default_showmanyc,
+      .__imbue = _IO_default_imbue
+    },
+
+    [IO_VTABLE_obstack] =
+    {
+      .__finish = NULL,
+      .__overflow = _IO_obstack_overflow,
+      .__underflow = NULL,
+      .__uflow = NULL,
+      .__pbackfail = NULL,
+      .__xsputn = _IO_obstack_xsputn,
+      .__xsgetn = NULL,
+      .__seekoff = NULL,
+      .__seekpos = NULL,
+      .__setbuf = NULL,
+      .__sync = NULL,
+      .__doallocate = NULL,
+      .__read = NULL,
+      .__write = NULL,
+      .__seek = NULL,
+      .__close = NULL,
+      .__stat = NULL,
+      .__showmanyc = NULL,
+      .__imbue = NULL
+    },
+
+    [IO_VTABLE_printf_helper] =
+    {
+      .__finish = _IO_default_finish,
+      .__overflow = _IO_printf_helper_overflow,
+      .__underflow = _IO_default_underflow,
+      .__uflow = _IO_default_uflow,
+      .__pbackfail = _IO_default_pbackfail,
+      .__xsputn = _IO_default_xsputn,
+      .__xsgetn = _IO_default_xsgetn,
+      .__seekoff = _IO_default_seekoff,
+      .__seekpos = _IO_default_seekpos,
+      .__setbuf = _IO_default_setbuf,
+      .__sync = _IO_default_sync,
+      .__doallocate = _IO_default_doallocate,
+      .__read = _IO_default_read,
+      .__write = _IO_default_write,
+      .__seek = _IO_default_seek,
+      .__close = _IO_default_close,
+      .__stat = _IO_default_stat,
+    },
+
+    [IO_VTABLE_wprintf_helper] =
+    {
+      .__finish = _IO_wdefault_finish,
+      .__overflow = _IO_wprintf_helper_overflow,
+      .__underflow = _IO_default_underflow,
+      .__uflow = _IO_default_uflow,
+      .__pbackfail = (_IO_pbackfail_t) _IO_wdefault_pbackfail,
+      .__xsputn = _IO_wdefault_xsputn,
+      .__xsgetn = _IO_wdefault_xsgetn,
+      .__seekoff = _IO_default_seekoff,
+      .__seekpos = _IO_default_seekpos,
+      .__setbuf = _IO_default_setbuf,
+      .__sync = _IO_default_sync,
+      .__doallocate = _IO_wdefault_doallocate,
+      .__read = _IO_default_read,
+      .__write = _IO_default_write,
+      .__seek = _IO_default_seek,
+      .__close = _IO_default_close,
+      .__stat = _IO_default_stat,
+    },
+
+    /* Obsolete vtables.  */
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1)
+    [IO_VTABLE_old_file] =
+    {
+      .__finish = _IO_old_file_finish,
+      .__overflow = _IO_old_file_overflow,
+      .__underflow = _IO_old_file_underflow,
+      .__uflow = _IO_default_uflow,
+      .__pbackfail = _IO_default_pbackfail,
+      .__xsputn = _IO_old_file_xsputn,
+      .__xsgetn = _IO_default_xsgetn,
+      .__seekoff = _IO_old_file_seekoff,
+      .__seekpos = _IO_default_seekpos,
+      .__setbuf = _IO_old_file_setbuf,
+      .__sync = _IO_old_file_sync,
+      .__doallocate = _IO_file_doallocate,
+      .__read = _IO_file_read,
+      .__write = _IO_old_file_write,
+      .__seek = _IO_file_seek,
+      .__close = _IO_file_close,
+      .__stat = _IO_file_stat
+    },
+
+    [IO_VTABLE_old_proc] =
+    {
+      .__finish = _IO_old_file_finish,
+      .__overflow = _IO_old_file_overflow,
+      .__underflow = _IO_old_file_underflow,
+      .__uflow = _IO_default_uflow,
+      .__pbackfail = _IO_default_pbackfail,
+      .__xsputn = _IO_old_file_xsputn,
+      .__xsgetn = _IO_default_xsgetn,
+      .__seekoff = _IO_old_file_seekoff,
+      .__seekpos = _IO_default_seekpos,
+      .__setbuf = _IO_old_file_setbuf,
+      .__sync = _IO_old_file_sync,
+      .__doallocate = _IO_file_doallocate,
+      .__read = _IO_file_read,
+      .__write = _IO_old_file_write,
+      .__seek = _IO_file_seek,
+      .__close = _IO_old_proc_close,
+      .__stat = _IO_file_stat,
+      .__showmanyc = _IO_default_showmanyc,
+      .__imbue = _IO_default_imbue
+    },
+
+    [IO_VTABLE_old_cookie] =
+    {
+      .__finish = _IO_file_finish,
+      .__overflow = _IO_file_overflow,
+      .__underflow = _IO_file_underflow,
+      .__uflow = _IO_default_uflow,
+      .__pbackfail = _IO_default_pbackfail,
+      .__xsputn = _IO_file_xsputn,
+      .__xsgetn = _IO_default_xsgetn,
+      .__seekoff = _IO_cookie_seekoff,
+      .__seekpos = _IO_default_seekpos,
+      .__setbuf = _IO_file_setbuf,
+      .__sync = _IO_file_sync,
+      .__doallocate = _IO_file_doallocate,
+      .__read = _IO_cookie_read,
+      .__write = _IO_cookie_write,
+      .__seek = _IO_old_cookie_seek,
+      .__close = _IO_cookie_close,
+      .__stat = _IO_default_stat,
+      .__showmanyc = _IO_default_showmanyc,
+      .__imbue = _IO_default_imbue
+    },
+#endif
+  };
+
+
+/* These symbols need to be exported for backwards compatibility.
+   They are no longer used by glibc itself.  */
+
+#ifdef SHARED
+const struct _IO_jump_t _IO_file_jumps =
+{
+  .__finish = _IO_file_finish,
+  .__overflow = _IO_file_overflow,
+  .__underflow = _IO_file_underflow,
+  .__uflow = _IO_default_uflow,
+  .__pbackfail = _IO_default_pbackfail,
+  .__xsputn = _IO_file_xsputn,
+  .__xsgetn = _IO_file_xsgetn,
+  .__seekoff = _IO_new_file_seekoff,
+  .__seekpos = _IO_default_seekpos,
+  .__setbuf = _IO_new_file_setbuf,
+  .__sync = _IO_new_file_sync,
+  .__doallocate = _IO_file_doallocate,
+  .__read = _IO_file_read,
+  .__write = _IO_new_file_write,
+  .__seek = _IO_file_seek,
+  .__close = _IO_file_close,
+  .__stat = _IO_file_stat,
+  .__showmanyc = _IO_default_showmanyc,
+  .__imbue = _IO_default_imbue
+};
+
+const struct _IO_jump_t _IO_wfile_jumps =
+{
+  .__finish = _IO_new_file_finish,
+  .__overflow = (_IO_overflow_t) _IO_wfile_overflow,
+  .__underflow = (_IO_underflow_t) _IO_wfile_underflow,
+  .__uflow = (_IO_underflow_t) _IO_wdefault_uflow,
+  .__pbackfail = (_IO_pbackfail_t) _IO_wdefault_pbackfail,
+  .__xsputn = _IO_wfile_xsputn,
+  .__xsgetn = _IO_file_xsgetn,
+  .__seekoff = _IO_wfile_seekoff,
+  .__seekpos = _IO_default_seekpos,
+  .__setbuf = _IO_new_file_setbuf,
+  .__sync = (_IO_sync_t) _IO_wfile_sync,
+  .__doallocate = _IO_wfile_doallocate,
+  .__read = _IO_file_read,
+  .__write = _IO_new_file_write,
+  .__seek = _IO_file_seek,
+  .__close = _IO_file_close,
+  .__stat = _IO_file_stat,
+  .__showmanyc = _IO_default_showmanyc,
+  .__imbue = _IO_default_imbue
+};
+#endif
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..2e0b505 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..abb9e1d 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..09da13c 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..d96f230 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..763891e 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]