Bug 290411 - lib32: __syscall() not supported
Summary: lib32: __syscall() not supported
Status: Closed FIXED
Alias: None
Product: Base System
Classification: Unclassified
Component: arm (show other bugs)
Version: 15.0-CURRENT
Hardware: arm64 Any
: --- Affects Some People
Assignee: freebsd-arm (Nobody)
URL: https://reviews.freebsd.org/D53250
Keywords:
Depends on:
Blocks:
 
Reported: 2025-10-21 20:26 UTC by Robert Clausecker
Modified: 2025-11-10 11:01 UTC (History)
2 users (show)

See Also:
fuz: mfc-stable15?
fuz: mfc-stable14?


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Robert Clausecker freebsd_committer freebsd_triage 2025-10-21 20:26:20 UTC
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.
Comment 1 Mark Millard 2025-10-21 20:46:03 UTC
FYI: This also happens in a chroot to a armv7 world. It
is not specific to lib32.

So the summary likely should be adjusted.
Comment 2 Robert Clausecker freebsd_committer freebsd_triage 2025-10-21 20:51:28 UTC
It's a kernel issue, as the kernel gives SIGSYS / ENOSYS for SYS___syscall.
Comment 3 Robert Clausecker freebsd_committer freebsd_triage 2025-10-21 21:02:25 UTC
Should also affect i386 on amd64.  sys/compat/freebsd32/freebsd32_sysent.c has nosys for both SYS_syscall and SYS___syscall.
Comment 4 Mark Millard 2025-10-21 21:03:24 UTC
(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.
Comment 5 Mark Millard 2025-10-21 21:05:06 UTC
(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.
Comment 6 Robert Clausecker freebsd_committer freebsd_triage 2025-10-21 21:10:29 UTC
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?
Comment 7 Mark Millard 2025-10-21 21:13:10 UTC
Drat,

You likely are correct: Looks like I used the wrong directory tree
(aarch64) on that separate media, not armv7, retrying my 2nd test
. . .
Comment 8 Robert Clausecker freebsd_committer freebsd_triage 2025-10-21 21:13:53 UTC
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.
Comment 9 Mark Millard 2025-10-21 22:00:07 UTC
(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
#
Comment 10 Robert Clausecker freebsd_committer freebsd_triage 2025-10-21 22:16:59 UTC
Confirmed to fix the bug.
Comment 11 Mark Millard 2025-10-21 22:37:47 UTC
(In reply to Robert Clausecker from comment #10)

So may be 15.0-RELEASE can be corrected in time.
Comment 12 commit-hook freebsd_committer freebsd_triage 2025-10-22 12:29:12 UTC
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(-)
Comment 13 commit-hook freebsd_committer freebsd_triage 2025-10-29 11:16:41 UTC
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(-)
Comment 14 commit-hook freebsd_committer freebsd_triage 2025-10-29 11:17:43 UTC
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(-)
Comment 15 commit-hook freebsd_committer freebsd_triage 2025-10-30 04:24:06 UTC
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(-)