Skip to content

Commit

Permalink
glibc: add backwards compatibility for some symbols
Browse files Browse the repository at this point in the history
- `fcntl` was renamed to `fcntl64` in glibc 2.28 (see ziglang#9485)
- `res_{,n}{search,query,querydomain}` became "their own" symbols since
  glibc 2.34: they were prefixed with `__` before.

This PR makes it possible to use `fcntl` with glibc 2.27 or older and
the `res_*` functions with glibc 2.33 or older.

These patches will become redundant with universal-headers and can be
dropped. But we have to do with what we have now.

Closes ziglang#9485

Related: 39083c3
  • Loading branch information
motiejus committed Mar 28, 2023
1 parent 28d6dd7 commit 6876439
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 0 deletions.
8 changes: 8 additions & 0 deletions lib/libc/glibc/io/fcntl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down
8 changes: 8 additions & 0 deletions lib/libc/include/generic-glibc/fcntl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down
22 changes: 22 additions & 0 deletions lib/libc/include/generic-glibc/resolv.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 4 additions & 0 deletions test/link.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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
.{
Expand Down
25 changes: 25 additions & 0 deletions test/link/glibc_compat/build.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
const std = @import("std");

pub fn build(b: *std.Build) void {
const test_step = b.step("test", "Test");
b.default_step = test_step;

const targets: []const []const u8 = &.{
"aarch64-linux-gnu.2.27",
"aarch64-linux-gnu.2.28",
"aarch64-linux-gnu.2.33",
"aarch64-linux-gnu.2.34",
};

for (targets) |target| {
const exe = b.addExecutable(.{
.name = target,
.root_source_file = .{ .path = "main.c" },
.target = std.zig.CrossTarget.parse(
.{ .arch_os_abi = target },
) catch unreachable,
});
exe.linkLibC();
test_step.dependOn(&exe.step);
}
}
37 changes: 37 additions & 0 deletions test/link/glibc_compat/main.c
Original file line number Diff line number Diff line change
@@ -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);
}

0 comments on commit 6876439

Please sign in to comment.