Merge pull request #17702 from rootbeer/correct-libc-nonshared

Fix libc_nonshared.a
This commit is contained in:
Andrew Kelley
2024-01-04 16:28:39 -08:00
committed by GitHub
30 changed files with 922 additions and 544 deletions

83
lib/libc/glibc/README.md vendored Normal file
View File

@@ -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).

View File

@@ -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)

55
lib/libc/glibc/io/fstat-2.32.c vendored Normal file
View File

@@ -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
<https://www.gnu.org/licenses/>. */
#include <sys/stat.h>
/* This definition is only used if inlining fails for this function; see
the last page of <sys/stat.h>. 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)

52
lib/libc/glibc/io/fstat64-2.32.c vendored Normal file
View File

@@ -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
<https://www.gnu.org/licenses/>. */
#include <sys/stat.h>
/* This definition is only used if inlining fails for this function; see
the last page of <sys/stat.h>. 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);
}

52
lib/libc/glibc/io/fstatat-2.32.c vendored Normal file
View File

@@ -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
<https://www.gnu.org/licenses/>. */
#include <sys/stat.h>
/* This definition is only used if inlining fails for this function; see
the last page of <sys/stat.h>. 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);
}

52
lib/libc/glibc/io/fstatat64-2.32.c vendored Normal file
View File

@@ -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
<https://www.gnu.org/licenses/>. */
#include <sys/stat.h>
/* This definition is only used if inlining fails for this function; see
the last page of <sys/stat.h>. 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);
}

55
lib/libc/glibc/io/lstat-2.32.c vendored Normal file
View File

@@ -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
<https://www.gnu.org/licenses/>. */
#include <sys/stat.h>
/* This definition is only used if inlining fails for this function; see
the last page of <sys/stat.h>. 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)

52
lib/libc/glibc/io/lstat64-2.32.c vendored Normal file
View File

@@ -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
<https://www.gnu.org/licenses/>. */
#include <sys/stat.h>
/* This definition is only used if inlining fails for this function; see
the last page of <sys/stat.h>. 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);
}

55
lib/libc/glibc/io/mknod-2.32.c vendored Normal file
View File

@@ -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
<https://www.gnu.org/licenses/>. */
#include <sys/types.h>
#include <sys/stat.h>
/* This definition is only used if inlining fails for this function; see
the last page of <sys/stat.h>. 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)

53
lib/libc/glibc/io/mknodat-2.32.c vendored Normal file
View File

@@ -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
<https://www.gnu.org/licenses/>. */
#include <sys/types.h>
#include <sys/stat.h>
/* This definition is only used if inlining fails for this function; see
the last page of <sys/stat.h>. 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);
}

54
lib/libc/glibc/io/stat-2.32.c vendored Normal file
View File

@@ -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
<https://www.gnu.org/licenses/>. */
#include <sys/stat.h>
/* This definition is only used if inlining fails for this function; see
the last page of <sys/stat.h>. 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)

52
lib/libc/glibc/io/stat64-2.32.c vendored Normal file
View File

@@ -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
<https://www.gnu.org/licenses/>. */
#include <sys/stat.h>
/* This definition is only used if inlining fails for this function; see
the last page of <sys/stat.h>. 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);
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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}. */

View File

@@ -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

View File

@@ -1,75 +0,0 @@
#ifndef _KERNEL_STAT_H
#define _KERNEL_STAT_H
#include <sgidefs.h>
/* 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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 */

View File

@@ -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. */

View File

@@ -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");

View File

@@ -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 ++ "stdlib" ++ s ++ "atexit.c",
.flavor = .nonshared,
.path = lib_libc_glibc ++ "io" ++ s ++ "stat-2.32.c",
.include = nonshared_stat,
},
.{
.path = lib_libc_glibc ++ "stdlib" ++ s ++ "at_quick_exit.c",
.flavor = .nonshared,
.path = lib_libc_glibc ++ "io" ++ s ++ "fstat-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 ++ "lstat-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 ++ "stat64-2.32.c",
.include = nonshared_stat,
},
.{ .path = lib_libc_glibc ++ "csu" ++ s ++ "errno.c" },
.{
.path = lib_libc_glibc ++ "io" ++ s ++ "fstat64-2.32.c",
.include = nonshared_stat,
},
.{
.path = lib_libc_glibc ++ "io" ++ s ++ "lstat64-2.32.c",
.include = nonshared_stat,
},
.{
.path = lib_libc_glibc ++ "io" ++ s ++ "fstatat-2.32.c",
.include = nonshared_stat,
},
.{
.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] = .{

View File

@@ -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();

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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
}