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

FreeBSD does not require libc for syscalls #16590

Open
andrewrk opened this issue Jul 28, 2023 · 15 comments
Open

FreeBSD does not require libc for syscalls #16590

andrewrk opened this issue Jul 28, 2023 · 15 comments
Labels
contributor friendly This issue is limited in scope and/or knowledge of Zig internals. enhancement Solving this issue will likely involve adding new logic or components to the codebase. os-freebsd
Milestone

Comments

@andrewrk
Copy link
Member

source: https://lobste.rs/s/yjd59n/crt_free_2023_tips_tricks#c_viakfm

The task is to change this to false for FreeBSD:

zig/lib/std/target.zig

Lines 398 to 413 in 282cb5e

/// On Darwin, we always link libSystem which contains libc.
/// Similarly on FreeBSD and NetBSD we always link system libc
/// since this is the stable syscall interface.
pub fn requiresLibC(os: Os) bool {
return switch (os.tag) {
.freebsd,
.netbsd,
.macos,
.ios,
.tvos,
.watchos,
.dragonfly,
.openbsd,
.haiku,
.solaris,
=> true,

And then go implement syscalls in the standard library via inline assembly like we already do for Linux rather than relying on libc for this target.

This is great news, hurray! We no longer need to build libc in order to cross-compile zig code for this target.

@andrewrk andrewrk added enhancement Solving this issue will likely involve adding new logic or components to the codebase. contributor friendly This issue is limited in scope and/or knowledge of Zig internals. os-freebsd labels Jul 28, 2023
@andrewrk andrewrk added this to the 0.12.0 milestone Jul 28, 2023
@davidchisnall
Copy link

All of the system call stubs in FreeBSD are machine generated from syscalls.master. If you want them as inline assembly, you can probably reuse the code.

Note that the syscall calling convention is a little bit interesting on FreeBSD. Arguments are passed in the same location that they are for normal function calls (just replace the call instruction with syscall), with the exception of x8-64, where the SysV ABI defines a different register for one of the arguments (the trampoline is then just a register-register move and a syscall). The return values are more complex. On sensible architectures the error state is defined by the carry bit. If the carry bit is set, the return value register contains the errno value, if it is not set then it contains the result. This lets you branch on carry to detect failure. I believe MIPS and RISC-V use the second return register.

@andrewrk
Copy link
Member Author

Thanks for the tips!

@RealDeuce
Copy link

RealDeuce commented Aug 2, 2023

So, it's worth noting though that syscalls.master is version-specific and will change across FreeBSD major versions.
For example, swapoff() changed from 13 to 14:

424	AUE_SWAPOFF	COMPAT13 {
		int swapoff(
		    _In_z_ const char *name
		);
	}


582	AUE_SWAPOFF	STD {
		int swapoff(
		    _In_z_ const char *name,
		    u_int flags,
		);
	}

COMPATXX are optionally compiled in (IIRC, the current supported releases are included by default). I've assumed this is why FreeBSD has used libc for syscalls.

@andrewrk
Copy link
Member Author

andrewrk commented Aug 2, 2023

I'm feeling a bit confused about whether there is a stable syscall ABI or not. What can an application developer expect if they provide a binary to a FreeBSD OS user?

@RealDeuce
Copy link

Just looked... it appears GENERIC includes COMPATXXX all the way back to 4 when it was introduced, so less of a concern than I thought.

@RealDeuce
Copy link

RealDeuce commented Aug 2, 2023

So my understanding is that basically, the ABI is stable, but it's possible for the user to exclude parts of it.

I just discovered that by default, the whole thing is included... I had previously thought old syscalls were removed from the default kernel, but that's not true.

@RealDeuce
Copy link

RealDeuce commented Aug 2, 2023

So an application developer can expect that the binary will work for the version it was compiled for, and every version after that unless the user has built a custom kernel that removes backward compatibility.

@RealDeuce
Copy link

So the only real "gotcha" is making sure that the syscalls.master used is from the oldest supported FreeBSD, to avoid using syscalls from the future.

@mikdusan
Copy link
Member

mikdusan commented Aug 3, 2023

For our purposes, syscalls.master is lacking some information. Specifically, we need to map a syscall to the semver of FreeBSD where it was introduced. The good news is information can be gleaned from the freebsd.src repository's tagged versions of syscalls.master.

Using syscall swapoff as an example, the latest release 13.2.0 syscalls.master provides this information:

  1. syscall_424 swapoff is marked with COMPAT13 meaning after 13.0.0 this became backwards compatible.
  2. syscall_582 swapoff is marked with STD meaning this is current for 13.2.0. But it doesn't tell us exactly when it was introduced. We can guess it was introduced at or after 13.0.0 but "at or after" is not good enough.

Manually searching history we learn:

  1. syscall_424 swapoff was introduced in 5.1.0. Interestingly, the manpage suggests 5.0.0 was the introduction.
  2. syscall_582 swapoff was introduced in 13.1.0.

This looks very promising indeed!

@RealDeuce
Copy link

I'm not sure why the semver for each syscall would be needed unless the plan is to have each FreeBSD release from 4.x on be a unique target... not that I'm opposed to that, it just seems like a lot of unnecessary work, and makes targeting "FreeBSD" more complex than I would expect it to be.

@igalic
Copy link

igalic commented Aug 23, 2023

I believe MIPS and RISC-V use the second return register.

MIPS is no longer supported.

@dch
Copy link

dch commented Sep 18, 2023

@emaste can you offer any further wisdom here? If zig can rely on using oldest supported syscall tables then it could generate FreeBSD compatible binaries directly from any other OS/architecture which is very desirable.

It would help FreeBSD to be a tier 1 target for zig compiler instead of a tier 2.

freebsd-git pushed a commit to freebsd/freebsd-src that referenced this issue Sep 18, 2023
It was introduced in 92da00b, after 5.0 and beforen 5.1.  Reported
in ziglang/zig#16590.
@emaste
Copy link

emaste commented Sep 18, 2023

So the only real "gotcha" is making sure that the syscalls.master used is from the oldest supported FreeBSD, to avoid using syscalls from the future.

Yes, it's unfortunate that you had to hunt for this information, but this is correct. We may eventually remove COMPAT entries for very old FreeBSD versions from the default kernel configuration, but I expect that wouldn't happen for a minimum of a couple of decades after EOL.

I'm not sure why the semver for each syscall would be needed

If you're bypassing libc the libc stubs and associated symver isn't important. 12.x is the oldest supported FreeBSD release so that may be what you want to target, but it is EOL in a few more months and 13.x may be preferable.

Rust and Go have similar issues. Discussions in rust-lang/rust#89058 and golang/go#48164 have a lot of information that is relevant here.

Manually searching history we learn:
syscall_424 swapoff was introduced in 5.1.0. Interestingly, the manpage suggests 5.0.0 was the introduction.

Hmm, let's see. swapoff was added by freebsd/freebsd-src@92da00b and indeed I see that is between 5.0 and 5.1. Fixed in freebsd/freebsd-src@b15f640

All of the system call stubs in FreeBSD are machine generated from syscalls.master.

Generated by https://github.com/freebsd/freebsd-src/blob/main/sys/tools/makesyscalls.lua

freebsd-git pushed a commit to freebsd/freebsd-src that referenced this issue Sep 21, 2023
It was introduced in 92da00b, after 5.0 and beforen 5.1.  Reported
in ziglang/zig#16590.

(cherry picked from commit b15f640)
freebsd-git pushed a commit to freebsd/freebsd-src that referenced this issue Sep 21, 2023
It was introduced in 92da00b, after 5.0 and beforen 5.1.  Reported
in ziglang/zig#16590.

(cherry picked from commit b15f640)
(cherry picked from commit f4bb052)
@fel1x-developer
Copy link
Contributor

From what I read so far, it seems that we don't need to do bring libc headers.

If so, the last checkbox of #1759 can be marked done and #2876 can be closed

@nektro
Copy link
Contributor

nektro commented Jan 24, 2024

freebsd will still have to be added to wiki/Updating-libc once -lc cross compilation is supported, which is being tracked in #2876

bsdjhb pushed a commit to bsdjhb/cheribsd that referenced this issue Feb 3, 2024
It was introduced in 92da00b, after 5.0 and beforen 5.1.  Reported
in ziglang/zig#16590.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
contributor friendly This issue is limited in scope and/or knowledge of Zig internals. enhancement Solving this issue will likely involve adding new logic or components to the codebase. os-freebsd
Projects
None yet
Development

No branches or pull requests

9 participants