-
Notifications
You must be signed in to change notification settings - Fork 1k
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
freebsd: Add support for FreeBSD 12.x ABI #721
Conversation
In FreeBSD 12.x, several ABI were changed in an incompatible way: * Inodes were changed from 32-bit to 64-bit. This affects `struct stat` and `struct dirent` structures in Rust libc. https://svnweb.freebsd.org/base?view=revision&revision=318736 * Time-related members of `struct kevent` were changed to 64-bit. Again, this affects the definition of the same structure in Rust libc. https://svnweb.freebsd.org/base?view=revision&revision=320043 Currently, a Rust program compiled on FreeBSD 11.x will work on FreeBSD 12.x thanks to symbol versioning. Unfortunately, a program compiled on FreeBSD 12.x will break. Until Rust gains support for target versions, we need to detect the correct structures to use, based on the build host. This won't make it possible to build a FreeBSD 11 executable on a FreeBSD 12 host, but it is good enough when the build and target hosts are the same. This patch introduces a build script which uses freebsd-version(1) to detect the version. When it is 12 or more, it defines the `freebsd12_abi` feature. Modules in `src/unix/bsd/freebsdlike/freebsd` were reorganized. They are now split based on this ABI version instead of the target architecture. For instance, `struct stat` is defined once in `freebsd12.rs` for all architectures. `struct kevent` grew a new member, `ext` in FreeBSD 12.x. To avoid too much pain to users of this structure, both flavors (`freebsd11.rs` and `freebsd12.rs`) now have the `ext` member. In the case of `freebsd11`, this is a 0-length array. To help initialize the structure, one can use the `libc::KEVENT_EXT_ZEROED` constant. Fixes rust-lang/rust#42681.
I'm not sure at all if the addition of the Here is the tentative patch in the With unmodified
With the two patches, the testsuites of |
fa60c72
to
4bd2261
Compare
☔ The latest upstream changes (presumably #722) made this pull request unmergeable. Please resolve the merge conflicts. |
Having several ABI in libc for FreeBSD would be the right thing regarding the break at OS level: it permits Rust program using libc to pick the right struct depending the OS version. One thing is still problematic: the So we have the following target ABI selection (regarding the host):
All these things under But the PR solves several problems too: FreeBSD will be able to have the right ABI when built using FreeBSD, and it is a good step from my point of vue. I will add some elements on the proposed RFC (target-extension) regarding the ABI selection in |
Thanks for the PR! Unfortunately though I don't think this is a good strategy for the libc crate. This is essentially boiling down to compile-time detection, but the compile-time detection is fallible and lossy. For example this wouldn't work for cross-compiled scenarios (e.g. wouldn't get the compiler nightlies working) and in general doesn't allow tuning for various versions. This is a general problem which rust-lang/rfcs#2048 is targeted at addressing, essentially allowing communication to the compiler through separate targets what's actually being targeted, allowing |
Thanks for your comment! I read and commented on the draft of this RFC, but I missed the pull request on GitHub and the subsequent comments. I'm reading them and I will experiment with the runtime detection you suggest because I'm not sure I understand how it works yet. I will comment in the RFC pull request with my findings. In particular, symbols are versioned on FreeBSD, so for instance FreeBSD 12 still knows about the |
@dumbbell whoa interesting!
What's going on with issue reports like rust-lang/rust#42681 then? Should we be linking to different symbols? |
By out-of-the-box, I mean the So if I take the example in rust-lang/rust#42681, My understanding is that |
Interesting! Can we request the old symbols be used then? That's what we do for OSX (requesting old and/or new symbols) |
Oh that'd be awesome! If we could update the |
@dumbbell's proposal will fix self-builds on FreeBSD 12, but as @alexcrichton commented, it won't fix cross builds. I think it should be possible to fix cross builds too by using feature flags to select which ABI to use. An on-by-default feature flag named |
Not that if there are symbols for both the 32 and 64 but variants of functions then we could do a linux-like interface where both |
@alexcrichton it isn't so simple. First, I doubt the compatibility layer was done for providing an alternate way to use the system, but more for helping transition. As example, the old- But I assume it is possible to make libc to only use old interface. But it is a bit abusing the compat layer, and it will break any program that will want to use It could be done for transitional purpose for rustc, but requiring the same for all Rust ecosystem would be very dangerous: problems will not be detected at compile-time, but only at runtime with wired behaviour. |
The actual behavior for FreeBSD 12 regarding |
Hi! Sorry, I was in holidays for a few couple weeks and took some time to resume work. I played with a simple C program to learn how to link it to the old symbols. Here is the original program which uses the three (AFAIK) structures whose layout was modified in FreeBSD 12 ( #include <sys/param.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
main(int argc, char *argv[])
{
int ret;
DIR *dirp;
struct statfs statfsbuf;
struct dirent *dp;
struct stat statbuf;
ret = statfs(".", &statfsbuf);
if (ret != 0) {
perror("Failed to statfs current working directory");
return 1;
}
printf(
"statfs:\n"
" Mountpoint: %s\n\n",
statfsbuf.f_mntonname);
dirp = opendir(".");
if (dirp == NULL) {
perror("Failed to open current working directory");
return 1;
}
while ((dp = readdir(dirp)) != NULL) {
char *filename;
filename = malloc(dp->d_namlen + 1);
memcpy(filename, dp->d_name, dp->d_namlen);
filename[dp->d_namlen] = '\0';
printf("%s:\n", filename);
ret = stat(filename, &statbuf);
if (ret != 0) {
free(filename);
perror("Failed to stat");
continue;
}
printf(
" st_mode: %06o\n"
" st_size: %ld bytes\n",
statbuf.st_mode,
statbuf.st_size);
free(filename);
}
closedir(dirp);
return 0;
} Here is the modified program to explicitely link to the old symbols: #define _WANT_FREEBSD11_STATFS
#define _WANT_FREEBSD11_STAT
#include <sys/param.h>
#include <sys/mount.h>
#include <sys/stat.h>
#define _WANT_FREEBSD11_DIRENT
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
__asm__(".symver statfs,statfs@FBSD_1.0");
__asm__(".symver readdir,readdir@FBSD_1.0");
__asm__(".symver stat,stat@FBSD_1.0");
int
main(int argc, char *argv[])
{
int ret;
DIR *dirp;
struct freebsd11_statfs statfsbuf;
struct freebsd11_dirent *dp;
struct freebsd11_stat statbuf;
ret = statfs(".", (struct statfs *)&statfsbuf);
if (ret != 0) {
perror("Failed to statfs current working directory");
return 1;
}
printf(
"statfs:\n"
" Mountpoint: %s\n\n",
statfsbuf.f_mntonname);
dirp = opendir(".");
if (dirp == NULL) {
perror("Failed to open current working directory");
return 1;
}
while ((dp = (struct freebsd11_dirent *)readdir(dirp)) != NULL) {
char *filename;
filename = malloc(dp->d_namlen + 1);
memcpy(filename, dp->d_name, dp->d_namlen);
filename[dp->d_namlen] = '\0';
printf("%s:\n", filename);
ret = stat(filename, (struct stat *)&statbuf);
if (ret != 0) {
free(filename);
perror("Failed to stat");
continue;
}
printf(
" st_mode: %06o\n"
" st_size: %ld bytes\n",
statbuf.st_mode,
statbuf.st_size);
free(filename);
}
closedir(dirp);
return 0;
} I compiled the two files on FreeBSD 12. The second one is effectively linked to the old symbols but both programs return the same result. Also, the one linked to the old symbols still works on FreeBSD 11 (even though it was compiled on FreeBSD 12). So basically:
Presumably, we would only need that last item in Rust because the structures are redefined in Rust. As @asomers said, we could explicitely link to old symbols on FreeBSD 12+ and put that behind an opt-out feature flag. I'm willing to prepare a patch; @alexcrichton, do you have any pointers to where to start? I don't know if it's a good long-term solution, but at least it would deal with the immediate incompatibility. |
By "I don't know if it's a good long-term solution", I agree with @semarie that the old symbols are made available to help the transition. But if there an inode is greater than 32-bit, it'll break. And there is also I would love to find something which fully works at runtime, but I don't know Rust well enough. In particular, I don't know if we could have e.g. a single |
@dumbbell I think you could use |
I'm going to close this due to inactivity, and I think it may be best to focus on the in-progress RFC for now perhaps? |
We really need these issues fixed for FreeBSD. FreeBSD CURRENT is quite an active development platform, just as people tend to be advised to use rust-nightly. |
|
Fixing the ino64 changes isn't as trivial due to the truncation problem. I'm tempted to just do it anyhow as right now without using the port or an annoying patchset for rust it is completely unusable on FreeBSD12. |
In FreeBSD 12.x, several ABI were changed in an incompatible way:
Inodes were changed from 32-bit to 64-bit. This affects
struct stat
andstruct dirent
structures in Rust libc.Time-related members of
struct kevent
were changed to 64-bit. Again, this affects the definition of the same structure in Rust libc.Currently, a Rust program compiled on FreeBSD 11.x will work on FreeBSD 12.x thanks to symbol versioning. Unfortunately, a program compiled on FreeBSD 12.x will break.
Until Rust gains support for target versions, we need to detect the correct structures to use, based on the build host. This won't make it possible to build a FreeBSD 11 executable on a FreeBSD 12 host, but it is good enough when the build and target hosts are the same.
This patch introduces a build script which uses freebsd-version(1) to detect the version. When it is 12 or more, it defines the
freebsd12_abi
feature.Modules in
src/unix/bsd/freebsdlike/freebsd
were reorganized. They are now split based on this ABI version instead of the target architecture. For instance,struct stat
is defined once infreebsd12.rs
for all architectures.struct kevent
grew a new member,ext
in FreeBSD 12.x. To avoid too much pain to users of this structure, both flavors (freebsd11.rs
andfreebsd12.rs
) now have theext
member. In the case offreebsd11
, this is a 0-length array. To help initialize the structure, one can use thelibc::KEVENT_EXT_ZEROED
constant.Fixes rust-lang/rust#42681.