Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compiling libgit2 on glibc 2.17 stat error #255

Open
NobodyXu opened this issue Jun 11, 2024 · 2 comments
Open

Compiling libgit2 on glibc 2.17 stat error #255

NobodyXu opened this issue Jun 11, 2024 · 2 comments

Comments

@NobodyXu
Copy link

NobodyXu commented Jun 11, 2024

Related: jj-vcs/jj#3844

According to this comment by @yuja

For example, git_config_add_file_ondisk calls statically-linked stat64->fstatat64. OTOH, it refers to dynamically-linked errno.

which might. be the problem.

@polarathene
Copy link
Contributor

TL;DR: Zig prior to 0.12.0 didn't handle linking glibc correctly if the target version was 2.32 or lower due to how these symbols were handled (not actual function calls).

You can skip the remainder of this comment, relevant details are covered in the follow-up comment.


Original response (suspected relevance to glibc 2.32 vs glibc 2.33)

If it helps, this reminded me of when I was looking into a glibc version linking behaviour: #232 (comment)

At the bottom of that linked comment is a collapsed section "Dynamic linking differences (resolved)", which has some output from another collapsed section "Reproduction example" earlier in the comment.

It's a very simple reproduction that shows how fstat64 changed from glibc 2.33 onwards:

# Same output for 2.17:
$ cargo zigbuild --release --target x86_64-unknown-linux-gnu.2.32
$ readelf -W --version-info --dyn-syms target/x86_64-unknown-linux-gnu/release/example | grep stat64
    61: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __fxstat64@GLIBC_2.2.5 (2)
    62: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __xstat64@GLIBC_2.2.5 (2)
$ cargo zigbuild --release --target x86_64-unknown-linux-gnu.2.33

$ readelf -W --version-info --dyn-syms target/x86_64-unknown-linux-gnu/release/example | grep stat64
    25: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND fstat64@GLIBC_2.33 (7)
    40: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND stat64@GLIBC_2.33 (7)

Initial investigation

For jj, there was not enough information for how to reproduce the broken quickinstall build:

Inspecting the broken jj 0.18.0 quickinstall build
$ cd /tmp
$ curl -fsSL \
  https://github.com/cargo-bins/cargo-quickinstall/releases/download/jj-cli-0.18.0/jj-cli-0.18.0-x86_64-unknown-linux-gnu.tar.gz \
  | tar -xz -C /tmp

$ file jj
ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.0.0, with debug_info, not stripped

# The broken glibc build doesn't link openssl (static linked?) or interpreter:
$ patchelf --print-needed jj
libm.so.6
libpthread.so.0
libc.so.6
libdl.so.2

$ patchelf --print-interpreter jj
/lib64/ld-linux-x86-64.so.2

$ readelf -W --version-info --syms jj | grep 'Name: GLIBC' | sed -re 's/.*GLIBC_(.+) Flags.*/\1/g' | sort -t . -k1,1n -k2,2n | tail -n 1
2.17

$ readelf -W --version-info --syms jj | grep stat64
 27228: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS stat64.c
 27229: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS fstat64.c
 27232: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS lstat64.c
 27323: 0000000001274b90    49 FUNC    WEAK   DEFAULT   15 fstat64
 27408: 0000000001274b70    23 FUNC    WEAK   DEFAULT   15 stat64
 27434: 0000000001274bd0    26 FUNC    WEAK   DEFAULT   15 lstat64
 33015: 0000000001274b70    23 FUNC    GLOBAL DEFAULT   15 __stat64
 33018: 0000000001274b90    49 FUNC    GLOBAL DEFAULT   15 __fstat64
 33020: 0000000001274bd0    26 FUNC    GLOBAL DEFAULT   15 __lstat64

# No output (the problem?):
$ strip jj && readelf -W --version-info --syms jj | grep stat64

# NOTE: clang 15 was released in Sep 2022, zig 0.10 was used to build
$ readelf -p .comment jj
String dump of section '.comment':
  [     1]  clang version 15.0.7 (https://github.com/ziglang/zig-bootstrap a3a6e85f9ec95b1772f5ace363e46df2f336c6b8)
  [    6a]  Linker: LLD 15.0.7
  [    7d]  rustc version 1.78.0 (9b00956e5 2024-04-29)
Local JJ build
# zig 0.13.0 rust 1.81.0 openssl 3.2.2
$ dnf install -y patchelf git gcc rustup zig perl openssl-devel openssl-devel-engine
$ rustup-init -y --profile minimal && source "$HOME/.cargo/env"
$ cargo install cargo-zigbuild

$ git clone --depth 1 https://github.com/martinvonz/jj /tmp/jj && cd /tmp/jj
$ RUSTFLAGS="-L /usr/lib64 -C strip=none" cargo zigbuild --release --target x86_64-unknown-linux-gnu.2.17

$ patchelf --print-needed target/x86_64-unknown-linux-gnu/release/jj
libssl.so.3
libcrypto.so.3
libm.so.6
libpthread.so.0
libc.so.6
libdl.so.2
ld-linux-x86-64.so.2

$ patchelf --print-interpreter target/x86_64-unknown-linux-gnu/release/jj
/lib64/ld-linux-x86-64.so.2

$ readelf -W --version-info --syms target/x86_64-unknown-linux-gnu/release/jj | grep 'Name: GLIBC' | sed -re 's/.*GLIBC_(.+) Flags.*/\1/g' | sort -t . -k1,1n -k2,2n | tail -n 1
2.17

$ readelf -W --version-info --syms target/x86_64-unknown-linux-gnu/release/jj | grep stat64
   399: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __lxstat64@GLIBC_2.2.5 (2)
   400: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __fxstat64@GLIBC_2.2.5 (2)
   402: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __xstat64@GLIBC_2.2.5 (2)
 29175: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS stat64-2.32.c
 29176: 00000000010e0680    21 FUNC    LOCAL  HIDDEN    16 stat64
 29177: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS fstat64-2.32.c
 29178: 00000000010e06a0    20 FUNC    LOCAL  HIDDEN    16 fstat64
 29179: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS lstat64-2.32.c
 29180: 00000000010e06c0    21 FUNC    LOCAL  HIDDEN    16 lstat64
 33897: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __lxstat64
 33898: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __fxstat64
 33900: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __xstat64

# Stripped:
$ strip target/x86_64-unknown-linux-gnu/release/jj
$ readelf -W --version-info --syms target/x86_64-unknown-linux-gnu/release/jj | grep stat64
   402: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __lxstat64@GLIBC_2.2.5 (2)
   404: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __xstat64@GLIBC_2.2.5 (2)
   405: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __fxstat64@GLIBC_2.2.5 (2)

# With glibc 2.33 target:
$ RUSTFLAGS="-L /usr/lib64 -C strip=none" cargo zigbuild --release --target x86_64-unknown-linux-gnu.2.33
$ readelf -W --version-info --syms target/x86_64-unknown-linux-gnu/release/jj | grep stat64
   349: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND fstat64@GLIBC_2.33 (12)
   363: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND stat64@GLIBC_2.33 (12)
   364: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND lstat64@GLIBC_2.33 (12)
 33699: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND fstat64
 33748: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND stat64
 33749: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND lstat64

Minimal reproduction attempt

Initial environment setup

Cargo.toml:

[package]
name = "example"
version = "0.1.0"
edition = "2021"

[dependencies]
libc = "0.2.153"

src/main.rs:

use std::fs::File;
use std::os::unix::io::AsRawFd;

fn main() {
    let file = File::open("hello.txt").expect("`hello.txt` should exist");
    // Placeholder value:
    let mut uid = 42;

    unsafe {
        let mut stat: libc::stat64 = std::mem::zeroed();
        // Returns c_int, 0 is success, -1 is failure:
        if libc::fstat64(file.as_raw_fd(), &mut stat) == 0 {
            uid = stat.st_uid;
        }
    }

    println!("`hello.txt` is owned by UID: {uid}");
}
# Older release before glibc 2.32:
$ docker run --rm -it fedora:31

# Glibc 2.30
$ ldd --version
ldd (GNU libc) 2.30
Copyright (C) 2019 Free Software Foundation, Inc.

# Install deps:
$ dnf install -y gcc pip nano
$ pip install ziglang
$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
$ . "$HOME/.cargo/env"
$ cargo install cargo-zigbuild

# Create demo project:
$ mkdir -p /example/src
$ nano /example/Cargo.toml
$ nano /example/src/main.rs
Build attempts with zig
## glibc 2.17 target
# NOTE: fstat64 has 2.32 version even though build host is glibc 2.30? However, these are only from debug symbols
# UPDATE: This was identified as a zig patch/workaround for proper glibc <= 2.32 support
$ RUSTFLAGS="-C strip=none" cargo zigbuild --release --target x86_64-unknown-linux-gnu.2.17
$ readelf -W --version-info --syms target/x86_64-unknown-linux-gnu/release/example | grep stat64
    60: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __fxstat64@GLIBC_2.2.5 (2)
    61: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __xstat64@GLIBC_2.2.5 (2)
   745: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS stat64-2.32.c
   746: 000000000005a4a0    21 FUNC    LOCAL  HIDDEN    15 stat64
   747: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS fstat64-2.32.c
   748: 000000000005a4c0    20 FUNC    LOCAL  HIDDEN    15 fstat64
   749: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS lstat64-2.32.c
  1045: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __fxstat64
  1046: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __xstat64
$ readelf -W --version-info --syms target/x86_64-unknown-linux-gnu/release/example | grep 'Name: GLIBC' | sed -re 's/.*GLIBC_(.+) Flags.*/\1/g' | sort -t . -k1,1n -k2,2n | tail -n 1
2.16

## glibc 2.32 target
# Same as above:
$ RUSTFLAGS="-C strip=none" cargo zigbuild --release --target x86_64-unknown-linux-gnu.2.32
$ readelf -W --version-info --syms target/x86_64-unknown-linux-gnu/release/example | grep stat64
    60: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __fxstat64@GLIBC_2.2.5 (2)
    61: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __xstat64@GLIBC_2.2.5 (2)
   745: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS stat64-2.32.c
   746: 000000000005a4d0    21 FUNC    LOCAL  HIDDEN    15 stat64
   747: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS fstat64-2.32.c
   748: 000000000005a4f0    20 FUNC    LOCAL  HIDDEN    15 fstat64
   749: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS lstat64-2.32.c
  1045: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __fxstat64
  1046: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __xstat64
# Min glibc version did go up:
$ readelf -W --version-info --syms target/x86_64-unknown-linux-gnu/release/example | grep 'Name: GLIBC' | sed -re 's/.*GLIBC_(.+) Flags.*/\1/g' | sort -t . -k1,1n -k2,2n | tail -n 1
2.28
# NOTE: Without version should be equivalent to host glibc, thus 2.30, but outputs is same as for 2.32?:
# UPDATE: The 2.32 annotation to debug symbols is zig specific, not related to actual glibc min version requirements
$ RUSTFLAGS="-C strip=none" cargo zigbuild --release --target x86_64-unknown-linux-gnu

## glibc 2.33 target
# Min glibc version 2.33 now required, zig will build correctly for targets of glibc that are newer than the host glibc:
$ RUSTFLAGS="-C strip=none" cargo zigbuild --release --target x86_64-unknown-linux-gnu.2.33
readelf -W --version-info --syms target/x86_64-unknown-linux-gnu/release/example | grep stat64
     3: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND fstat64@GLIBC_2.33 (3)
    39: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND stat64@GLIBC_2.33 (3)
   769: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND fstat64
   950: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND stat64

$ readelf -W --version-info --syms target/x86_64-unknown-linux-gnu/release/example | grep 'Name: GLIBC' | sed -re 's/.*GLIBC_(.+) Flags.*/\1/g' | sort -t . -k1,1n -k2,2n | tail -n 1
2.33

$ readelf -p .comment /example/target/x86_64-unknown-linux-gnu/release/example
String dump of section '.comment':
  [     0]  Linker: LLD 18.1.6
  [    13]  clang version 18.1.6 (https://github.com/ziglang/zig-bootstrap 98bc6bf4fc4009888d33941daf6b600d20a42a56)
  [    7d]  rustc version 1.81.0 (eeb90cda1 2024-09-04)
Build attempt without zig
# `cargo build` (Rust 1.81, uses fedora 31 provided glibc 2.30):
# Symbols differ a bit vs zig:
$ RUSTFLAGS="-C strip=none" cargo build --release --target x86_64-unknown-linux-gnu
$ readelf -W --version-info --syms target/x86_64-unknown-linux-gnu/release/example | grep stat64
    20: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __xstat64@GLIBC_2.2.5 (2)
    34: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __fxstat64@GLIBC_2.2.5 (2)
    59: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __lxstat64@GLIBC_2.2.5 (2)
   587: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __xstat64@@GLIBC_2.2.5
   603: 0000000000046120    19 FUNC    GLOBAL HIDDEN    13 fstat64
   612: 0000000000046100    20 FUNC    GLOBAL HIDDEN    13 stat64
   658: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __fxstat64@@GLIBC_2.2.5
   685: 0000000000046140    20 FUNC    GLOBAL HIDDEN    13 lstat64
   767: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __lxstat64@@GLIBC_2.2.5

$ readelf -W --version-info --syms target/x86_64-unknown-linux-gnu/release/example | grep 'Name: GLIBC' | sed -re 's/.*GLIBC_(.+) Flags.*/\1/g' | sort -t . -k1,1n -k2,2n | tail -n 1
2.28

With -C strip=symbols to remove debug symbols, you'll get the same two line outputs for cargo build / cargo zigbuild as I showed for the other reproduction example.

In an attempt to match the jj build environment a bit better, I switched to zig 0.10.0 (which is what quickinstall is using) and Rust 1.78.0:

Build attempt with zig 0.10.0 + Rust 1.78.0
# From the same build Fedora 31 environment above:
$ dnf install -y xz patchelf && mkdir /opt/zig
$ curl -fsSL https://ziglang.org/download/0.10.0/zig-linux-x86_64-0.10.0.tar.xz \
  | tar -xJ -C /opt/zig --strip-components=1
$ export PATH="/opt/zig:${PATH}"
# zigbuild prefers python installs before checking for binary installs, uninstall the zig 0.13.0 python package:
$ pip uninstall ziglang
$ rustup toolchain install 1.78.0 && rustup default 1.78.0
$ RUSTFLAGS="-C strip=none" cargo zigbuild --release --target x86_64-unknown-linux-gnu.2.17

# Close enough?:
$ readelf -p .comment target/x86_64-unknown-linux-gnu/release/example
String dump of section '.comment':
  [     1]  clang version 15.0.3 ([email protected]:ziglang/zig-bootstrap.git 85033a9aa569b41658404d0e8a5ab887b81d537b)
  [    6a]  Linker: LLD 15.0.3
  [    7d]  rustc version 1.78.0 (9b00956e5 2024-04-29)

# Now we have output for symbols weakly linked, similar to the broken jj release build, huzzah!:
$ readelf -W --version-info --syms target/x86_64-unknown-linux-gnu/release/example | grep stat64
   752: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS stat64.c
   753: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS fstat64.c
   756: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS lstat64.c
   781: 000000000006a070    49 FUNC    WEAK   DEFAULT   15 fstat64
   967: 000000000006a050    23 FUNC    WEAK   DEFAULT   15 stat64
  1149: 000000000006a050    23 FUNC    GLOBAL DEFAULT   15 __stat64
  1153: 000000000006a070    49 FUNC    GLOBAL DEFAULT   15 __fstat64

# No symbols output (expected):
$ strip target/x86_64-unknown-linux-gnu/release/example
$ readelf -W --version-info --syms target/x86_64-unknown-linux-gnu/release/example | grep stat64

# However it still functions correctly (unexpected):
# UPDATE: This was my mistake, I was testing the fstat64 call, not the failure condition with incorrect errno returned as detailed later
$ touch hello.txt && chown 77:77 hello.txt
$ target/x86_64-unknown-linux-gnu/release/example
`hello.txt` is owned by UID: 77

$ patchelf --print-needed target/x86_64-unknown-linux-gnu/release/example
libpthread.so.0
libc.so.6
libdl.so.2
ld-linux-x86-64.so.2

So... something else is going on that I'm missing... as I can't reproduce whatever else was going on 🤷‍♂️

@polarathene
Copy link
Contributor

Actually... I just realized the bug report wasn't about this fstat64 call at all, it was about the git paths being different / deprecated, thus the paths themselves didn't exist. (EDIT: As covered below in linked issue, the fstat64 call was misleadingly returning an errno of 0 when the checked file path did not exist)

zig 0.11.0 is the last release it fails. Seems to have been fixed from zig 0.12.0 onwards, but I don't know if it was described in the release notes 🤔 Oh it seems like it might have been this issue (regarding errno and fstatat64). That aligns with the findings at the cited jj comment 🎉

Proper minimal reproduction

The zig issues provide reproduction in other languages, once I learned it was about errno I could reproduce in rust too (well via unsafe libc calls):

src/main.rs:

// Reproduction requires building with zig < 0.12.0 and glibc target < 2.33
fn main() {
    unsafe {
        // Reproduction requires the checked file path to be invalid:
        let filepath = std::ffi::CString::new("this_file_does_not_exist").unwrap();
        let mut stat: libc::stat64 = std::mem::zeroed();
        let ptr = filepath.as_ptr();

        // Returns c_int, 0 is success, -1 is failure:
        let ret = libc::stat64(ptr, &mut stat);
        // This and other stat calls will fail in the same way:
        //let ret = libc::fstatat64(libc::AT_FDCWD, ptr, &mut stat as *mut libc::stat64, 0);

        let errno = std::io::Error::last_os_error();
        // NOTE: `errno.raw_os_error().unwrap();` can provide just the error code itself

        match ret {
            // Example of working functionality when successful:
            0 => {
                let uid = stat.st_uid;
                println!("The file is owned by UID: {uid}");
            },
            // The `errno` code will incorrectly be 0 (Success) despite actually failing (`ret == -1`):
            _ => println!("Failure!\n| ret: {ret:?}\n| err: {errno:?}")
        }
    }
}

Initial environment setup:

$ docker run --rm -it fedora:41

# Add zig releases:
$ mkdir /opt/zig-11 /opt/zig-12
$ curl -fsSL https://ziglang.org/download/0.11.0/zig-linux-x86_64-0.11.0.tar.xz \
  | tar -xJ -C /opt/zig-11 --strip-components=1
$ curl -fsSL https://ziglang.org/download/0.12.0/zig-linux-x86_64-0.12.0.tar.xz \
  | tar -xJ -C /opt/zig-12 --strip-components=1

# Add rust:
$ dnf install -y gcc rustup nano
$ rustup-init -y --profile minimal && source "$HOME/.cargo/env"
$ cargo install cargo-zigbuild

# Prep project:
$ cargo init /tmp/example && cd /tmp/example
$ cargo add libc
# Replace main.rs with above rust snippet:
$ rm -f src/main.rs && nano src/main.rs

Here are the results:

# `ret -1` is expected, but the `err` code should be `2`, not `0` as it wasn't actually successful:
$ CARGO_ZIGBUILD_ZIG_PATH=/opt/zig-11/zig cargo zigbuild --release --target x86_64-unknown-linux-gnu.2.32
$ target/x86_64-unknown-linux-gnu/release/example
Failure!
| ret: -1
| err: Os { code: 0, kind: Uncategorized, message: "Success" }

# Correct for glibc 2.33+ where the fstat symbol changed to real function calls:
$ rm -rf target
$ CARGO_ZIGBUILD_ZIG_PATH=/opt/zig-11/zig cargo zigbuild --release --target x86_64-unknown-linux-gnu.2.33
Failure!
| ret: -1
| err: Os { code: 2, kind: NotFound, message: "No such file or directory" }

# glibc 2.32 is working correctly from zig 0.12.0+:
$ rm -rf target
$ CARGO_ZIGBUILD_ZIG_PATH=/opt/zig-12/zig cargo zigbuild --release --target x86_64-unknown-linux-gnu.2.32
Failure!
| ret: -1
| err: Os { code: 2, kind: NotFound, message: "No such file or directory" }

References

Release dates for context to the October 2020 glibc change referenced below:

  • glibc 2.32 (2020 August)
  • glibc 2.33 (2021 February)
Quoted reference links for technical background (glibc 2.32 below issue with fstat and errno + zig patch)

ziglang/zig#17034 (comment)

Stepping through the generated code in a debugger, the fstatat syscall executes, fails, returns the correct status code, then that code is converted into an errno and stashed in a thread-local variable.
The call returns and Zig code fetches errno, but seems to fetch it from a different place than where errno was stored.

ziglang/zig#17034 (comment)

So "fstatat64" is the undefined symbol in the main object file (confused-tls.o). Oddly the "libc.so.6" binary doesn't have any fstatat symbols.
Then libc_nonshared.a has undefined references to "__fstatat64", and also includes "__fstatat64" and a weak "fstatat64".
I believe this weak symbol is resolving the undefined symbol in the main binary.

ziglang/zig#17034 (comment)

The other thing that doesn't make sense is that the libc_nonshared.c fstat implementation was a raw syscall.
The libc_noshared implementation is meant to forward to the "real" libc, via a non-standard "xstat()" implementation. (The whole point of the nonshared.a library is to link in stubs that jump into the dynamically linked library using a version-aware API....)

It looks like the libc_nonshared (also called "static-only-routines" in the Makefiles) fstat* wrappers were excised from libc_nonshared in Oct 2020

A related issue also cites libgit2:

ziglang/zig#11878 (comment)

This breaks using libgit2 with zig cc for me, since it relies on the lstat errno when creating the directory for cloning a repository

Associated PR fix adds some docs:

Like the public headers, these files contain a couple customizations 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.

Which also explains where the 2.32 version pinning was coming from with my earlier output of newer zig builds below glibc 2.33:

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.

And another reference I came across while looking into the glibc 2.33 change (before landing on that zig issue above):

wheybags/glibc_version_header#32 (comment)

Until glibc 2.32, stat64 etc. were redirected to __xstat64 etc. by inline functions or macros; glibc 2.33 changed them to true functions.
As a result, code compiled against glibc 2.32 or older will get the old __xstat64 etc. implementation that is still present, whereas code compiled against glibc 2.33 will get the new stat64 etc. implementation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants