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

errno definitions not an integer constant #103

Closed
alisonatwork opened this issue Mar 5, 2021 · 6 comments
Closed

errno definitions not an integer constant #103

alisonatwork opened this issue Mar 5, 2021 · 6 comments
Labels
wontfix This will not be worked on

Comments

@alisonatwork
Copy link
Contributor

I was experimenting with compiling some non-cosmo code and came across this error:

$ cat etest.c
#ifdef NO_COSMO
#include <sys/stat.h>
#include <errno.h>
#include <stdio.h>
#endif
int main() {
  struct stat s;
  int i = stat("nope", &s);
  printf("stat=-1? %d\n", i);
  switch (errno) {
    case ENOENT:
      printf("hooray!\n");
  }
  printf("errno=2? %d\n", errno);
}
$ cc -DNO_COSMO etest.c
$ ./a.out
stat=-1? -1
hooray!
errno=2? 2
$ cc -g -Og -static -nostdlib -nostdinc -fno-pie -no-pie -mno-red-zone -fno-omit-frame-pointer -pg -mnop-mcount \
> -o etest.com.dbg etest.c -fuse-ld=bfd -Wl,-T,ape.lds \
> -include o/cosmopolitan.h o/libc/crt/crt.o o/ape/ape.o o/cosmopolitan.a
etest.c: In function 'main':
etest.c:11:5: error: case label does not reduce to an integer constant
   11 |     case ENOENT:
      |     ^~~~
$ grep ENOENT o/cosmopolitan.h
#define ENOENT          ENOENT           /* no such file or directory */
hidden extern const long ENOENT;
#define kNtErrorFileNotFound 2     /* ENOENT */

I tried moving things around in cosmopolitan.h a bit, but no joy. It seems that the actual definition is in libc/sysv/consts/ENOENT.S, and I guess it changes (for some of them at least) at runtime. Is there any way to get around this, or would it be better to patch the code to use if/else instead of switch?

@jart jart added the wontfix This will not be worked on label Mar 5, 2021
@jart
Copy link
Owner

jart commented Mar 5, 2021

The switch statements need to be if statements. You've identified the one key area where we have no choice but to bend the POSIX rules, as discussed in the APE blog post: https://justine.lol/ape.html In the future we might be able to modify chibicc to be lenient about symbolic cases but it's something that's unlikely to make it into the C standard.

For more background on why things need to be this way, having a symbol for things like ENOENT ensures that at load time your _init() function can unpack the correct number for the system you're using, because systems don't agree on which the magic number should be. Each time you reference system constant symbol, it yoinks a tiny ULEB128 encoded binary value into linkage for each operating system.

@jart jart closed this as completed Mar 5, 2021
@jacereda
Copy link
Contributor

jacereda commented Oct 9, 2021

I'm not sure I understand the reason for the incompatibility... Wouldn't something like this do the trick?

#define errno __geterrno()

The __geterrno would perform a table lookup to transform errno from native values to cosmopolitan values.

@Jules-Bertholet
Copy link
Contributor

@jacereda's question came up in a discussion regarding a proposed change to Rust: rust-lang/rfcs#3305 (comment)

@jart
Copy link
Owner

jart commented Sep 7, 2022

@jacereda In order to use POSIX magic numbers as constants, like the rest of the C community, we'd have to have every system interface (e.g. read, write, etc.) translate the magic numbers to the Linux values, for all possible numbers. That entails lots of bloat that would add to our static binaries.

What I like about having constants be symbolic is it means we only have to pay for what we use. For example, if the only thing you care about is if read() returned EINTR then that'll be the only symbols you need to link, and the read() function can be very fast and lightweight, since it doesn't perform any translation.

The tradeoff is these gosh darn switch() statements. We must find a way to address this because it's such a big issue. Possibly by modifying the C language itself to permit smarter relocations.

@jart
Copy link
Owner

jart commented Sep 7, 2022

@Jules-Bertholet I've replied to the Rust thread and brought up some other good points, like how many magic numbers (e.g. termios) are sparse; therefore, system call wrappers would need to do things like binary searches every time you interact with the kernel. That's slow! rust-lang/rfcs#3305 (comment)

@comex
Copy link

comex commented Sep 7, 2022

(If you used a perfect hash table instead of a binary search, you wouldn't need any branches. Even with a binary search, the runtime cost would likely be dwarfed by the cost of even just entering and leaving the kernel [at least with speculative execution mitigations enabled], never mind doing the actual work of the syscall. And yet I can definitely sympathize with the concern when it comes to code size, or even bloat from an aesthetic perspective… Anyway, that's just my personal opinion. I'm just a commenter – in particular, not a member of any Rust team.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
wontfix This will not be worked on
Projects
None yet
Development

No branches or pull requests

5 participants