aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdhemerval Zanella Netto <adhemerval.zanella@linaro.org>2022-12-27 18:11:43 -0300
committerAdhemerval Zanella <adhemerval.zanella@linaro.org>2023-03-27 13:57:55 -0300
commit3020f72618e4f1d7338cd42b8bc7b2813e961b5a (patch)
treed61cc39cb5aa140de5331cd1a2ba6ab796db0c81
parentf65ca70deaf38db4ca12458e74cefd8ad9063956 (diff)
downloadglibc-3020f72618e4f1d7338cd42b8bc7b2813e961b5a.tar.xz
glibc-3020f72618e4f1d7338cd42b8bc7b2813e961b5a.zip
libio: Remove the usage of __libc_IO_vtables
Instead of using a special ELF section along with a linker script directive to put the IO vtables within the RELRO section, the libio vtables are all moved to an array marked as data.relro (so linker will place in the RELRO segment without the need of extra directives). To avoid static linking namespace issues and including all vtable referenced objects, all required function pointers are set to weak alias. Checked on x86_64-linux-gnu, i686-linux-gnu, and aarch64-linux-gnu. Reviewed-by: Carlos O'Donell <carlos@redhat.com>
-rw-r--r--Makerules24
-rw-r--r--elf/Makefile16
-rw-r--r--include/libc-symbols.h18
-rw-r--r--libio/Makefile2
-rw-r--r--libio/fileops.c81
-rw-r--r--libio/iofopncook.c60
-rw-r--r--libio/iopopen.c25
-rw-r--r--libio/libio-macros.sym7
-rw-r--r--libio/libioP.h136
-rw-r--r--libio/memstream.c32
-rw-r--r--libio/oldfileops.c23
-rw-r--r--libio/oldiopopen.c23
-rw-r--r--libio/stdio.c3
-rw-r--r--libio/strfile.h2
-rw-r--r--libio/strops.c24
-rw-r--r--libio/tst-vtables-interposed.c5
-rw-r--r--libio/vtables.c478
-rw-r--r--libio/wfileops.c79
-rw-r--r--libio/wmemstream.c32
-rw-r--r--libio/wstrops.c24
-rw-r--r--stdio-common/printf_buffer_as_file.c28
-rw-r--r--stdio-common/wprintf_buffer_as_file.c28
22 files changed, 637 insertions, 513 deletions
diff --git a/Makerules b/Makerules
index 57b3f093c4..16887cb443 100644
--- a/Makerules
+++ b/Makerules
@@ -544,34 +544,10 @@ $(LINK.o) -shared -static-libgcc -Wl,-O1 $(sysdep-LDFLAGS) \
-L$(subst :, -L,$(rpath-link)) -Wl,-rpath-link=$(rpath-link)
endef
-ifeq (yes,$(use-default-link))
# If the linker is good enough, we can let it use its default linker script.
# In the long term the custom linker script will be removed.
shlib-lds =
shlib-lds-flags =
-else
-# binutils only position loadable notes into the first page for binaries,
-# not for shared objects
-# lld --verbose does not dump a linker script. Use -fuse-ld=bfd.
-$(common-objpfx)shlib.lds: $(common-objpfx)config.make $(..)Makerules
- $(LINK.o) -shared -Wl,-O1 \
- -nostdlib -nostartfiles -fuse-ld=bfd \
- $(sysdep-LDFLAGS) $(rtld-LDFLAGS) $(LDFLAGS.so) \
- -Wl,--verbose 2>/dev/null | \
- sed > $@T \
- -e '/^=========/,/^=========/!d;/^=========/d' \
- -e 's@^.*\*(\.jcr).*$$@& \
- PROVIDE(__start___libc_IO_vtables = .);\
- __libc_IO_vtables : { *(__libc_IO_vtables) }\
- PROVIDE(__stop___libc_IO_vtables = .);\
- /DISCARD/ : { *(.gnu.glibc-stub.*) }@'
- test -s $@T
- mv -f $@T $@
-common-generated += shlib.lds
-
-shlib-lds = $(common-objpfx)shlib.lds
-shlib-lds-flags = -T $(shlib-lds)
-endif
define build-shlib
$(build-shlib-helper) -o $@ $(shlib-lds-flags) \
diff --git a/elf/Makefile b/elf/Makefile
index 4d0e04b2a2..be6f2ca068 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -595,23 +595,9 @@ $(objpfx)tst-relro-ldso.out: tst-relro-symbols.py $(..)/scripts/glibcelf.py \
$(objpfx)tst-relro-libc.out: tst-relro-symbols.py $(..)/scripts/glibcelf.py \
$(common-objpfx)libc.so
$(PYTHON) tst-relro-symbols.py $(common-objpfx)libc.so \
- --required=_IO_cookie_jumps \
--required=_IO_file_jumps \
- --required=_IO_file_jumps_maybe_mmap \
- --required=_IO_file_jumps_mmap \
- --required=_IO_mem_jumps \
- --required=_IO_printf_buffer_as_file_jumps \
- --required=_IO_proc_jumps \
- --required=_IO_str_jumps \
--required=_IO_wfile_jumps \
- --required=_IO_wfile_jumps_maybe_mmap \
- --required=_IO_wfile_jumps_mmap \
- --required=_IO_wmem_jumps \
- --required=_IO_wprintf_buffer_as_file_jumps \
- --required=_IO_wstr_jumps \
- --optional=_IO_old_cookie_jumps \
- --optional=_IO_old_file_jumps \
- --optional=_IO_old_proc_jumps \
+ --required=__io_vtables \
> $@ 2>&1; $(evaluate-test)
ifeq ($(run-built-tests),yes)
diff --git a/include/libc-symbols.h b/include/libc-symbols.h
index 155781d448..37c91bb3a4 100644
--- a/include/libc-symbols.h
+++ b/include/libc-symbols.h
@@ -243,20 +243,26 @@ for linking")
This is only necessary when defining something in assembly, or playing
funny alias games where the size should be other than what the compiler
thinks it is. */
-#ifdef __ASSEMBLER__
-# define declare_object_symbol_alias(symbol, original, size) \
+#define declare_object_symbol_alias(symbol, original, size) \
declare_object_symbol_alias_1 (symbol, original, size)
+#ifdef __ASSEMBLER__
# define declare_object_symbol_alias_1(symbol, original, s_size) \
strong_alias (original, symbol) ASM_LINE_SEP \
.type C_SYMBOL_NAME (symbol), %object ASM_LINE_SEP \
.size C_SYMBOL_NAME (symbol), s_size ASM_LINE_SEP
#else /* Not __ASSEMBLER__. */
# ifdef HAVE_ASM_SET_DIRECTIVE
-# define declare_symbol_alias_1_alias(symbol, original) \
- ".set " __SYMBOL_PREFIX #symbol ", " __SYMBOL_PREFIX #original
+# define declare_object_symbol_alias_1(symbol, original, size) \
+ asm (".global " __SYMBOL_PREFIX # symbol "\n" \
+ ".type " __SYMBOL_PREFIX # symbol ", %object\n" \
+ ".set " __SYMBOL_PREFIX #symbol ", " __SYMBOL_PREFIX original "\n" \
+ ".size " __SYMBOL_PREFIX #symbol ", " #size "\n");
# else
-# define declare_symbol_alias_1_alias(symbol, original) \
- __SYMBOL_PREFIX #symbol " = " __SYMBOL_PREFIX #original
+# define declare_object_symbol_alias_1(symbol, original, size) \
+ asm (".global " __SYMBOL_PREFIX # symbol "\n" \
+ ".type " __SYMBOL_PREFIX # symbol ", %object\n" \
+ __SYMBOL_PREFIX #symbol " = " __SYMBOL_PREFIX original "\n" \
+ ".size " __SYMBOL_PREFIX #symbol ", " #size "\n");
# endif /* HAVE_ASM_SET_DIRECTIVE */
#endif /* __ASSEMBLER__ */
diff --git a/libio/Makefile b/libio/Makefile
index 52892a282e..2877fec484 100644
--- a/libio/Makefile
+++ b/libio/Makefile
@@ -51,6 +51,8 @@ routines := \
\
libc_fatal fmemopen oldfmemopen vtables
+gen-as-const-headers += libio-macros.sym
+
tests = tst_swprintf tst_wprintf tst_swscanf tst_wscanf tst_getwc tst_putwc \
tst_wprintf2 tst-widetext test-fmemopen tst-ext tst-ext2 \
tst-fgetws tst-ungetwc1 tst-ungetwc2 tst-swscanf tst-sscanf \
diff --git a/libio/fileops.c b/libio/fileops.c
index b75d748539..58c9e985e4 100644
--- a/libio/fileops.c
+++ b/libio/fileops.c
@@ -815,7 +815,7 @@ _IO_new_file_sync (FILE *fp)
}
libc_hidden_ver (_IO_new_file_sync, _IO_file_sync)
-static int
+int
_IO_file_sync_mmap (FILE *fp)
{
if (fp->_IO_read_ptr != fp->_IO_read_end)
@@ -1109,7 +1109,7 @@ _IO_file_seekoff_mmap (FILE *fp, off64_t offset, int dir, int mode)
return offset;
}
-static off64_t
+off64_t
_IO_file_seekoff_maybe_mmap (FILE *fp, off64_t offset, int dir,
int mode)
{
@@ -1360,7 +1360,7 @@ _IO_file_xsgetn (FILE *fp, void *data, size_t n)
}
libc_hidden_def (_IO_file_xsgetn)
-static size_t
+size_t
_IO_file_xsgetn_mmap (FILE *fp, void *data, size_t n)
{
size_t have;
@@ -1405,7 +1405,7 @@ _IO_file_xsgetn_mmap (FILE *fp, void *data, size_t n)
return s - (char *) data;
}
-static size_t
+size_t
_IO_file_xsgetn_maybe_mmap (FILE *fp, void *data, size_t n)
{
/* We only get here if this is the first attempt to read something.
@@ -1428,76 +1428,3 @@ versioned_symbol (libc, _IO_new_file_seekoff, _IO_file_seekoff, GLIBC_2_1);
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);
-
-const struct _IO_jump_t _IO_file_jumps libio_vtable =
-{
- 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 libio_vtable =
-{
- 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 libio_vtable =
-{
- 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/iofopncook.c b/libio/iofopncook.c
index d6a06c5acb..5511c07c18 100644
--- a/libio/iofopncook.c
+++ b/libio/iofopncook.c
@@ -30,7 +30,7 @@
#include <shlib-compat.h>
#include <pointer_guard.h>
-static ssize_t
+ssize_t
_IO_cookie_read (FILE *fp, void *buf, ssize_t size)
{
struct _IO_cookie_file *cfile = (struct _IO_cookie_file *) fp;
@@ -43,7 +43,7 @@ _IO_cookie_read (FILE *fp, void *buf, ssize_t size)
return read_cb (cfile->__cookie, buf, size);
}
-static ssize_t
+ssize_t
_IO_cookie_write (FILE *fp, const void *buf, ssize_t size)
{
struct _IO_cookie_file *cfile = (struct _IO_cookie_file *) fp;
@@ -63,7 +63,7 @@ _IO_cookie_write (FILE *fp, const void *buf, ssize_t size)
return n;
}
-static off64_t
+off64_t
_IO_cookie_seek (FILE *fp, off64_t offset, int dir)
{
struct _IO_cookie_file *cfile = (struct _IO_cookie_file *) fp;
@@ -77,7 +77,7 @@ _IO_cookie_seek (FILE *fp, off64_t offset, int dir)
? _IO_pos_BAD : offset);
}
-static int
+int
_IO_cookie_close (FILE *fp)
{
struct _IO_cookie_file *cfile = (struct _IO_cookie_file *) fp;
@@ -91,7 +91,7 @@ _IO_cookie_close (FILE *fp)
}
-static off64_t
+off64_t
_IO_cookie_seekoff (FILE *fp, off64_t offset, int dir, int mode)
{
/* We must force the fileops code to always use seek to determine
@@ -100,31 +100,6 @@ _IO_cookie_seekoff (FILE *fp, off64_t offset, int dir, int mode)
return _IO_file_seekoff (fp, offset, dir, mode);
}
-
-static const struct _IO_jump_t _IO_cookie_jumps libio_vtable = {
- 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),
-};
-
-
/* Copy the callbacks from SOURCE to *TARGET, with pointer
mangling. */
static void
@@ -209,7 +184,7 @@ versioned_symbol (libc, _IO_fopencookie, fopencookie, GLIBC_2_2);
#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_2)
-static off64_t
+off64_t
attribute_compat_text_section
_IO_old_cookie_seek (FILE *fp, off64_t offset, int dir)
{
@@ -226,29 +201,6 @@ _IO_old_cookie_seek (FILE *fp, off64_t offset, int dir)
return (ret == -1) ? _IO_pos_BAD : ret;
}
-static const struct _IO_jump_t _IO_old_cookie_jumps libio_vtable = {
- 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),
-};
-
FILE *
attribute_compat_text_section
_IO_old_fopencookie (void *cookie, const char *mode,
diff --git a/libio/iopopen.c b/libio/iopopen.c
index d0545ad5ea..a64033e60f 100644
--- a/libio/iopopen.c
+++ b/libio/iopopen.c
@@ -45,8 +45,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
@@ -297,29 +295,6 @@ _IO_new_proc_close (FILE *fp)
return wstatus;
}
-static const struct _IO_jump_t _IO_proc_jumps libio_vtable = {
- 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/libio-macros.sym b/libio/libio-macros.sym
new file mode 100644
index 0000000000..cfb5cf2841
--- /dev/null
+++ b/libio/libio-macros.sym
@@ -0,0 +1,7 @@
+#include <libioP.h>
+
+--
+
+IO_JUMP_T_SIZE sizeof (struct _IO_jump_t)
+IO_FILE_JUMPS_OFFSET sizeof (struct _IO_jump_t) * IO_FILE_JUMPS
+IO_WFILE_JUMPS_OFFSET sizeof (struct _IO_jump_t) * IO_WFILE_JUMPS
diff --git a/libio/libioP.h b/libio/libioP.h
index 80941b763f..d777553cb0 100644
--- a/libio/libioP.h
+++ b/libio/libioP.h
@@ -469,19 +469,68 @@ extern int _IO_default_sync (FILE *) __THROW;
extern int _IO_default_showmanyc (FILE *) __THROW;
extern void _IO_default_imbue (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 int __printf_buffer_as_file_overflow (FILE *fp, int ch);
+extern size_t __printf_buffer_as_file_xsputn (FILE *fp, const void *buf,
+ size_t len);
+extern wint_t __wprintf_buffer_as_file_overflow (FILE *fp, int ch);
+extern size_t __wprintf_buffer_as_file_xsputn (FILE *fp, const void *buf,
+ size_t len);
+
+enum
+{
+ IO_STR_JUMPS = 0,
+ IO_WSTR_JUMPS = 1,
+ IO_FILE_JUMPS = 2,
+ IO_FILE_JUMPS_MMAP = 3,
+ IO_FILE_JUMPS_MAYBE_MMAP = 4,
+ IO_WFILE_JUMPS = 5,
+ IO_WFILE_JUMPS_MMAP = 6,
+ IO_WFILE_JUMPS_MAYBE_MMAP = 7,
+ IO_COOKIE_JUMPS = 8,
+ IO_PROC_JUMPS = 9,
+ IO_MEM_JUMPS = 10,
+ IO_WMEM_JUMPS = 11,
+ IO_PRINTF_BUFFER_AS_FILE_JUMPS = 12,
+ IO_WPRINTF_BUFFER_AS_FILE_JUMPS = 13,
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1)
+ IO_OLD_FILE_JUMPS = 14,
+ IO_OLD_PROC_JUMPS = 15,
+ IO_OLD_COOKIED_JUMPS = 16,
+ IO_VTABLES_NUM = IO_OLD_COOKIED_JUMPS + 1,
+#elif SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_2)
+ IO_OLD_COOKIED_JUMPS = 14,
+ IO_VTABLES_NUM = IO_OLD_COOKIED_JUMPS + 1,
+#else
+ IO_VTABLES_NUM = IO_WPRINTF_BUFFER_AS_FILE_JUMPS + 1
+#endif
+};
+#define IO_VTABLES_LEN (IO_VTABLES_NUM * sizeof (struct _IO_jump_t))
+
+extern const struct _IO_jump_t __io_vtables[] attribute_hidden;
+#define _IO_str_jumps (__io_vtables[IO_STR_JUMPS])
+#define _IO_wstr_jumps (__io_vtables[IO_WSTR_JUMPS])
+#define _IO_file_jumps (__io_vtables[IO_FILE_JUMPS])
+#define _IO_file_jumps_mmap (__io_vtables[IO_FILE_JUMPS_MMAP])
+#define _IO_file_jumps_maybe_mmap (__io_vtables[IO_FILE_JUMPS_MAYBE_MMAP])
+#define _IO_wfile_jumps (__io_vtables[IO_WFILE_JUMPS])
+#define _IO_wfile_jumps_mmap (__io_vtables[IO_WFILE_JUMPS_MMAP])
+#define _IO_wfile_jumps_maybe_mmap (__io_vtables[IO_WFILE_JUMPS_MAYBE_MMAP])
+#define _IO_cookie_jumps (__io_vtables[IO_COOKIE_JUMPS])
+#define _IO_proc_jumps (__io_vtables[IO_PROC_JUMPS])
+#define _IO_mem_jumps (__io_vtables[IO_MEM_JUMPS])
+#define _IO_wmem_jumps (__io_vtables[IO_WMEM_JUMPS])
+#define _IO_printf_buffer_as_file_jumps (__io_vtables[IO_PRINTF_BUFFER_AS_FILE_JUMPS])
+#define _IO_wprintf_buffer_as_file_jumps (__io_vtables[IO_WPRINTF_BUFFER_AS_FILE_JUMPS])
+#define _IO_old_file_jumps (__io_vtables[IO_OLD_FILE_JUMPS])
+#define _IO_old_proc_jumps (__io_vtables[IO_OLD_PROC_JUMPS])
+#define _IO_old_cookie_jumps (__io_vtables[IO_OLD_COOKIED_JUMPS])
+
+#ifdef SHARED
+# define libio_static_fn_required(name)
+#else
+# define libio_static_fn_required(name) __asm (".globl " #name);
+#endif
+
extern int _IO_do_write (FILE *, const char *, size_t);
libc_hid