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

Add intrinsics.syscall_bsd #3524

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

Feoramund
Copy link
Contributor

I'm working on porting core:net to FreeBSD, and I ran into this predicament where syscall was returning only positive numbers, which isn't too helpful for detecting errors. I know very little about how LLVM works; feedback's appreciated. I used the rcx register to do the negation since it's already clobbered.

@Yawning
Copy link
Contributor

Yawning commented May 2, 2024

You don't need to save/restore RFLAGS, because the assembly snippet already specifies that it's clobbered, and "Odin's syscall intrinsic will always return -errno on failure" makes preserving CF non-important. Otherwise this looks fine, apologies for being lazy when I dealt with this in the past.

@andreas-jonsson
Copy link
Sponsor Contributor

Hi @Feoramund, I have been working on a NetBSD port of Odin. I'm currently missing core:net just like the other BSD's.
Let me know if you would like to get some help testing or collaborating on that. I imagine the code would look and work very similar on NetBSD.

@Feoramund
Copy link
Contributor Author

You don't need to save/restore RFLAGS, because the assembly snippet already specifies that it's clobbered, and "Odin's syscall intrinsic will always return -errno on failure" makes preserving CF non-important. Otherwise this looks fine, apologies for being lazy when I dealt with this in the past.

I found a way to negate the return value without needing to save/reload CF. The not and inc instructions don't touch CF, so I used those to construct the negative value.

Hi @Feoramund, I have been working on a NetBSD port of Odin. I'm currently missing core:net just like the other BSD's. Let me know if you would like to get some help testing or collaborating on that. I imagine the code would look and work very similar on NetBSD.

I have an echo server working off of syscalls right now, so hopefully won't be much longer before I can plug it all into an OS-specific file for core:net and put up a PR for testing. Any extra help poking around would be greatly appreciated.

@Feoramund
Copy link
Contributor Author

Feoramund commented May 2, 2024

I've hit a snag. While implementing fcntl, I found this:

     F_GETOWN          Get the process ID or process group currently receiving
                       SIGIO and SIGURG signals; process groups are returned
                       as negative values (arg is ignored).

[...] FCNTL(2)

     In addition, if fd refers to a descriptor open on a terminal device (as
     opposed to a descriptor open on a socket), a cmd of F_SETOWN can fail for
     the same reasons as in tcsetpgrp(3), and a cmd of F_GETOWN for the
     reasons as stated in tcgetpgrp(3).

[...] TCGETPGRP(3)

ERRORS
     If an error occurs, tcgetpgrp() returns -1 and the global variable errno
     is set to indicate the error, as follows:

     [EBADF]            The fd argument is not a valid file descriptor.

     [ENOTTY]           The calling process does not have a controlling
                        terminal or the underlying terminal device represented
                        by fd is not the controlling terminal.

Based on this, it's possible for fcntl to return a negative non-error value. I had concerns about this being possible, but I wasn't sure if or where it would show up.

In this one instance, if that value never overlaps with any of the possible error values, then it's not a big concern, however I think it'd be better to solve this more cleanly. I may need to re-think this. I'm wondering if a separate FreeBSD-specific implementation of syscall with a different signature would be for the best. I.e. syscall :: proc(id: uintptr, args: ..uintptr) -> (uintptr, bool) ---

I'll have to figure out how to do that.

EDIT: While reading through the source code of the compiler, I had an idea. Perhaps it might be more useful to implement an intrinsic that returns the state of the flags. I was able to write one pretty quickly.

@Feoramund Feoramund marked this pull request as draft May 2, 2024 23:44
@Feoramund Feoramund changed the title Support negative errno syscall on FreeBSD amd64 Provide error bool for FreeBSD syscall return value May 5, 2024
@Feoramund
Copy link
Contributor Author

I figured out how to modify syscall to have an alternative signature and return a boolean for the error status on FreeBSD, both for amd64 and arm64 which are considered the FreeBSD tier 1 platforms.

@Feoramund Feoramund marked this pull request as ready for review May 5, 2024 11:14
@andreas-jonsson
Copy link
Sponsor Contributor

I figured out how to modify syscall to have an alternative signature and return a boolean for the error status on FreeBSD

Does this make sense to adopt on other platforms as well? I always assumed it never overlapped with error values.
Should this not be an issue on all Unix systems?

@Yawning
Copy link
Contributor

Yawning commented May 20, 2024

I figured out how to modify syscall to have an alternative signature and return a boolean for the error status on FreeBSD

Does this make sense to adopt on other platforms as well? I always assumed it never overlapped with error values. Should this not be an issue on all Unix systems?

There is no way to distinguish certain cases of overlap on Linux (depending on architecture), so the workarounds are "Linux-isms at the syscall interface layer" (F_GETOWN_EX). Some architectures do also pass a boolean back (sparc, ppc64), but nothing that Odin currently supports has this extension.

Per the documentation:

A limitation of the Linux system call conventions on some architectures
(notably i386) means that if a (negative) process group ID to be re‐
turned by F_GETOWN falls in the range -1 to -4095, then the return value
is wrongly interpreted by glibc as an error in the system call; that is,
the return value of fcntl() will be -1, and errno will contain the (pos‐
itive) process group ID. The Linux-specific F_GETOWN_EX operation
avoids this problem. Since glibc 2.11, glibc makes the kernel F_GETOWN
problem invisible by implementing F_GETOWN using F_GETOWN_EX.

This is a BSD-style syscall that checks for a high Carry Flag as the
error state. If the CF is high, the boolean return value is false, and
if it is low (no errors) then the boolean return value is true.
It's possible for the return string to be longer than 128 characters
these days, so I've increased it to 1024, same as the other BSDs.

SYSCTL was otherwise erring out due to lack of buffer space.
@Feoramund Feoramund force-pushed the freebsd-amd64-syscall-errno branch from 53e9628 to 20c32c8 Compare June 12, 2024 17:58
@Feoramund Feoramund changed the title Provide error bool for FreeBSD syscall return value Add intrinsics.syscall_bsd Jun 12, 2024
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

Successfully merging this pull request may close these issues.

None yet

4 participants