From 9edd4a9979f520abc6a3f5c0029966b5cc0f280e Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Sat, 2 Jun 2018 22:00:18 +0300 Subject: libc: Wrap low level glibc io calls for stdio This is much less work and actually works better. --- Makefile | 3 +- src/libc-stdio.c | 42 +++++++++++++++++++++++ src/libc-stdio.h | 102 ------------------------------------------------------- src/libc.c | 9 ++++- 4 files changed, 52 insertions(+), 104 deletions(-) create mode 100644 src/libc-stdio.c delete mode 100644 src/libc-stdio.h diff --git a/Makefile b/Makefile index d5dc142..c7d0515 100644 --- a/Makefile +++ b/Makefile @@ -34,9 +34,10 @@ runtime/libdl.so: private override CPPFLAGS += -D_GNU_SOURCE -DLINKER_DEBUG=1 runtime/libdl.so: private override CFLAGS += -Wno-pedantic -Wno-variadic-macros -Wno-pointer-to-int-cast -Wno-int-to-pointer-cast runtime/libdl.so: wrapper.a src/linker/dlfcn.c src/linker/linker.c src/linker/linker_environ.c src/linker/rt.c src/linker/strlcpy.c runtime/libc.so: private override CPPFLAGS += -D_GNU_SOURCE +runtime/libc.so: private override LDFLAGS += -Wl,-wrap,_IO_file_xsputn runtime/libc.so: private override CFLAGS += -Wno-deprecated-declarations runtime/libc.so: private override LDLIBS += `pkg-config --libs libbsd libunwind` -runtime/libc.so: verbose src/libc.c +runtime/libc.so: verbose src/libc.c src/libc-stdio.c runtime/libpthread.so: private override CPPFLAGS += -D_GNU_SOURCE runtime/libpthread.so: private override LDLIBS += -lpthread runtime/libpthread.so: src/libpthread.c diff --git a/src/libc-stdio.c b/src/libc-stdio.c new file mode 100644 index 0000000..713497b --- /dev/null +++ b/src/libc-stdio.c @@ -0,0 +1,42 @@ +#include + +struct bionic___sFILE { +#if defined(__LP64__) + char __private[152]; +#else + char __private[84]; +#endif +} __attribute__((aligned(sizeof(void*)))); + +// Bionic standard stream support pre-M Android +// Post-M it's saner and they point to stdin/stdout/stderr symbols instead +const struct bionic___sFILE bionic___sF[3] = { + {{ 's', 't', 'd', 'i', 'n' }}, + {{ 's', 't', 'd', 'o', 'u', 't' }}, + {{ 's', 't', 'd', 'e', 'r', 'r' }} +}; + +static inline FILE* +bionic_file_to_glibc_file(FILE *f) +{ + if (f == (void*)&bionic___sF[0]) + return stdin; + else if (f == (void*)&bionic___sF[1]) + return stdout; + else if (f == (void*)&bionic___sF[2]) + return stderr; + return f; +} + +// Wrapping internal glibc VTABLE functions to handle bionic's pre-M crap +// We define __real_IO_file_xsputn in libc.c so linker will link our library, +// it's not used however for anything. + +extern size_t +__real_IO_file_xsputn(FILE *f, const void *buf, size_t n); + +size_t +__wrap_IO_file_xsputn(FILE *f, const void *buf, size_t n) +{ + return __real_IO_file_xsputn(bionic_file_to_glibc_file(f), buf, n); +} diff --git a/src/libc-stdio.h b/src/libc-stdio.h deleted file mode 100644 index 9dacd21..0000000 --- a/src/libc-stdio.h +++ /dev/null @@ -1,102 +0,0 @@ -#pragma once - -#include - -struct bionic___sFILE { -#if defined(__LP64__) - char __private[152]; -#else - char __private[84]; -#endif -} __attribute__((aligned(sizeof(void*)))); - -// Bionic standard stream support pre-M Android -// Post-M it's saner and they point to stdin/stdout/stderr symbols instead -const struct bionic___sFILE bionic___sF[3] = { - {{ 's', 't', 'd', 'i', 'n' }}, - {{ 's', 't', 'd', 'o', 'u', 't' }}, - {{ 's', 't', 'd', 'e', 'r', 'r' }} -}; - -static inline FILE* -bionic_file_to_glibc_file(FILE *f) -{ - if (f == (void*)&bionic___sF[0]) - return stdin; - else if (f == (void*)&bionic___sF[1]) - return stdout; - else if (f == (void*)&bionic___sF[2]) - return stderr; - return f; -} - -FILE* -bionic_freopen(const char *filename, const char *modes, FILE *stream) -{ - return freopen(filename, modes, bionic_file_to_glibc_file(stream)); -} - -int -bionic_fclose(FILE *stream) -{ - return fclose(bionic_file_to_glibc_file(stream)); -} - -int -bionic_fputc(int c, FILE *stream) -{ - return fputc(c, bionic_file_to_glibc_file(stream)); -} - -int -bionic_putc(int c, FILE *stream) -{ - return putc(c, bionic_file_to_glibc_file(stream)); -} - - -int -bionic_fputs(const char *c, FILE *stream) -{ - return fputs(c, bionic_file_to_glibc_file(stream)); -} - -wint_t -bionic_fputwc(wchar_t wc, FILE *stream) -{ - return fputwc(wc, bionic_file_to_glibc_file(stream)); -} - -wint_t -bionic_putwc(wchar_t wc, FILE *stream) -{ - return putwc(wc, bionic_file_to_glibc_file(stream)); -} - -size_t -bionic_fread(void *ptr, size_t size, size_t nmemb, FILE *stream) -{ - char buf[256], fname[256] = {0}; - stream = bionic_file_to_glibc_file(stream); - snprintf(buf, sizeof(buf), "/proc/self/fd/%d", fileno(stream)); - readlink(buf, fname, sizeof(fname)); - verbose("%s (%d)\n%p, %zu, %zu, %p", fname, fileno(stream), ptr, size, nmemb, (void*)stream); - return fread(ptr, size, nmemb, stream); -} - -size_t -bionic_fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream) -{ - char buf[256], fname[256] = {0}; - stream = bionic_file_to_glibc_file(stream); - snprintf(buf, sizeof(buf), "/proc/self/fd/%d", fileno(stream)); - readlink(buf, fname, sizeof(fname)); - verbose("%s (%d)\n%p, %zu, %zu, %p", fname, fileno(stream), ptr, size, nmemb, (void*)stream); - return fwrite(ptr, size, nmemb, stream); -} - -int -bionic_fflush(FILE *stream) -{ - return fflush(bionic_file_to_glibc_file(stream)); -} diff --git a/src/libc.c b/src/libc.c index a61acd0..7d24275 100644 --- a/src/libc.c +++ b/src/libc.c @@ -72,7 +72,14 @@ tkill(int tid, int sig) // Stuff needed for runtime compatibility, but not neccessary for linking // Also stuff that exists in glibc, but needs to be wrapped for runtime compatibility -#include "libc-stdio.h" +// Some defines from app-stdio.c as per GNU linker's manual for --wrap: +// You may wish to provide a __real_malloc function as well, so that links without the +// --wrap option will succeed. If you do this, you should not put the definition of +// __real_malloc in the same file as __wrap_malloc; if you do, the assembler may resolve +// the call before the linker has a chance to wrap it to malloc. + +size_t __real_IO_file_xsputn(FILE *f, const void *buf, size_t n) {} + #include "libc-ctype.h" const unsigned int bionic___page_size = PAGE_SIZE; -- cgit v1.2.3