commit 13aa7871b274fd22c7fdf277174a43d09788bd27 (tree)
parent 9f957184a13fd39b74b978a8eb19b4c9eb6afa09
Author: Andrew Kelley <andrew@ziglang.org>
Date: Thu, 6 Apr 2023 17:15:58 -0400
Merge pull request #15101 from motiejus/glibc_compat
glibc: add backwards compatibility for some symbols
Diffstat:
7 files changed, 104 insertions(+), 0 deletions(-)
diff --git a/lib/libc/glibc/README.md b/lib/libc/glibc/README.md
@@ -0,0 +1,8 @@
+glibc headers are slightly patched for backwards compatibility. This is not
+good, because it requires to maintain our patchset whlist upgrading glibc.
+
+Until universal headers are real and this file can be removed, these commits
+need to be cherry-picked in the future glibc header upgrades:
+
+- 39083c31a550ed80f369f60d35791e98904b8096
+- a89813ef282c092a9caf699731c7faaf485acabe
diff --git a/lib/libc/glibc/io/fcntl.h b/lib/libc/glibc/io/fcntl.h
@@ -167,6 +167,10 @@ typedef __pid_t pid_t;
effective IDs, not real IDs. */
#endif
+
+/* fcntl was a simple symbol until glibc 2.27 inclusive. glibc 2.28 onwards
+ * re-defines it to fcntl64 (via #define) if _FILE_OFFSET_BITS == 64. */
+#if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 28) || __GLIBC__ > 2
/* Do the file control operation described by CMD on FD.
The remaining arguments are interpreted depending on CMD.
@@ -197,6 +201,9 @@ extern int __fcntl_time64 (int __fd, int __request, ...) __THROW;
# define fcntl __fcntl_time64
# endif
#endif
+#else /* glibc 2.27 or lower */
+extern int fcntl (int __fd, int __cmd, ...);
+#endif
/* Open FILE and return a new file descriptor for it, or -1 on error.
OFLAG determines the type of access used. If O_CREAT or O_TMPFILE is set
diff --git a/lib/libc/include/generic-glibc/fcntl.h b/lib/libc/include/generic-glibc/fcntl.h
@@ -167,6 +167,11 @@ typedef __pid_t pid_t;
effective IDs, not real IDs. */
#endif
+
+/* fcntl was a simple symbol until glibc 2.27 inclusive.
+ * glibc 2.28 onwards converted it to a macro when compiled with
+ * USE_LARGEFILE64. */
+#if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 28) || __GLIBC__ > 2
/* Do the file control operation described by CMD on FD.
The remaining arguments are interpreted depending on CMD.
@@ -197,6 +202,9 @@ extern int __fcntl_time64 (int __fd, int __request, ...) __THROW;
# define fcntl __fcntl_time64
# endif
#endif
+#else /* glibc 2.27 or lower */
+extern int fcntl (int __fd, int __cmd, ...);
+#endif
/* Open FILE and return a new file descriptor for it, or -1 on error.
OFLAG determines the type of access used. If O_CREAT or O_TMPFILE is set
diff --git a/lib/libc/include/generic-glibc/resolv.h b/lib/libc/include/generic-glibc/resolv.h
@@ -169,6 +169,28 @@ __END_DECLS
#define res_init __res_init
#define res_isourserver __res_isourserver
+/* In glibc 2.33 and earlier res_search, res_nsearch, res_query, res_nquery,
+ * res_querydomain, res_nquerydomain were #define'd to __res_search,
+ * __res_nsearch, etc. glibc 2.34 onwards removes the macros and exposes the
+ * symbols directly. New glibc exposes compat symbols with underscores for
+ * backwards compatibility. Applications linked to glibc 2.34+ are expected
+ * to use the non-underscored symbols.
+ *
+ * It will be enough to bring the macros back when compiling against the older
+ * glibc versions.
+ *
+ * See glibc commit ea9878ec271c791880fcbbe519d70c42f8113750.
+ */
+#if (__GLIBC__ == 2 && __GLIBC_MINOR__ < 34)
+#define res_search __res_search
+#define res_nsearch __res_nsearch
+#define res_query __res_query
+#define res_nquery __res_nquery
+#define res_querydomain __res_querydomain
+#define res_nquerydomain __res_nquerydomain
+#endif
+/* end glibc compat hacks */
+
#ifdef _LIBC
# define __RESOLV_DEPRECATED
# define __RESOLV_DEPRECATED_MSG(msg)
diff --git a/test/link.zig b/test/link.zig
@@ -20,6 +20,10 @@ pub const cases = [_]Case{
.build_root = "test/link/interdependent_static_c_libs",
.import = @import("link/interdependent_static_c_libs/build.zig"),
},
+ .{
+ .build_root = "test/link/glibc_compat",
+ .import = @import("link/glibc_compat/build.zig"),
+ },
// WASM Cases
.{
diff --git a/test/link/glibc_compat/build.zig b/test/link/glibc_compat/build.zig
@@ -0,0 +1,18 @@
+const std = @import("std");
+
+pub fn build(b: *std.Build) void {
+ const test_step = b.step("test", "Test");
+ b.default_step = test_step;
+
+ inline for (.{ "aarch64-linux-gnu.2.27", "aarch64-linux-gnu.2.34" }) |t| {
+ const exe = b.addExecutable(.{
+ .name = t,
+ .root_source_file = .{ .path = "main.c" },
+ .target = std.zig.CrossTarget.parse(
+ .{ .arch_os_abi = t },
+ ) catch unreachable,
+ });
+ exe.linkLibC();
+ test_step.dependOn(&exe.step);
+ }
+}
diff --git a/test/link/glibc_compat/main.c b/test/link/glibc_compat/main.c
@@ -0,0 +1,37 @@
+#define _FILE_OFFSET_BITS 64
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <resolv.h>
+
+int main() {
+ /* in glibc 2.28+ and _FILE_OFFSET_BITS=64 fcntl is #define'd to fcntl64
+ * Thus headers say `fcntl64` exists, but libc.so.6 (the old one)
+ * disagrees, resulting in a linking error unless headers are made
+ * backwards-compatible.
+ *
+ * Glibc 2.28+:
+ * FUNC GLOBAL DEFAULT UND fcntl64@GLIBC_2.28 (3):
+ *
+ * Glibc 2.27 or older:
+ * FUNC GLOBAL DEFAULT UND fcntl@GLIBC_2.2.5
+ */
+ printf("address to fcntl: %p\n", fcntl);
+
+ /* The following functions became symbols of their own right with glibc
+ * 2.34+. Before 2.34 resolv.h would #define res_search __res_search; and
+ * __res_search is a valid symbol since the beginning of time.
+ *
+ * On glibc 2.34+ these symbols are linked this way:
+ * FUNC GLOBAL DEFAULT UND res_search@GLIBC_2.34 (2)
+ *
+ * Pre-glibc 2.34:
+ * FUNC GLOBAL DEFAULT UND __res_search@GLIBC_2.2.5 (4)
+ */
+ printf("address to res_search: %p\n", res_search);
+ printf("address to res_nsearch: %p\n", res_nsearch);
+ printf("address to res_query: %p\n", res_query);
+ printf("address to res_nquery: %p\n", res_nquery);
+ printf("address to res_querydomain: %p\n", res_querydomain);
+ printf("address to res_nquerydomain: %p\n", res_nquerydomain);
+}