Hi, Willy
On Mon, Jul 03, 2023 at 04:36:51PM +0800, Zhangjin Wu wrote:
Syscalls that return pointer use that -MAX_ERRNO range to encode errors (such as mmap()). I just do not know if there is a convention saying that other ones also restrict themselves to that range or not. If you find some info which guarantees that it's the case for all of them, then by all means let's proceed like this, but in this case it should be mentioned in the comment why we think it's valid to do this. For now it's presented as an opportunity only.
Currently, I only found a prove-in-use case in musl:
https://elixir.bootlin.com/musl/latest/source/src/internal/syscall_ret.c: #include <errno.h> #include "syscall.h" long __syscall_ret(unsigned long r) { if (r > -4096UL) { errno = -r; return -1; } return r; }
Our new implementation (based on the one used by mmap()) is almostly the same as musl. Not sure if this is enough. I have tried to 'git blame' on __syscall_ret() of musl to find some clue, but failed, because the function has been added before importing into its git repo.
OK, we already used the glibc-saved registers in the past to determine the official list of clobbered registers (and the ABI spec was even updated based on this). Here, musl is sufficiently deployed to consider this as valid. You can simply go that route and mention in the commit message that while you found no official reference stating that this is valid for int/long returns, you found at least one other implementation relying on this (i.e. if the kernel ever changes it will cause breakage).
ok.
Also, the rest of the commit message regarding uintptr_t (which we don't use), bit values and modular arithmetics is extremely confusing and not needed at all. What matters is only to know if we need to consider only values -MAX_ERRNO..-1 as error or all negative ones. If so, then it's obvious that ret >= (unsigned long)-MAX_ERRNO catches them all, as the current mmap() function already does with -4095UL.
Yes, will clean up the commit message, but at first, let's continue get more information about which one is ok:
-MAX_ERRNO..-1 as error, for sys_mmap (we know in nolibc) currently
all negative ones, for others currently
You can double-check in glibc for example, but I'm starting to guess you'll find the same test as above, i.e. errors are exclusively >-4096, regardless of the expected return type.
Your guest is definitely true ;-)
Glibc has the same logic in its INLINE_SYSCALL() macro:
https://elixir.bootlin.com/glibc/latest/source/sysdeps/unix/sysv/linux/sysde...
#undef INTERNAL_SYSCALL_ERROR_P #define INTERNAL_SYSCALL_ERROR_P(val) \ ((unsigned long int) (val) > -4096UL)
#ifndef SYSCALL_ERROR_LABEL # define SYSCALL_ERROR_LABEL(sc_err) \ ({ \ __set_errno (sc_err); \ -1L; \ }) #endif
/* Define a macro which expands into the inline wrapper code for a system call. It sets the errno and returns -1 on a failure, or the syscall return value otherwise. */ #undef INLINE_SYSCALL #define INLINE_SYSCALL(name, nr, args...) \ ({ \ long int sc_ret = INTERNAL_SYSCALL (name, nr, args); \ __glibc_unlikely (INTERNAL_SYSCALL_ERROR_P (sc_ret)) \ ? SYSCALL_ERROR_LABEL (INTERNAL_SYSCALL_ERRNO (sc_ret)) \ : sc_ret; \ })
Nothing differs.
But 'git blame' has no clue to any 'spec' or 'standard' either.
- fcb78a55058fd, linux: Consolidate INLINE_SYSCALL
Moved all of the arch specific INTERNAL_SYSCALL_ERROR_P() to common header
- 369b849f1a382, sysdeps/unix/sysv/linux/s390/s390-32/sysdep.h (INTERNAL_SYSCALL,...
Firstly defined this macro: INTERNAL_SYSCALL_ERROR_P()
$ git show 369b849f1a3 | grep "define.*INTERNAL_SYSCALL_ERROR_P" +#define INTERNAL_SYSCALL_ERROR_P(val) ((unsigned int) (val) >= 0xfffff001u) +#define INTERNAL_SYSCALL_ERROR_P(val) ((unsigned int) (val) >= 0xfffff001u) +#define INTERNAL_SYSCALL_ERROR_P(val) ((unsigned long) (val) >= -515L) +#define INTERNAL_SYSCALL_ERROR_P(val) ((unsigned long) (val) >= -4095L)
Willy, I plan to further use something like, is it ok for you?
tools/include/nolibc/errno.h:
-#define MAX_ERRNO 4095 +#define MAX_ERRNO 4095UL
tools/include/nolibc/sys.h:
/* Syscall return helper for library routines * set errno as -ret when ret in [-MAX_ERRNO, -1] * * Note, No official reference states the errno range * here aligns with musl (src/internal/syscall_ret.c) * and glibc (sysdeps/unix/sysv/linux/sysdep.h) */ static __inline__ __attribute__((unused, always_inline)) long __sysret(unsigned long ret) { if (ret >= -MAX_ERRNO) { SET_ERRNO(-(long)ret); return -1; } return ret; }
Or we also directly use 4096UL here.
static __inline__ __attribute__((unused, always_inline)) long __sysret(unsigned long ret) { if (ret > -4096UL) { SET_ERRNO(-(long)ret); return -1; } return ret; }
Best regards, Zhangjin
Thanks! Willy