diff --git a/lib/libc/glibc/README.md b/lib/libc/glibc/README.md
new file mode 100644
index 000000000000..0bcf23ae343d
--- /dev/null
+++ b/lib/libc/glibc/README.md
@@ -0,0 +1,83 @@
+# Zig GNU C Library ("glibc") Support
+
+Zig supports building binaries that will dynamically link against the
+[GNU C Library ("glibc")](https://www.gnu.org/software/libc/) when run.
+This support extends across a range of glibc versions.
+
+By default, Zig binaries will not depend on any external C library, but
+they can be linked against one with the `-lc` option. The target ABI defines
+which C library: `musl` for the [musl C library](https://musl.libc.org/) or
+`gnu` for the GNU C library.
+
+A specific GNU C library version can be chosen with an appropriate
+`-target`. For example, `-target native-native-gnu.2.19` will use the
+default CPU and OS targets, but will link in a run-time dependency on
+glibc v2.19 (or later). Use `zig env` to show the default target and
+version.
+
+Glibc symbols are defined in the `std.c.` namespace in Zig, though the
+`std.os.` namespace is generally what should be used to access C-library
+APIs in Zig code (it is defined depending on the linked C library).
+
+See `src/glibc.zig` for how Zig will build the glibc components. The
+generated shared object files are sufficient only for compile-time
+linking. They are stub libraries that only indicate that which symbols
+will be present at run-time, along with their type and size. The symbols
+do not reference an actual implementation.
+
+## Targets
+
+The GNU C Library supports a very wide set of platforms and architectures.
+The current Zig support for glibc only includes Linux.
+
+Zig supports glibc versions back to v2.17 (2012) as the Zig standard
+library depends on symbols that were introduced in 2.17.
+
+## Glibc stubs
+
+The file `lib/libc/glibc/abilist` is a Zig-specific binary blob that
+defines the supported glibc versions and the set of symbols each version
+must define. See https://github.com/ziglang/glibc-abi-tool for the
+tooling to generate this blob. The code in `glibc.zig` parses the abilist
+to build version-specific stub libraries on demand.
+
+The generated stub library is used for compile-time linking, with the
+expectation that at run-time the real glibc library will provide the
+actual symbol implementations.
+
+### Public Headers
+
+The glibc headers are in `lib/libc/include/generic-glibc/`. These are
+customized and have a couple Zig-specific `#ifdef`s to make the single set
+of headers represent any of the supported glibc versions. There are
+currently a handful of patches to these headers to represent new features
+(e.g. `reallocarray`) or changes in implementation (e.g., the `stat()`
+family of functions).
+
+The related Zig https://github.com/ziglang/universal-headers is a project
+designed to more robustly build multi-version header files suitable for
+compilation across a variety of target C library versions.
+
+## Glibc static C-Runtime object files and libraries
+
+Linking against glibc also implies linking against several, generally
+"invisible" glibc C Runtime libraries: `crti.o`, `crtn.o`, `Scrt1.o` and
+`libc_nonshared.a`. These objects are linked into generated Zig binaries
+and are not run-time linking dependencies. Generally they provide
+bootstrapping, initialization, and mapping of un-versioned public APIs to
+glibc-private versioned APIs.
+
+Like the public headers, these files contain a couple customiziations for
+Zig to be able to build for any supported glibc version. E.g., for glibc
+versions before v2.32, `libc_nonshared.a` contained stubs that directed
+the `fstat()` call to a versioned `__fxstat()` call.
+
+These files used for these objects are in `lib/libc/glibc`. See the
+`tools/update_glibc.zig` tool for updating content in here from the
+upstream glibc.
+
+# More Information
+
+See
+https://github.com/ziglang/zig/commit/2314051acaad37dd5630dd7eca08571d620d6496
+for an example commit that updates glibc (to v2.38).
diff --git a/lib/libc/glibc/include/libc-symbols.h b/lib/libc/glibc/include/libc-symbols.h
index 57946144888f..d684c9621482 100644
--- a/lib/libc/glibc/include/libc-symbols.h
+++ b/lib/libc/glibc/include/libc-symbols.h
@@ -155,6 +155,18 @@
extern __typeof (name) aliasname __attribute__ ((weak, alias (#name))) \
__attribute_copy__ (name);
+/* Zig patch. weak_hidden_alias was removed from glibc v2.36 (v2.37?), Zig
+ needs it for the v2.32 and earlier {f,l,}stat wrappers, so only include
+ in this header for 2.32 and earlier. */
+#if (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 32) || __GLIBC__ < 2
+# define weak_hidden_alias(name, aliasname) \
+ _weak_hidden_alias (name, aliasname)
+# define _weak_hidden_alias(name, aliasname) \
+ extern __typeof (name) aliasname \
+ __attribute__ ((weak, alias (#name), __visibility__ ("hidden"))) \
+ __attribute_copy__ (name);
+#endif
+
/* Declare SYMBOL as weak undefined symbol (resolved to 0 if not defined). */
# define weak_extern(symbol) _weak_extern (weak symbol)
# define _weak_extern(expr) _Pragma (#expr)
diff --git a/lib/libc/glibc/io/fstat-2.32.c b/lib/libc/glibc/io/fstat-2.32.c
new file mode 100644
index 000000000000..6ce077dc4ae2
--- /dev/null
+++ b/lib/libc/glibc/io/fstat-2.32.c
@@ -0,0 +1,55 @@
+/* Copyright (C) 1996-2020 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.
+
+ In addition to the permissions in the GNU Lesser General Public
+ License, the Free Software Foundation gives you unlimited
+ permission to link the compiled version of this file with other
+ programs, and to distribute those programs without any restriction
+ coming from the use of this file. (The GNU Lesser General Public
+ License restrictions do apply in other respects; for example, they
+ cover modification of the file, and distribution when not linked
+ into another program.)
+
+ Note that people who make modified versions of this file are not
+ obligated to grant this special exception for their modified
+ versions; it is their choice whether to do so. The GNU Lesser
+ General Public License gives permission to release a modified
+ version without this exception; this exception also makes it
+ possible to release a modified version which carries forward this
+ exception.
+
+ 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
+ . */
+
+#include
+
+/* This definition is only used if inlining fails for this function; see
+ the last page of . The real work is done by the `x'
+ function which is passed a version number argument. We arrange in the
+ makefile that when not inlined this function is always statically
+ linked; that way a dynamically-linked executable always encodes the
+ version number corresponding to the data structures it uses, so the `x'
+ functions in the shared library can adapt without needing to recompile
+ all callers. */
+
+#undef fstat
+#undef __fstat
+int
+attribute_hidden
+__fstat (int fd, struct stat *buf)
+{
+ return __fxstat (_STAT_VER, fd, buf);
+}
+
+weak_hidden_alias (__fstat, fstat)
diff --git a/lib/libc/glibc/io/fstat64-2.32.c b/lib/libc/glibc/io/fstat64-2.32.c
new file mode 100644
index 000000000000..c4dd3acd6046
--- /dev/null
+++ b/lib/libc/glibc/io/fstat64-2.32.c
@@ -0,0 +1,52 @@
+/* Copyright (C) 1996-2020 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.
+
+ In addition to the permissions in the GNU Lesser General Public
+ License, the Free Software Foundation gives you unlimited
+ permission to link the compiled version of this file with other
+ programs, and to distribute those programs without any restriction
+ coming from the use of this file. (The GNU Lesser General Public
+ License restrictions do apply in other respects; for example, they
+ cover modification of the file, and distribution when not linked
+ into another program.)
+
+ Note that people who make modified versions of this file are not
+ obligated to grant this special exception for their modified
+ versions; it is their choice whether to do so. The GNU Lesser
+ General Public License gives permission to release a modified
+ version without this exception; this exception also makes it
+ possible to release a modified version which carries forward this
+ exception.
+
+ 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
+ . */
+
+#include
+
+/* This definition is only used if inlining fails for this function; see
+ the last page of . The real work is done by the `x'
+ function which is passed a version number argument. We arrange in the
+ makefile that when not inlined this function is always statically
+ linked; that way a dynamically-linked executable always encodes the
+ version number corresponding to the data structures it uses, so the `x'
+ functions in the shared library can adapt without needing to recompile
+ all callers. */
+
+#undef fstat64
+int
+attribute_hidden
+fstat64 (int fd, struct stat64 *buf)
+{
+ return __fxstat64 (_STAT_VER, fd, buf);
+}
diff --git a/lib/libc/glibc/io/fstatat-2.32.c b/lib/libc/glibc/io/fstatat-2.32.c
new file mode 100644
index 000000000000..edc773487abf
--- /dev/null
+++ b/lib/libc/glibc/io/fstatat-2.32.c
@@ -0,0 +1,52 @@
+/* Copyright (C) 2005-2020 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.
+
+ In addition to the permissions in the GNU Lesser General Public
+ License, the Free Software Foundation gives you unlimited
+ permission to link the compiled version of this file with other
+ programs, and to distribute those programs without any restriction
+ coming from the use of this file. (The GNU Lesser General Public
+ License restrictions do apply in other respects; for example, they
+ cover modification of the file, and distribution when not linked
+ into another program.)
+
+ Note that people who make modified versions of this file are not
+ obligated to grant this special exception for their modified
+ versions; it is their choice whether to do so. The GNU Lesser
+ General Public License gives permission to release a modified
+ version without this exception; this exception also makes it
+ possible to release a modified version which carries forward this
+ exception.
+
+ 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
+ . */
+
+#include
+
+/* This definition is only used if inlining fails for this function; see
+ the last page of . The real work is done by the `x'
+ function which is passed a version number argument. We arrange in the
+ makefile that when not inlined this function is always statically
+ linked; that way a dynamically-linked executable always encodes the
+ version number corresponding to the data structures it uses, so the `x'
+ functions in the shared library can adapt without needing to recompile
+ all callers. */
+
+#undef fstatat
+int
+attribute_hidden
+fstatat (int fd, const char *file, struct stat *buf, int flag)
+{
+ return __fxstatat (_STAT_VER, fd, file, buf, flag);
+}
diff --git a/lib/libc/glibc/io/fstatat64-2.32.c b/lib/libc/glibc/io/fstatat64-2.32.c
new file mode 100644
index 000000000000..b57133bd9093
--- /dev/null
+++ b/lib/libc/glibc/io/fstatat64-2.32.c
@@ -0,0 +1,52 @@
+/* Copyright (C) 2005-2020 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.
+
+ In addition to the permissions in the GNU Lesser General Public
+ License, the Free Software Foundation gives you unlimited
+ permission to link the compiled version of this file with other
+ programs, and to distribute those programs without any restriction
+ coming from the use of this file. (The GNU Lesser General Public
+ License restrictions do apply in other respects; for example, they
+ cover modification of the file, and distribution when not linked
+ into another program.)
+
+ Note that people who make modified versions of this file are not
+ obligated to grant this special exception for their modified
+ versions; it is their choice whether to do so. The GNU Lesser
+ General Public License gives permission to release a modified
+ version without this exception; this exception also makes it
+ possible to release a modified version which carries forward this
+ exception.
+
+ 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
+ . */
+
+#include
+
+/* This definition is only used if inlining fails for this function; see
+ the last page of . The real work is done by the `x'
+ function which is passed a version number argument. We arrange in the
+ makefile that when not inlined this function is always statically
+ linked; that way a dynamically-linked executable always encodes the
+ version number corresponding to the data structures it uses, so the `x'
+ functions in the shared library can adapt without needing to recompile
+ all callers. */
+
+#undef fstatat64
+int
+attribute_hidden
+fstatat64 (int fd, const char *file, struct stat64 *buf, int flag)
+{
+ return __fxstatat64 (_STAT_VER, fd, file, buf, flag);
+}
diff --git a/lib/libc/glibc/io/lstat-2.32.c b/lib/libc/glibc/io/lstat-2.32.c
new file mode 100644
index 000000000000..7134741106d7
--- /dev/null
+++ b/lib/libc/glibc/io/lstat-2.32.c
@@ -0,0 +1,55 @@
+/* Copyright (C) 1996-2020 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.
+
+ In addition to the permissions in the GNU Lesser General Public
+ License, the Free Software Foundation gives you unlimited
+ permission to link the compiled version of this file with other
+ programs, and to distribute those programs without any restriction
+ coming from the use of this file. (The GNU Lesser General Public
+ License restrictions do apply in other respects; for example, they
+ cover modification of the file, and distribution when not linked
+ into another program.)
+
+ Note that people who make modified versions of this file are not
+ obligated to grant this special exception for their modified
+ versions; it is their choice whether to do so. The GNU Lesser
+ General Public License gives permission to release a modified
+ version without this exception; this exception also makes it
+ possible to release a modified version which carries forward this
+ exception.
+
+ 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
+ . */
+
+#include
+
+/* This definition is only used if inlining fails for this function; see
+ the last page of . The real work is done by the `x'
+ function which is passed a version number argument. We arrange in the
+ makefile that when not inlined this function is always statically
+ linked; that way a dynamically-linked executable always encodes the
+ version number corresponding to the data structures it uses, so the `x'
+ functions in the shared library can adapt without needing to recompile
+ all callers. */
+
+#undef lstat
+#undef __lstat
+int
+attribute_hidden
+__lstat (const char *file, struct stat *buf)
+{
+ return __lxstat (_STAT_VER, file, buf);
+}
+
+weak_hidden_alias (__lstat, lstat)
diff --git a/lib/libc/glibc/io/lstat64-2.32.c b/lib/libc/glibc/io/lstat64-2.32.c
new file mode 100644
index 000000000000..a890da71a853
--- /dev/null
+++ b/lib/libc/glibc/io/lstat64-2.32.c
@@ -0,0 +1,52 @@
+/* Copyright (C) 1996-2020 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.
+
+ In addition to the permissions in the GNU Lesser General Public
+ License, the Free Software Foundation gives you unlimited
+ permission to link the compiled version of this file with other
+ programs, and to distribute those programs without any restriction
+ coming from the use of this file. (The GNU Lesser General Public
+ License restrictions do apply in other respects; for example, they
+ cover modification of the file, and distribution when not linked
+ into another program.)
+
+ Note that people who make modified versions of this file are not
+ obligated to grant this special exception for their modified
+ versions; it is their choice whether to do so. The GNU Lesser
+ General Public License gives permission to release a modified
+ version without this exception; this exception also makes it
+ possible to release a modified version which carries forward this
+ exception.
+
+ 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
+ . */
+
+#include
+
+/* This definition is only used if inlining fails for this function; see
+ the last page of . The real work is done by the `x'
+ function which is passed a version number argument. We arrange in the
+ makefile that when not inlined this function is always statically
+ linked; that way a dynamically-linked executable always encodes the
+ version number corresponding to the data structures it uses, so the `x'
+ functions in the shared library can adapt without needing to recompile
+ all callers. */
+
+#undef lstat64
+int
+attribute_hidden
+lstat64 (const char *file, struct stat64 *buf)
+{
+ return __lxstat64 (_STAT_VER, file, buf);
+}
diff --git a/lib/libc/glibc/io/mknod-2.32.c b/lib/libc/glibc/io/mknod-2.32.c
new file mode 100644
index 000000000000..ac968292303d
--- /dev/null
+++ b/lib/libc/glibc/io/mknod-2.32.c
@@ -0,0 +1,55 @@
+/* Copyright (C) 1995-2020 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.
+
+ In addition to the permissions in the GNU Lesser General Public
+ License, the Free Software Foundation gives you unlimited
+ permission to link the compiled version of this file with other
+ programs, and to distribute those programs without any restriction
+ coming from the use of this file. (The GNU Lesser General Public
+ License restrictions do apply in other respects; for example, they
+ cover modification of the file, and distribution when not linked
+ into another program.)
+
+ Note that people who make modified versions of this file are not
+ obligated to grant this special exception for their modified
+ versions; it is their choice whether to do so. The GNU Lesser
+ General Public License gives permission to release a modified
+ version without this exception; this exception also makes it
+ possible to release a modified version which carries forward this
+ exception.
+
+ 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
+ . */
+
+
+#include
+#include
+
+/* This definition is only used if inlining fails for this function; see
+ the last page of . The real work is done by the `x'
+ function which is passed a version number argument. We arrange in the
+ makefile that when not inlined this function is always statically
+ linked; that way a dynamically-linked executable always encodes the
+ version number corresponding to the data structures it uses, so the `x'
+ functions in the shared library can adapt without needing to recompile
+ all callers. */
+
+int
+attribute_hidden
+__mknod (const char *path, mode_t mode, dev_t dev)
+{
+ return __xmknod (_MKNOD_VER, path, mode, &dev);
+}
+
+weak_hidden_alias (__mknod, mknod)
diff --git a/lib/libc/glibc/io/mknodat-2.32.c b/lib/libc/glibc/io/mknodat-2.32.c
new file mode 100644
index 000000000000..65c9f1aa9c2d
--- /dev/null
+++ b/lib/libc/glibc/io/mknodat-2.32.c
@@ -0,0 +1,53 @@
+/* Copyright (C) 1995-2020 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.
+
+ In addition to the permissions in the GNU Lesser General Public
+ License, the Free Software Foundation gives you unlimited
+ permission to link the compiled version of this file with other
+ programs, and to distribute those programs without any restriction
+ coming from the use of this file. (The GNU Lesser General Public
+ License restrictions do apply in other respects; for example, they
+ cover modification of the file, and distribution when not linked
+ into another program.)
+
+ Note that people who make modified versions of this file are not
+ obligated to grant this special exception for their modified
+ versions; it is their choice whether to do so. The GNU Lesser
+ General Public License gives permission to release a modified
+ version without this exception; this exception also makes it
+ possible to release a modified version which carries forward this
+ exception.
+
+ 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
+ . */
+
+
+#include
+#include
+
+/* This definition is only used if inlining fails for this function; see
+ the last page of . The real work is done by the `x'
+ function which is passed a version number argument. We arrange in the
+ makefile that when not inlined this function is always statically
+ linked; that way a dynamically-linked executable always encodes the
+ version number corresponding to the data structures it uses, so the `x'
+ functions in the shared library can adapt without needing to recompile
+ all callers. */
+
+int
+attribute_hidden
+mknodat (int fd, const char *path, mode_t mode, dev_t dev)
+{
+ return __xmknodat (_MKNOD_VER, fd, path, mode, &dev);
+}
diff --git a/lib/libc/glibc/io/stat-2.32.c b/lib/libc/glibc/io/stat-2.32.c
new file mode 100644
index 000000000000..8c3cd877c8c3
--- /dev/null
+++ b/lib/libc/glibc/io/stat-2.32.c
@@ -0,0 +1,54 @@
+/* Copyright (C) 1996-2020 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.
+
+ In addition to the permissions in the GNU Lesser General Public
+ License, the Free Software Foundation gives you unlimited
+ permission to link the compiled version of this file with other
+ programs, and to distribute those programs without any restriction
+ coming from the use of this file. (The GNU Lesser General Public
+ License restrictions do apply in other respects; for example, they
+ cover modification of the file, and distribution when not linked
+ into another program.)
+
+ Note that people who make modified versions of this file are not
+ obligated to grant this special exception for their modified
+ versions; it is their choice whether to do so. The GNU Lesser
+ General Public License gives permission to release a modified
+ version without this exception; this exception also makes it
+ possible to release a modified version which carries forward this
+ exception.
+
+ 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
+ . */
+
+#include
+
+/* This definition is only used if inlining fails for this function; see
+ the last page of . The real work is done by the `x'
+ function which is passed a version number argument. We arrange in the
+ makefile that when not inlined this function is always statically
+ linked; that way a dynamically-linked executable always encodes the
+ version number corresponding to the data structures it uses, so the `x'
+ functions in the shared library can adapt without needing to recompile
+ all callers. */
+
+#undef stat
+int
+attribute_hidden
+__stat (const char *file, struct stat *buf)
+{
+ return __xstat (_STAT_VER, file, buf);
+}
+
+weak_hidden_alias (__stat, stat)
diff --git a/lib/libc/glibc/io/stat64-2.32.c b/lib/libc/glibc/io/stat64-2.32.c
new file mode 100644
index 000000000000..8b6b662f3ac4
--- /dev/null
+++ b/lib/libc/glibc/io/stat64-2.32.c
@@ -0,0 +1,52 @@
+/* Copyright (C) 1996-2020 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.
+
+ In addition to the permissions in the GNU Lesser General Public
+ License, the Free Software Foundation gives you unlimited
+ permission to link the compiled version of this file with other
+ programs, and to distribute those programs without any restriction
+ coming from the use of this file. (The GNU Lesser General Public
+ License restrictions do apply in other respects; for example, they
+ cover modification of the file, and distribution when not linked
+ into another program.)
+
+ Note that people who make modified versions of this file are not
+ obligated to grant this special exception for their modified
+ versions; it is their choice whether to do so. The GNU Lesser
+ General Public License gives permission to release a modified
+ version without this exception; this exception also makes it
+ possible to release a modified version which carries forward this
+ exception.
+
+ 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
+ . */
+
+#include
+
+/* This definition is only used if inlining fails for this function; see
+ the last page of . The real work is done by the `x'
+ function which is passed a version number argument. We arrange in the
+ makefile that when not inlined this function is always statically
+ linked; that way a dynamically-linked executable always encodes the
+ version number corresponding to the data structures it uses, so the `x'
+ functions in the shared library can adapt without needing to recompile
+ all callers. */
+
+#undef stat64
+int
+attribute_hidden
+stat64 (const char *file, struct stat64 *buf)
+{
+ return __xstat64 (_STAT_VER, file, buf);
+}
diff --git a/lib/libc/glibc/sysdeps/unix/sysv/linux/alpha/kernel_stat.h b/lib/libc/glibc/sysdeps/unix/sysv/linux/alpha/kernel_stat.h
deleted file mode 100644
index a292920969b2..000000000000
--- a/lib/libc/glibc/sysdeps/unix/sysv/linux/alpha/kernel_stat.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/* Definition of `struct stat' used in the kernel. */
-struct kernel_stat
- {
- unsigned int st_dev;
- unsigned int st_ino;
- unsigned int st_mode;
- unsigned int st_nlink;
- unsigned int st_uid;
- unsigned int st_gid;
- unsigned int st_rdev;
- long int st_size;
- unsigned long int st_atime_sec;
- unsigned long int st_mtime_sec;
- unsigned long int st_ctime_sec;
- unsigned int st_blksize;
- int st_blocks;
- unsigned int st_flags;
- unsigned int st_gen;
- };
-
-/* Definition of `struct stat64' used in the kernel. */
-struct kernel_stat64
- {
- unsigned long st_dev;
- unsigned long st_ino;
- unsigned long st_rdev;
- long st_size;
- unsigned long st_blocks;
-
- unsigned int st_mode;
- unsigned int st_uid;
- unsigned int st_gid;
- unsigned int st_blksize;
- unsigned int st_nlink;
- unsigned int __pad0;
-
- unsigned long st_atime_sec;
- unsigned long st_atimensec;
- unsigned long st_mtime_sec;
- unsigned long st_mtimensec;
- unsigned long st_ctime_sec;
- unsigned long st_ctimensec;
- long __glibc_reserved[3];
- };
-
-/* Definition of `struct stat' used by glibc 2.0. */
-struct glibc2_stat
- {
- __dev_t st_dev;
- __ino_t st_ino;
- __mode_t st_mode;
- __nlink_t st_nlink;
- __uid_t st_uid;
- __gid_t st_gid;
- __dev_t st_rdev;
- __off_t st_size;
- __time_t st_atime_sec;
- __time_t st_mtime_sec;
- __time_t st_ctime_sec;
- unsigned int st_blksize;
- int st_blocks;
- unsigned int st_flags;
- unsigned int st_gen;
- };
-
-/* Definition of `struct stat' used by glibc 2.1. */
-struct glibc21_stat
- {
- __dev_t st_dev;
- __ino64_t st_ino;
- __mode_t st_mode;
- __nlink_t st_nlink;
- __uid_t st_uid;
- __gid_t st_gid;
- __dev_t st_rdev;
- __off_t st_size;
- __time_t st_atime_sec;
- __time_t st_mtime_sec;
- __time_t st_ctime_sec;
- __blkcnt64_t st_blocks;
- __blksize_t st_blksize;
- unsigned int st_flags;
- unsigned int st_gen;
- int __pad3;
- long __glibc_reserved[4];
- };
-
-#define STAT_IS_KERNEL_STAT 0
-#define STAT64_IS_KERNEL_STAT64 1
-#define XSTAT_IS_XSTAT64 1
-#define STATFS_IS_STATFS64 0
diff --git a/lib/libc/glibc/sysdeps/unix/sysv/linux/arm/kernel_stat.h b/lib/libc/glibc/sysdeps/unix/sysv/linux/arm/kernel_stat.h
deleted file mode 100644
index b1bc1459f08e..000000000000
--- a/lib/libc/glibc/sysdeps/unix/sysv/linux/arm/kernel_stat.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/* Definition of `struct stat' used in the kernel.. */
-struct kernel_stat
- {
- unsigned short int st_dev;
- unsigned short int __pad1;
-#define _HAVE___PAD1
- unsigned long int st_ino;
- unsigned short int st_mode;
- unsigned short int st_nlink;
- unsigned short int st_uid;
- unsigned short int st_gid;
- unsigned short int st_rdev;
- unsigned short int __pad2;
-#define _HAVE___PAD2
- unsigned long int st_size;
- unsigned long int st_blksize;
- unsigned long int st_blocks;
- struct timespec st_atim;
- struct timespec st_mtim;
- struct timespec st_ctim;
- unsigned long int __glibc_reserved4;
-#define _HAVE___UNUSED4
- unsigned long int __glibc_reserved5;
-#define _HAVE___UNUSED5
- };
-
-#define _HAVE_STAT___UNUSED4
-#define _HAVE_STAT___UNUSED5
-#define _HAVE_STAT___PAD1
-#define _HAVE_STAT___PAD2
-#define _HAVE_STAT_NSEC
-#define _HAVE_STAT64___PAD1
-#define _HAVE_STAT64___PAD2
-#define _HAVE_STAT64___ST_INO
-#define _HAVE_STAT64_NSEC
-
-#define STAT_IS_KERNEL_STAT 0
-#define STAT64_IS_KERNEL_STAT64 1
-#define XSTAT_IS_XSTAT64 0
-#define STATFS_IS_STATFS64 0
diff --git a/lib/libc/glibc/sysdeps/unix/sysv/linux/hppa/kernel_stat.h b/lib/libc/glibc/sysdeps/unix/sysv/linux/hppa/kernel_stat.h
deleted file mode 100644
index e8ad135e7023..000000000000
--- a/lib/libc/glibc/sysdeps/unix/sysv/linux/hppa/kernel_stat.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/* definition of "struct stat" from the kernel */
-struct kernel_stat {
- unsigned long st_dev; /* dev_t is 32 bits on parisc */
- unsigned long st_ino; /* 32 bits */
- unsigned short st_mode; /* 16 bits */
- unsigned short st_nlink; /* 16 bits */
- unsigned short st_reserved1; /* old st_uid */
- unsigned short st_reserved2; /* old st_gid */
- unsigned long st_rdev;
- unsigned long st_size;
- struct timespec st_atim;
- struct timespec st_mtim;
- struct timespec st_ctim;
- long st_blksize;
- long st_blocks;
- unsigned long __glibc_reserved1; /* ACL stuff */
- unsigned long __glibc_reserved2; /* network */
- unsigned long __glibc_reserved3; /* network */
- unsigned long __glibc_reserved4; /* cnodes */
- unsigned short __glibc_reserved5; /* netsite */
- short st_fstype;
- unsigned long st_realdev;
- unsigned short st_basemode;
- unsigned short st_spareshort;
- unsigned long st_uid;
- unsigned long st_gid;
- unsigned long st_spare4[3];
-};
-
-#define _HAVE_STAT_NSEC
-#define _HAVE_STAT64_NSEC
-
-#define STAT_IS_KERNEL_STAT 0
-#define STAT64_IS_KERNEL_STAT64 1
-#define XSTAT_IS_XSTAT64 0
-#define STATFS_IS_STATFS64 0
diff --git a/lib/libc/glibc/sysdeps/unix/sysv/linux/i386/kernel_stat.h b/lib/libc/glibc/sysdeps/unix/sysv/linux/i386/kernel_stat.h
deleted file mode 100644
index b1bc1459f08e..000000000000
--- a/lib/libc/glibc/sysdeps/unix/sysv/linux/i386/kernel_stat.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/* Definition of `struct stat' used in the kernel.. */
-struct kernel_stat
- {
- unsigned short int st_dev;
- unsigned short int __pad1;
-#define _HAVE___PAD1
- unsigned long int st_ino;
- unsigned short int st_mode;
- unsigned short int st_nlink;
- unsigned short int st_uid;
- unsigned short int st_gid;
- unsigned short int st_rdev;
- unsigned short int __pad2;
-#define _HAVE___PAD2
- unsigned long int st_size;
- unsigned long int st_blksize;
- unsigned long int st_blocks;
- struct timespec st_atim;
- struct timespec st_mtim;
- struct timespec st_ctim;
- unsigned long int __glibc_reserved4;
-#define _HAVE___UNUSED4
- unsigned long int __glibc_reserved5;
-#define _HAVE___UNUSED5
- };
-
-#define _HAVE_STAT___UNUSED4
-#define _HAVE_STAT___UNUSED5
-#define _HAVE_STAT___PAD1
-#define _HAVE_STAT___PAD2
-#define _HAVE_STAT_NSEC
-#define _HAVE_STAT64___PAD1
-#define _HAVE_STAT64___PAD2
-#define _HAVE_STAT64___ST_INO
-#define _HAVE_STAT64_NSEC
-
-#define STAT_IS_KERNEL_STAT 0
-#define STAT64_IS_KERNEL_STAT64 1
-#define XSTAT_IS_XSTAT64 0
-#define STATFS_IS_STATFS64 0
diff --git a/lib/libc/glibc/sysdeps/unix/sysv/linux/kstat_cp.h b/lib/libc/glibc/sysdeps/unix/sysv/linux/kstat_cp.h
deleted file mode 100644
index 69397db0d2ee..000000000000
--- a/lib/libc/glibc/sysdeps/unix/sysv/linux/kstat_cp.h
+++ /dev/null
@@ -1,2 +0,0 @@
-/* Empty, it is overridden by an architecture which might require copy to or
- from a kernel_stat stat struct to glibc export stat{64}. */
diff --git a/lib/libc/glibc/sysdeps/unix/sysv/linux/m68k/kernel_stat.h b/lib/libc/glibc/sysdeps/unix/sysv/linux/m68k/kernel_stat.h
deleted file mode 100644
index b1bc1459f08e..000000000000
--- a/lib/libc/glibc/sysdeps/unix/sysv/linux/m68k/kernel_stat.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/* Definition of `struct stat' used in the kernel.. */
-struct kernel_stat
- {
- unsigned short int st_dev;
- unsigned short int __pad1;
-#define _HAVE___PAD1
- unsigned long int st_ino;
- unsigned short int st_mode;
- unsigned short int st_nlink;
- unsigned short int st_uid;
- unsigned short int st_gid;
- unsigned short int st_rdev;
- unsigned short int __pad2;
-#define _HAVE___PAD2
- unsigned long int st_size;
- unsigned long int st_blksize;
- unsigned long int st_blocks;
- struct timespec st_atim;
- struct timespec st_mtim;
- struct timespec st_ctim;
- unsigned long int __glibc_reserved4;
-#define _HAVE___UNUSED4
- unsigned long int __glibc_reserved5;
-#define _HAVE___UNUSED5
- };
-
-#define _HAVE_STAT___UNUSED4
-#define _HAVE_STAT___UNUSED5
-#define _HAVE_STAT___PAD1
-#define _HAVE_STAT___PAD2
-#define _HAVE_STAT_NSEC
-#define _HAVE_STAT64___PAD1
-#define _HAVE_STAT64___PAD2
-#define _HAVE_STAT64___ST_INO
-#define _HAVE_STAT64_NSEC
-
-#define STAT_IS_KERNEL_STAT 0
-#define STAT64_IS_KERNEL_STAT64 1
-#define XSTAT_IS_XSTAT64 0
-#define STATFS_IS_STATFS64 0
diff --git a/lib/libc/glibc/sysdeps/unix/sysv/linux/mips/kernel_stat.h b/lib/libc/glibc/sysdeps/unix/sysv/linux/mips/kernel_stat.h
deleted file mode 100644
index 19524f7ea442..000000000000
--- a/lib/libc/glibc/sysdeps/unix/sysv/linux/mips/kernel_stat.h
+++ /dev/null
@@ -1,75 +0,0 @@
-#ifndef _KERNEL_STAT_H
-#define _KERNEL_STAT_H
-
-#include
-/* As tempting as it is to define XSTAT_IS_XSTAT64 for n64, the
- userland data structures are not identical, because of different
- padding. */
-/* Definition of `struct stat' used in the kernel. */
-#if _MIPS_SIM != _ABIO32
-struct kernel_stat
- {
- unsigned int st_dev;
- unsigned int __pad1[3];
- unsigned long long st_ino;
- unsigned int st_mode;
- unsigned int st_nlink;
- int st_uid;
- int st_gid;
- unsigned int st_rdev;
- unsigned int __pad2[3];
- long long st_size;
- unsigned int st_atime_sec;
- unsigned int st_atime_nsec;
- unsigned int st_mtime_sec;
- unsigned int st_mtime_nsec;
- unsigned int st_ctime_sec;
- unsigned int st_ctime_nsec;
- unsigned int st_blksize;
- unsigned int __pad3;
- unsigned long long st_blocks;
- };
-#else
-struct kernel_stat
- {
- unsigned long int st_dev;
- long int __pad1[3]; /* Reserved for network id */
- unsigned long int st_ino;
- unsigned long int st_mode;
- unsigned long int st_nlink;
- long int st_uid;
- long int st_gid;
- unsigned long int st_rdev;
- long int __pad2[2];
- long int st_size;
- long int __pad3;
- unsigned int st_atime_sec;
- unsigned int st_atime_nsec;
- unsigned int st_mtime_sec;
- unsigned int st_mtime_nsec;
- unsigned int st_ctime_sec;
- unsigned int st_ctime_nsec;
- long int st_blksize;
- long int st_blocks;
- char st_fstype[16]; /* Filesystem type name, unsupported */
- long st_pad4[8];
- /* Linux specific fields */
- unsigned int st_flags;
- unsigned int st_gen;
- };
-#endif
-
-#define STAT_IS_KERNEL_STAT 0
-#define STAT64_IS_KERNEL_STAT64 0
-#define XSTAT_IS_XSTAT64 0
-#if _MIPS_SIM == _ABI64
-# define STATFS_IS_STATFS64 1
-#else
-# define STATFS_IS_STATFS64 0
-#endif
-/* MIPS64 has unsigned 32 bit timestamps fields, so use statx as well. */
-#if _MIPS_SIM == _ABI64
-# define STAT_HAS_TIME32
-#endif
-
-#endif
diff --git a/lib/libc/glibc/sysdeps/unix/sysv/linux/s390/s390-32/kernel_stat.h b/lib/libc/glibc/sysdeps/unix/sysv/linux/s390/s390-32/kernel_stat.h
deleted file mode 100644
index b1bc1459f08e..000000000000
--- a/lib/libc/glibc/sysdeps/unix/sysv/linux/s390/s390-32/kernel_stat.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/* Definition of `struct stat' used in the kernel.. */
-struct kernel_stat
- {
- unsigned short int st_dev;
- unsigned short int __pad1;
-#define _HAVE___PAD1
- unsigned long int st_ino;
- unsigned short int st_mode;
- unsigned short int st_nlink;
- unsigned short int st_uid;
- unsigned short int st_gid;
- unsigned short int st_rdev;
- unsigned short int __pad2;
-#define _HAVE___PAD2
- unsigned long int st_size;
- unsigned long int st_blksize;
- unsigned long int st_blocks;
- struct timespec st_atim;
- struct timespec st_mtim;
- struct timespec st_ctim;
- unsigned long int __glibc_reserved4;
-#define _HAVE___UNUSED4
- unsigned long int __glibc_reserved5;
-#define _HAVE___UNUSED5
- };
-
-#define _HAVE_STAT___UNUSED4
-#define _HAVE_STAT___UNUSED5
-#define _HAVE_STAT___PAD1
-#define _HAVE_STAT___PAD2
-#define _HAVE_STAT_NSEC
-#define _HAVE_STAT64___PAD1
-#define _HAVE_STAT64___PAD2
-#define _HAVE_STAT64___ST_INO
-#define _HAVE_STAT64_NSEC
-
-#define STAT_IS_KERNEL_STAT 0
-#define STAT64_IS_KERNEL_STAT64 1
-#define XSTAT_IS_XSTAT64 0
-#define STATFS_IS_STATFS64 0
diff --git a/lib/libc/glibc/sysdeps/unix/sysv/linux/sh/kernel_stat.h b/lib/libc/glibc/sysdeps/unix/sysv/linux/sh/kernel_stat.h
deleted file mode 100644
index b1bc1459f08e..000000000000
--- a/lib/libc/glibc/sysdeps/unix/sysv/linux/sh/kernel_stat.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/* Definition of `struct stat' used in the kernel.. */
-struct kernel_stat
- {
- unsigned short int st_dev;
- unsigned short int __pad1;
-#define _HAVE___PAD1
- unsigned long int st_ino;
- unsigned short int st_mode;
- unsigned short int st_nlink;
- unsigned short int st_uid;
- unsigned short int st_gid;
- unsigned short int st_rdev;
- unsigned short int __pad2;
-#define _HAVE___PAD2
- unsigned long int st_size;
- unsigned long int st_blksize;
- unsigned long int st_blocks;
- struct timespec st_atim;
- struct timespec st_mtim;
- struct timespec st_ctim;
- unsigned long int __glibc_reserved4;
-#define _HAVE___UNUSED4
- unsigned long int __glibc_reserved5;
-#define _HAVE___UNUSED5
- };
-
-#define _HAVE_STAT___UNUSED4
-#define _HAVE_STAT___UNUSED5
-#define _HAVE_STAT___PAD1
-#define _HAVE_STAT___PAD2
-#define _HAVE_STAT_NSEC
-#define _HAVE_STAT64___PAD1
-#define _HAVE_STAT64___PAD2
-#define _HAVE_STAT64___ST_INO
-#define _HAVE_STAT64_NSEC
-
-#define STAT_IS_KERNEL_STAT 0
-#define STAT64_IS_KERNEL_STAT64 1
-#define XSTAT_IS_XSTAT64 0
-#define STATFS_IS_STATFS64 0
diff --git a/lib/libc/glibc/sysdeps/unix/sysv/linux/sparc/sparc32/kernel_stat.h b/lib/libc/glibc/sysdeps/unix/sysv/linux/sparc/sparc32/kernel_stat.h
deleted file mode 100644
index 4a2df42d375e..000000000000
--- a/lib/libc/glibc/sysdeps/unix/sysv/linux/sparc/sparc32/kernel_stat.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/* Definition of `struct stat' used in the kernel */
-struct kernel_stat
- {
- unsigned short int st_dev;
- unsigned long int st_ino;
- unsigned short int st_mode;
- short int st_nlink;
- unsigned short int st_uid;
- unsigned short int st_gid;
- unsigned short int st_rdev;
- long int st_size;
- struct timespec st_atim;
- struct timespec st_mtim;
- struct timespec st_ctim;
- long int st_blksize;
- long int st_blocks;
- unsigned long int __glibc_reserved4;
- unsigned long int __glibc_reserved5;
- };
-
-#define _HAVE___UNUSED4
-#define _HAVE___UNUSED5
-
-#define _HAVE_STAT___UNUSED4
-#define _HAVE_STAT___UNUSED5
-#define _HAVE_STAT___PAD1
-#define _HAVE_STAT___PAD2
-#define _HAVE_STAT64___UNUSED4
-#define _HAVE_STAT64___UNUSED5
-#define _HAVE_STAT64___PAD2
-#define _HAVE_STAT_NSEC
-#define _HAVE_STAT64_NSEC
-
-#define STAT_IS_KERNEL_STAT 0
-#define STAT64_IS_KERNEL_STAT64 1
-#define XSTAT_IS_XSTAT64 0
-#define STATFS_IS_STATFS64 0
diff --git a/lib/libc/glibc/sysdeps/unix/sysv/linux/sparc/sparc64/kernel_stat.h b/lib/libc/glibc/sysdeps/unix/sysv/linux/sparc/sparc64/kernel_stat.h
deleted file mode 100644
index 29d18908da92..000000000000
--- a/lib/libc/glibc/sysdeps/unix/sysv/linux/sparc/sparc64/kernel_stat.h
+++ /dev/null
@@ -1,58 +0,0 @@
-#ifndef _KERNEL_STAT_H
-#define _KERNEL_STAT_H
-
-/* Definition of `struct stat' used in the kernel */
-struct kernel_stat
- {
- unsigned int st_dev;
- unsigned long int st_ino;
- unsigned int st_mode;
- short int st_nlink;
- unsigned int st_uid;
- unsigned int st_gid;
- unsigned int st_rdev;
- long int st_size;
- long int st_atime_sec;
- long int st_mtime_sec;
- long int st_ctime_sec;
- long int st_blksize;
- long int st_blocks;
- unsigned long int __glibc_reserved1;
- unsigned long int __glibc_reserved2;
- };
-
-/* Definition of `struct stat64' used in the kernel. */
-struct kernel_stat64
- {
- unsigned long int st_dev;
- unsigned long int st_ino;
- unsigned long int st_nlink;
-
- unsigned int st_mode;
- unsigned int st_uid;
- unsigned int st_gid;
- unsigned int __pad0;
-
- unsigned long int st_rdev;
- long int st_size;
- long int st_blksize;
- long int st_blocks;
-
- unsigned long int st_atime_sec;
- unsigned long int st_atime_nsec;
- unsigned long int st_mtime_sec;
- unsigned long int st_mtime_nsec;
- unsigned long int st_ctime_sec;
- unsigned long int st_ctime_nsec;
- long int __glibc_reserved[3];
- };
-
-#define STAT_IS_KERNEL_STAT 0
-#define STAT64_IS_KERNEL_STAT64 0
-#define XSTAT_IS_XSTAT64 1
-#ifdef __arch64__
-# define STATFS_IS_STATFS64 1
-#else
-# define STATFS_IS_STATFS64 0
-#endif
-#endif /* _KERNEL_STAT_H */
diff --git a/lib/libc/include/generic-glibc/string.h b/lib/libc/include/generic-glibc/string.h
index 77b6aa346b51..353754d0c477 100644
--- a/lib/libc/include/generic-glibc/string.h
+++ b/lib/libc/include/generic-glibc/string.h
@@ -501,6 +501,11 @@ extern char *stpncpy (char *__restrict __dest,
__THROW __nonnull ((1, 2));
#endif
+/*
+ * strlcpy and strlcat introduced in glibc 2.38
+ * https://sourceware.org/git/?p=glibc.git;a=commit;h=2e0bbbfbf95fc9e22692e93658a6fbdd2d4554da
+ */
+#if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 38) || __GLIBC__ > 2
#ifdef __USE_MISC
/* Copy at most N - 1 characters from SRC to DEST. */
extern size_t strlcpy (char *__restrict __dest,
@@ -513,6 +518,7 @@ extern size_t strlcat (char *__restrict __dest,
const char *__restrict __src, size_t __n)
__THROW __nonnull ((1, 2)) __attr_access ((__read_write__, 1, 3));
#endif
+#endif /* glibc v2.38 and later */
#ifdef __USE_GNU
/* Compare S1 and S2 as strings holding name & indices/version numbers. */
diff --git a/lib/std/fs/test.zig b/lib/std/fs/test.zig
index 95cacd25d1f2..cd50b8aae883 100644
--- a/lib/std/fs/test.zig
+++ b/lib/std/fs/test.zig
@@ -660,9 +660,6 @@ test "readAllAlloc" {
}
test "Dir.statFile" {
- // TODO: Re-enable once https://github.com/ziglang/zig/issues/17034 is solved
- if (builtin.os.tag == .linux and builtin.link_libc and builtin.abi == .gnu) return error.SkipZigTest;
-
try testWithAllSupportedPathTypes(struct {
fn impl(ctx: *TestContext) !void {
const test_file_name = try ctx.transformPath("test_file");
diff --git a/src/glibc.zig b/src/glibc.zig
index 00d76f32fb0d..b7483b7012fd 100644
--- a/src/glibc.zig
+++ b/src/glibc.zig
@@ -20,7 +20,7 @@ pub const Lib = struct {
};
pub const ABI = struct {
- all_versions: []const Version,
+ all_versions: []const Version, // all defined versions (one abilist from v2.0.0 up to current)
all_targets: []const target_util.ArchOsAbi,
/// The bytes from the file verbatim, starting from the u16 number
/// of function inclusions.
@@ -172,6 +172,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progr
const target = comp.root_mod.resolved_target.result;
const target_ver = target.os.version_range.linux.glibc;
+ const nonshared_stat = target_ver.order(.{ .major = 2, .minor = 32, .patch = 0 }) != .gt;
const start_old_init_fini = target_ver.order(.{ .major = 2, .minor = 33, .patch = 0 }) != .gt;
// In all cases in this function, we add the C compiler flags to
@@ -276,54 +277,72 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progr
},
.libc_nonshared_a => {
const s = path.sep_str;
- const linux_prefix = lib_libc_glibc ++
- "sysdeps" ++ s ++ "unix" ++ s ++ "sysv" ++ s ++ "linux" ++ s;
- const Flavor = enum { nonshared, shared };
const Dep = struct {
path: []const u8,
- flavor: Flavor = .shared,
- exclude: bool = false,
+ include: bool = true,
};
const deps = [_]Dep{
+ .{ .path = lib_libc_glibc ++ "stdlib" ++ s ++ "atexit.c" },
+ .{ .path = lib_libc_glibc ++ "stdlib" ++ s ++ "at_quick_exit.c" },
+ .{ .path = lib_libc_glibc ++ "sysdeps" ++ s ++ "pthread" ++ s ++ "pthread_atfork.c" },
+ .{ .path = lib_libc_glibc ++ "debug" ++ s ++ "stack_chk_fail_local.c" },
+
+ // libc_nonshared.a redirected stat functions to xstat until glibc 2.33,
+ // when they were finally versioned like other symbols.
+ .{
+ .path = lib_libc_glibc ++ "io" ++ s ++ "stat-2.32.c",
+ .include = nonshared_stat,
+ },
+ .{
+ .path = lib_libc_glibc ++ "io" ++ s ++ "fstat-2.32.c",
+ .include = nonshared_stat,
+ },
+ .{
+ .path = lib_libc_glibc ++ "io" ++ s ++ "lstat-2.32.c",
+ .include = nonshared_stat,
+ },
.{
- .path = lib_libc_glibc ++ "stdlib" ++ s ++ "atexit.c",
- .flavor = .nonshared,
+ .path = lib_libc_glibc ++ "io" ++ s ++ "stat64-2.32.c",
+ .include = nonshared_stat,
},
.{
- .path = lib_libc_glibc ++ "stdlib" ++ s ++ "at_quick_exit.c",
- .flavor = .nonshared,
+ .path = lib_libc_glibc ++ "io" ++ s ++ "fstat64-2.32.c",
+ .include = nonshared_stat,
},
.{
- .path = lib_libc_glibc ++ "sysdeps" ++ s ++ "pthread" ++ s ++ "pthread_atfork.c",
- .flavor = .nonshared,
+ .path = lib_libc_glibc ++ "io" ++ s ++ "lstat64-2.32.c",
+ .include = nonshared_stat,
},
.{
- .path = lib_libc_glibc ++ "debug" ++ s ++ "stack_chk_fail_local.c",
- .flavor = .nonshared,
+ .path = lib_libc_glibc ++ "io" ++ s ++ "fstatat-2.32.c",
+ .include = nonshared_stat,
},
- .{ .path = lib_libc_glibc ++ "csu" ++ s ++ "errno.c" },
+ .{
+ .path = lib_libc_glibc ++ "io" ++ s ++ "fstatat64-2.32.c",
+ .include = nonshared_stat,
+ },
+ .{
+ .path = lib_libc_glibc ++ "io" ++ s ++ "mknodat-2.32.c",
+ .include = nonshared_stat,
+ },
+ .{
+ .path = lib_libc_glibc ++ "io" ++ s ++ "mknod-2.32.c",
+ .include = nonshared_stat,
+ },
+
+ // __libc_start_main used to require statically linked init/fini callbacks
+ // until glibc 2.34 when they were assimilated into the shared library.
.{
.path = lib_libc_glibc ++ "csu" ++ s ++ "elf-init-2.33.c",
- .exclude = !start_old_init_fini,
+ .include = start_old_init_fini,
},
- .{ .path = linux_prefix ++ "stat.c" },
- .{ .path = linux_prefix ++ "fstat.c" },
- .{ .path = linux_prefix ++ "lstat.c" },
- .{ .path = linux_prefix ++ "stat64.c" },
- .{ .path = linux_prefix ++ "fstat64.c" },
- .{ .path = linux_prefix ++ "lstat64.c" },
- .{ .path = linux_prefix ++ "fstatat.c" },
- .{ .path = linux_prefix ++ "fstatat64.c" },
- .{ .path = linux_prefix ++ "mknodat.c" },
- .{ .path = lib_libc_glibc ++ "io" ++ s ++ "mknod.c" },
- .{ .path = linux_prefix ++ "stat_t64_cp.c" },
};
var files_buf: [deps.len]Compilation.CSourceFile = undefined;
var files_index: usize = 0;
for (deps) |dep| {
- if (dep.exclude) continue;
+ if (!dep.include) continue;
var args = std.ArrayList([]const u8).init(arena);
try args.appendSlice(&[_][]const u8{
@@ -347,13 +366,6 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progr
try args.append("-DCAN_USE_REGISTER_ASM_EBP");
}
- const shared_def = switch (dep.flavor) {
- .nonshared => "-DLIBC_NONSHARED=1",
- // glibc passes `-DSHARED` for these. However, empirically if
- // we do that here we will see undefined symbols such as `__GI_memcpy`.
- // So we pass the same thing as for nonshared.
- .shared => "-DLIBC_NONSHARED=1",
- };
try args.appendSlice(&[_][]const u8{
"-D_LIBC_REENTRANT",
"-include",
@@ -363,7 +375,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progr
"-include",
try lib_path(comp, arena, lib_libc_glibc ++ "include" ++ path.sep_str ++ "libc-symbols.h"),
"-DPIC",
- shared_def,
+ "-DLIBC_NONSHARED=1",
"-DTOP_NAMESPACE=glibc",
});
files_buf[files_index] = .{
diff --git a/src/print_targets.zig b/src/print_targets.zig
index bfb2ac017702..f8390a03b921 100644
--- a/src/print_targets.zig
+++ b/src/print_targets.zig
@@ -79,9 +79,12 @@ pub fn cmdTargets(
try jws.objectField("glibc");
try jws.beginArray();
for (glibc_abi.all_versions) |ver| {
- const tmp = try std.fmt.allocPrint(allocator, "{}", .{ver});
- defer allocator.free(tmp);
- try jws.write(tmp);
+ // Actual glibc minimum is architecture specific. This just covers the broadest minimum.
+ if (ver.order(target.glibc_min_version) != .lt) {
+ const tmp = try std.fmt.allocPrint(allocator, "{}", .{ver});
+ defer allocator.free(tmp);
+ try jws.write(tmp);
+ }
}
try jws.endArray();
diff --git a/src/target.zig b/src/target.zig
index 5ae5c420c2e3..8c66017e79fc 100644
--- a/src/target.zig
+++ b/src/target.zig
@@ -11,10 +11,16 @@ pub const ArchOsAbi = struct {
os: std.Target.Os.Tag,
abi: std.Target.Abi,
os_ver: ?std.SemanticVersion = null,
+
+ // Minimum glibc version that provides support for the arch/os (for
+ // .abi = .gnu). For most entries, the .glibc_min is null,
+ // meaning the Zig minimum required by the standard library (see
+ // glibc_min_version) is sufficient.
+ glibc_min: ?std.SemanticVersion = null,
};
pub const available_libcs = [_]ArchOsAbi{
- .{ .arch = .aarch64_be, .os = .linux, .abi = .gnu },
+ .{ .arch = .aarch64_be, .os = .linux, .abi = .gnu, .glibc_min = .{ .major = 2, .minor = 17, .patch = 0 } },
.{ .arch = .aarch64_be, .os = .linux, .abi = .musl },
.{ .arch = .aarch64_be, .os = .windows, .abi = .gnu },
.{ .arch = .aarch64, .os = .linux, .abi = .gnu },
@@ -54,14 +60,14 @@ pub const available_libcs = [_]ArchOsAbi{
.{ .arch = .mips, .os = .linux, .abi = .gnueabi },
.{ .arch = .mips, .os = .linux, .abi = .gnueabihf },
.{ .arch = .mips, .os = .linux, .abi = .musl },
- .{ .arch = .powerpc64le, .os = .linux, .abi = .gnu },
+ .{ .arch = .powerpc64le, .os = .linux, .abi = .gnu, .glibc_min = .{ .major = 2, .minor = 19, .patch = 0 } },
.{ .arch = .powerpc64le, .os = .linux, .abi = .musl },
.{ .arch = .powerpc64, .os = .linux, .abi = .gnu },
.{ .arch = .powerpc64, .os = .linux, .abi = .musl },
.{ .arch = .powerpc, .os = .linux, .abi = .gnueabi },
.{ .arch = .powerpc, .os = .linux, .abi = .gnueabihf },
.{ .arch = .powerpc, .os = .linux, .abi = .musl },
- .{ .arch = .riscv64, .os = .linux, .abi = .gnu },
+ .{ .arch = .riscv64, .os = .linux, .abi = .gnu, .glibc_min = .{ .major = 2, .minor = 27, .patch = 0 } },
.{ .arch = .riscv64, .os = .linux, .abi = .musl },
.{ .arch = .s390x, .os = .linux, .abi = .gnu },
.{ .arch = .s390x, .os = .linux, .abi = .musl },
@@ -76,6 +82,9 @@ pub const available_libcs = [_]ArchOsAbi{
.{ .arch = .x86_64, .os = .macos, .abi = .none, .os_ver = .{ .major = 10, .minor = 7, .patch = 0 } },
};
+/// Minimum glibc version, due to dependencies from the Zig standard library on glibc symbols
+pub const glibc_min_version: std.SemanticVersion = .{ .major = 2, .minor = 17, .patch = 0 };
+
pub fn libCGenericName(target: std.Target) [:0]const u8 {
switch (target.os.tag) {
.windows => return "mingw",
@@ -154,6 +163,12 @@ pub fn canBuildLibC(target: std.Target) bool {
const ver = target.os.version_range.semver;
return ver.min.order(libc.os_ver.?) != .lt;
}
+ // Ensure glibc (aka *-linux-gnu) version is supported
+ if (target.isGnuLibC()) {
+ const min_glibc_ver = libc.glibc_min orelse glibc_min_version;
+ const target_glibc_ver = target.os.version_range.linux.glibc;
+ return target_glibc_ver.order(min_glibc_ver) != .lt;
+ }
return true;
}
}
diff --git a/test/link/glibc_compat/build.zig b/test/link/glibc_compat/build.zig
index bb8d5d056daf..e0cc1a70d81f 100644
--- a/test/link/glibc_compat/build.zig
+++ b/test/link/glibc_compat/build.zig
@@ -1,4 +1,14 @@
const std = @import("std");
+const builtin = @import("builtin");
+
+// To run executables linked against a specific glibc version, the
+// run-time glibc version needs to be new enough. Check the host's glibc
+// version. Note that this does not allow for translation/vm/emulation
+// services to run these tests.
+const running_glibc_ver: ?std.SemanticVersion = switch (builtin.os.tag) {
+ .linux => builtin.os.version_range.linux.glibc,
+ else => null,
+};
pub fn build(b: *std.Build) void {
const test_step = b.step("test", "Test");
@@ -17,4 +27,95 @@ pub fn build(b: *std.Build) void {
_ = exe.getEmittedBin();
test_step.dependOn(&exe.step);
}
+
+ // Build & run against a sampling of supported glibc versions
+ for ([_][]const u8{
+ "native-linux-gnu.2.17", // Currently oldest supported, see #17769
+ "native-linux-gnu.2.23",
+ "native-linux-gnu.2.28",
+ "native-linux-gnu.2.33",
+ "native-linux-gnu.2.38",
+ "native-linux-gnu",
+ }) |t| {
+ const target = b.resolveTargetQuery(std.Target.Query.parse(
+ .{ .arch_os_abi = t },
+ ) catch unreachable);
+
+ const glibc_ver = target.result.os.version_range.linux.glibc;
+
+ const exe = b.addExecutable(.{
+ .name = t,
+ .root_source_file = .{ .path = "glibc_runtime_check.zig" },
+ .target = target,
+ });
+ exe.linkLibC();
+
+ // Only try running the test if the host glibc is known to be good enough. Ideally, the Zig
+ // test runner would be able to check this, but see https://github.com/ziglang/zig/pull/17702#issuecomment-1831310453
+ if (running_glibc_ver) |running_ver| {
+ if (glibc_ver.order(running_ver) == .lt) {
+ const run_cmd = b.addRunArtifact(exe);
+ run_cmd.skip_foreign_checks = true;
+ run_cmd.expectExitCode(0);
+
+ test_step.dependOn(&run_cmd.step);
+ }
+ }
+ const check = exe.checkObject();
+
+ // __errno_location is always a dynamically linked symbol
+ check.checkInDynamicSymtab();
+ check.checkExact("0 0 UND FUNC GLOBAL DEFAULT __errno_location");
+
+ // before v2.32 fstatat redirects through __fxstatat, afterwards its a
+ // normal dynamic symbol
+ if (glibc_ver.order(.{ .major = 2, .minor = 32, .patch = 0 }) == .lt) {
+ check.checkInDynamicSymtab();
+ check.checkExact("0 0 UND FUNC GLOBAL DEFAULT __fxstatat");
+
+ check.checkInSymtab();
+ check.checkContains("FUNC LOCAL HIDDEN fstatat");
+ } else {
+ check.checkInDynamicSymtab();
+ check.checkExact("0 0 UND FUNC GLOBAL DEFAULT fstatat");
+
+ check.checkInSymtab();
+ check.checkNotPresent("FUNC LOCAL HIDDEN fstatat");
+ }
+
+ // before v2.26 reallocarray is not supported
+ if (glibc_ver.order(.{ .major = 2, .minor = 26, .patch = 0 }) == .lt) {
+ check.checkInDynamicSymtab();
+ check.checkNotPresent("reallocarray");
+ } else {
+ check.checkInDynamicSymtab();
+ check.checkExact("0 0 UND FUNC GLOBAL DEFAULT reallocarray");
+ }
+
+ // before v2.38 strlcpy is not supported
+ if (glibc_ver.order(.{ .major = 2, .minor = 38, .patch = 0 }) == .lt) {
+ check.checkInDynamicSymtab();
+ check.checkNotPresent("strlcpy");
+ } else {
+ check.checkInDynamicSymtab();
+ check.checkExact("0 0 UND FUNC GLOBAL DEFAULT strlcpy");
+ }
+
+ // v2.16 introduced getauxval(), so always present
+ check.checkInDynamicSymtab();
+ check.checkExact("0 0 UND FUNC GLOBAL DEFAULT getauxval");
+
+ // Always have a dynamic "exit" reference
+ check.checkInDynamicSymtab();
+ check.checkExact("0 0 UND FUNC GLOBAL DEFAULT exit");
+
+ // An atexit local symbol is defined, and depends on undefined dynamic
+ // __cxa_atexit.
+ check.checkInSymtab();
+ check.checkContains("FUNC LOCAL HIDDEN atexit");
+ check.checkInDynamicSymtab();
+ check.checkExact("0 0 UND FUNC GLOBAL DEFAULT __cxa_atexit");
+
+ test_step.dependOn(&check.step);
+ }
}
diff --git a/test/link/glibc_compat/glibc_runtime_check.zig b/test/link/glibc_compat/glibc_runtime_check.zig
new file mode 100644
index 000000000000..7344bafc6ed2
--- /dev/null
+++ b/test/link/glibc_compat/glibc_runtime_check.zig
@@ -0,0 +1,116 @@
+// A zig test case that exercises some glibc symbols that have uncovered
+// problems in the past. This test must be compiled against a glibc.
+//
+// The build.zig tests the binary built from this source to see that
+// symbols are statically or dynamically linked, as expected.
+
+const std = @import("std");
+const builtin = @import("builtin");
+const assert = std.debug.assert;
+
+const c_malloc = @cImport(
+ @cInclude("malloc.h"), // for reallocarray
+);
+
+const c_stdlib = @cImport(
+ @cInclude("stdlib.h"), // for atexit
+);
+
+const c_string = @cImport(
+ @cInclude("string.h"), // for strlcpy
+);
+
+// Version of glibc this test is being built to run against
+const glibc_ver = builtin.target.os.version_range.linux.glibc;
+
+// PR #17034 - fstat moved between libc_nonshared and libc
+fn checkStat() !void {
+ const cwdFd = std.fs.cwd().fd;
+
+ var stat = std.mem.zeroes(std.c.Stat);
+ var result = std.c.fstatat(cwdFd, "a_file_that_definitely_does_not_exist", &stat, 0);
+ assert(result == -1);
+ assert(std.c.getErrno(result) == .NOENT);
+
+ result = std.c.stat("a_file_that_definitely_does_not_exist", &stat);
+ assert(result == -1);
+ assert(std.c.getErrno(result) == .NOENT);
+}
+
+// PR #17607 - reallocarray not visible in headers
+fn checkReallocarray() !void {
+ // reallocarray was introduced in v2.26
+ if (comptime glibc_ver.order(.{ .major = 2, .minor = 26, .patch = 0 }) == .lt) {
+ if (@hasDecl(c_malloc, "reallocarray")) {
+ @compileError("Before v2.26 'malloc.h' does not define 'reallocarray'");
+ }
+ } else {
+ return try checkReallocarray_v2_26();
+ }
+}
+
+fn checkReallocarray_v2_26() !void {
+ const size = 16;
+ const tenX = c_malloc.reallocarray(c_malloc.NULL, 10, size);
+ const elevenX = c_malloc.reallocarray(tenX, 11, size);
+
+ assert(tenX != c_malloc.NULL);
+ assert(elevenX != c_malloc.NULL);
+}
+
+// getauxval introduced in v2.16
+fn checkGetAuxVal() !void {
+ if (comptime glibc_ver.order(.{ .major = 2, .minor = 16, .patch = 0 }) == .lt) {
+ if (@hasDecl(std.c, "getauxval")) {
+ @compileError("Before v2.16 glibc does not define 'getauxval'");
+ }
+ } else {
+ try checkGetAuxVal_v2_16();
+ }
+}
+
+fn checkGetAuxVal_v2_16() !void {
+ const base = std.c.getauxval(std.elf.AT_BASE);
+ const pgsz = std.c.getauxval(std.elf.AT_PAGESZ);
+
+ assert(base != 0);
+ assert(pgsz != 0);
+}
+
+// strlcpy introduced in v2.38, which is newer than many installed glibcs
+fn checkStrlcpy() !void {
+ if (comptime glibc_ver.order(.{ .major = 2, .minor = 38, .patch = 0 }) == .lt) {
+ if (@hasDecl(c_string, "strlcpy")) {
+ @compileError("Before v2.38 glibc does not define 'strlcpy'");
+ }
+ } else {
+ try checkStrlcpy_v2_38();
+ }
+}
+
+fn checkStrlcpy_v2_38() !void {
+ var buf: [99]u8 = undefined;
+ const used = c_string.strlcpy(&buf, "strlcpy works!", buf.len);
+ assert(used == 15);
+}
+
+// atexit is part of libc_nonshared, so ensure its linked in correctly
+fn forceExit0Callback() callconv(.C) void {
+ std.c.exit(0); // Override the main() exit code
+}
+
+fn checkAtExit() !void {
+ const result = c_stdlib.atexit(forceExit0Callback);
+ assert(result == 0);
+}
+
+pub fn main() !u8 {
+ try checkStat();
+ try checkReallocarray();
+ try checkStrlcpy();
+
+ try checkGetAuxVal();
+ try checkAtExit();
+
+ std.c.exit(1); // overridden by atexit() callback
+}