Incorrect _STAT_VER* constants when cross compiling to arm32 on old glibc
Zig Version
0.13.0-dev.260+fb88cfdf6
Steps to Reproduce and Observed Behavior
tl;dr: Compiling with arm32 glibc 2.31 target pulls in incorrect _STAT_VER constants, causing fstatat function to return EINVAL.
Issue
Cross compiling the following code with zig cc -target arm-linux-gnueabihf.2.31 fstatat.c -o fstatat, creating an empty file /tmp/test.txt, and running the code will print fstatat: Invalid argument:
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int main() {
int dirfd = open("/tmp", O_RDONLY | O_DIRECTORY);
if (dirfd == -1) {
perror("open");
return 1;
}
const char *filename = "test.txt";
struct stat statbuf;
if (fstatat(dirfd, filename, &statbuf, 0) == -1) {
perror("fstatat");
close(dirfd);
return 1;
}
close(dirfd);
return 0;
}
Findings from debugging
Debugging this on a Raspberry Pi 3B+ armv7l running Debian Bullseye shows that the program enters __GI___fxstatat which then calls __xstat32_conv. Disassembling __xstat32_conv shows a suspicious comparison with the constant "3":
Dump of assembler code for function __xstat32_conv:
=> 0x76ef6944 <+0>: cmp r0, #3
0x76ef6948 <+4>: push {lr} ; (str lr, [sp, #-4]!)
... truncated
which matches the value of _STAT_VER_LINUX:
pi@raspberrypi3:/tmp $ cat /usr/include/arm-linux-gnueabihf/bits/stat.h | grep _STAT_VER
#define _STAT_VER_LINUX_OLD 1
#define _STAT_VER_KERNEL 1
#define _STAT_VER_SVR4 2
#define _STAT_VER_LINUX 3
#define _STAT_VER _STAT_VER_LINUX /* The one defined below. */
However, Zig's fstatat function passes in the constant "0":
Dump of assembler code for function fstatat:
0x00023fe0 <+0>: push {r11, lr}
0x00023fe4 <+4>: mov r11, sp
0x00023fe8 <+8>: sub sp, sp, #8
0x00023fec <+12>: mov r12, r2
0x00023ff0 <+16>: mov r2, r1
0x00023ff4 <+20>: mov r1, r0
0x00023ff8 <+24>: str r3, [sp]
0x00023ffc <+28>: mov r0, #0
0x00024000 <+32>: mov r3, r12
0x00024004 <+36>: bl 0x44960
0x00024008 <+40>: mov sp, r11
0x0002400c <+44>: pop {r11, pc}
End of assembler dump.
Expected Behavior
fstatat should not return EINVAL. In the sample program, there should be no output.