While debugging a devel/libunwind failure in an armv7 program running on aarch64, I found that the program crashes with ENOSYS while calling __syscall(). Here is a reproducer: #include <sys/mman.h> #include <sys/syscall.h> #include <unistd.h> int main() { __syscall(SYS_mmap, 0, 4096, 3, MAP_ANON|MAP_PRIVATE, -1, 0); } This is effectively what the GET_MEMORY() macro in libunwind does. Expected output: nothing. Actual output: Bad system call (core dumped). I'll work around this failure in libunwind for now, but please fix this for the future.
FYI: This also happens in a chroot to a armv7 world. It is not specific to lib32. So the summary likely should be adjusted.
It's a kernel issue, as the kernel gives SIGSYS / ENOSYS for SYS___syscall.
Should also affect i386 on amd64. sys/compat/freebsd32/freebsd32_sysent.c has nosys for both SYS_syscall and SYS___syscall.
(In reply to Robert Clausecker from comment #2) No: Note: As 15.0 split libc into libsys plus a smaller libc, 14.* and before vs. 15.0+ are likely distinct contexts. I still had a armv7 14.3-STABLE (1403505) media present and tried doing a chroot into that from aarch64 and doing the experiment: # cc armv7__syscall_test.c # ./a.out # So: It did not fail running the same system as the prior chroot test, just a different directory tree with a 14.3 world. So, likely the libsys split handling is what leads to 15.0+ being different.
(In reply to Mark Millard from comment #4) In case it is not clear: the host system was the same 15.0-STABLE system in both tests of chroot use.
One more observation: using syscall() works fine, but __syscall() does not, despite both being nosys in the table. I'm not sure what is going on here. I am running an armv7 jail on an aarch64 host. I chose lib32 as I don't know what the right prefix for COMPAT_FREEBSD32 related issues is. freebsd32_fetch_syscall_args() actually has special cases for both, so perhaps one of them is implemented incorrectly?
Drat, You likely are correct: Looks like I used the wrong directory tree (aarch64) on that separate media, not armv7, retrying my 2nd test . . .
I suspect it could be this one: sys/arm/arm/syscall.c has this in cpu_fetch_syscall_args(): if (sa->code == SYS_syscall) { sa->code = *ap++; nap--; } else if (sa->code == SYS___syscall) { sa->code = ap[_QUAD_LOWWORD]; nap -= 2; ap += 2; } whereas arm64/arm64/elf32_machdep.c has: if (sa->code == SYS_syscall) { sa->code = *ap++; nap--; } else if (sa->code == SYS___syscall) { sa->code = ap[1]; nap -= 2; ap += 2; } Now _QUAD_LOWWORD is 1, but only on big endian. On little endian it's 0. This means we grab the wrong syscall number. Let me test a fix real quick.
(In reply to Mark Millard from comment #7) Looks like I was even wrong about still having a 14.* armv7 world around to test. So I establshed a new such place for chroot use and tested (via a main 16 host context): # uname -apKU FreeBSD aarch64-main-pbase 16.0-CURRENT FreeBSD 16.0-CURRENT main-n281256-7d6221ff1447 GENERIC-NODEBUG arm armv7 1600001 1403506 # cc armv7__syscall_test.c # ./a.out Bad system call (core dumped) As for i386 (testing via a main 16 amd64 host, not 15.0): # uname -apKU FreeBSD 7950X3D-ZFS 16.0-CURRENT FreeBSD 16.0-CURRENT main-n281155-86d17239233e GENERIC-NODEBUG i386 i386 1600001 1403506 # cc i386__syscall_test.c # ./a.out #
Confirmed to fix the bug.
(In reply to Robert Clausecker from comment #10) So may be 15.0-RELEASE can be corrected in time.
A commit in branch main references this bug: URL: https://cgit.FreeBSD.org/src/commit/?id=1ca09538d94273601dac08204c1d0b3ca9115864 commit 1ca09538d94273601dac08204c1d0b3ca9115864 Author: Robert Clausecker <fuz@FreeBSD.org> AuthorDate: 2025-10-21 21:35:24 +0000 Commit: Robert Clausecker <fuz@FreeBSD.org> CommitDate: 2025-10-22 12:24:41 +0000 sys/arm64: fix COMPAT_FREEBSD32 __syscall() It seems like _QUAD_LOWWORD was incorrectly expanded into 1, which is correct for big endian but not little endian. This means we always grab the padding word for the syscall number, which is usually 0, causing SIGSYS to be delivered to the caller. Reintroduce _QUAD_LOWWORD to fix the syscall. PR: 290411 MFC after: 1 week Discussed with: jrtc27 Reviewed by: cognet, emaste Approved by: markj (mentor) Fixes: 8c9c3144ccfa3061879b8cec015ee7d1010e4766 Differential Revision: https://reviews.freebsd.org/D53250 sys/arm64/arm64/elf32_machdep.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
A commit in branch stable/15 references this bug: URL: https://cgit.FreeBSD.org/src/commit/?id=c824960b89af082e5f083c0c4f141965d203eaa1 commit c824960b89af082e5f083c0c4f141965d203eaa1 Author: Robert Clausecker <fuz@FreeBSD.org> AuthorDate: 2025-10-21 21:35:24 +0000 Commit: Robert Clausecker <fuz@FreeBSD.org> CommitDate: 2025-10-29 11:15:21 +0000 sys/arm64: fix COMPAT_FREEBSD32 __syscall() It seems like _QUAD_LOWWORD was incorrectly expanded into 1, which is correct for big endian but not little endian. This means we always grab the padding word for the syscall number, which is usually 0, causing SIGSYS to be delivered to the caller. Reintroduce _QUAD_LOWWORD to fix the syscall. PR: 290411 MFC after: 1 week Discussed with: jrtc27 Reviewed by: cognet, emaste Approved by: markj (mentor) Fixes: 8c9c3144ccfa3061879b8cec015ee7d1010e4766 Differential Revision: https://reviews.freebsd.org/D53250 (cherry picked from commit 1ca09538d94273601dac08204c1d0b3ca9115864) sys/arm64/arm64/elf32_machdep.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
A commit in branch stable/14 references this bug: URL: https://cgit.FreeBSD.org/src/commit/?id=cb2921924549b8068c67c6e35331d72b9b71e658 commit cb2921924549b8068c67c6e35331d72b9b71e658 Author: Robert Clausecker <fuz@FreeBSD.org> AuthorDate: 2025-10-21 21:35:24 +0000 Commit: Robert Clausecker <fuz@FreeBSD.org> CommitDate: 2025-10-29 11:16:47 +0000 sys/arm64: fix COMPAT_FREEBSD32 __syscall() It seems like _QUAD_LOWWORD was incorrectly expanded into 1, which is correct for big endian but not little endian. This means we always grab the padding word for the syscall number, which is usually 0, causing SIGSYS to be delivered to the caller. Reintroduce _QUAD_LOWWORD to fix the syscall. PR: 290411 MFC after: 1 week Discussed with: jrtc27 Reviewed by: cognet, emaste Approved by: markj (mentor) Fixes: 8c9c3144ccfa3061879b8cec015ee7d1010e4766 Differential Revision: https://reviews.freebsd.org/D53250 (cherry picked from commit 1ca09538d94273601dac08204c1d0b3ca9115864) sys/arm64/arm64/elf32_machdep.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
A commit in branch releng/15.0 references this bug: URL: https://cgit.FreeBSD.org/src/commit/?id=245d95ce16f366ebffaef3cdec938fa575979b68 commit 245d95ce16f366ebffaef3cdec938fa575979b68 Author: Robert Clausecker <fuz@FreeBSD.org> AuthorDate: 2025-10-21 21:35:24 +0000 Commit: Colin Percival <cperciva@FreeBSD.org> CommitDate: 2025-10-30 04:22:09 +0000 sys/arm64: fix COMPAT_FREEBSD32 __syscall() It seems like _QUAD_LOWWORD was incorrectly expanded into 1, which is correct for big endian but not little endian. This means we always grab the padding word for the syscall number, which is usually 0, causing SIGSYS to be delivered to the caller. Reintroduce _QUAD_LOWWORD to fix the syscall. Approved by: re (cperciva) PR: 290411 MFC after: 1 week Discussed with: jrtc27 Reviewed by: cognet, emaste Approved by: markj (mentor) Fixes: 8c9c3144ccfa3061879b8cec015ee7d1010e4766 Differential Revision: https://reviews.freebsd.org/D53250 (cherry picked from commit 1ca09538d94273601dac08204c1d0b3ca9115864) (cherry picked from commit c824960b89af082e5f083c0c4f141965d203eaa1) sys/arm64/arm64/elf32_machdep.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)