syscall(2)

الاسم
syscall - استدعاء نظام غير مباشر

المكتبة
مكتبة سي المعيارية (libc، -lc)

موجز
#include <sys/syscall.h>      /* تعريف ثوابت SYS_* */
#include <unistd.h>

long syscall(long number, ...);

    متطلبات ماكروات اختبار الميزات لـ glibc (انظر feature_test_macros(7)):

syscall():
    بدءًا من glibc 2.19:
        _DEFAULT_SOURCE
    قبل glibc 2.19:
        _BSD_SOURCE || _SVID_SOURCE

الوصف
syscall() هي دالة مكتبة صغيرة تستدعي استدعاء النظام الذي تمتلك واجهة لغة التجميع الخاصة به الـ number المحدّد مع الوسائط المحدّدة. يُعدّ استخدام syscall() مفيدًا، على سبيل المثال، عند استدعاء استدعاء نظام ليس له دالة غلاف (wrapper) في مكتبة سي.

تحفظ syscall() سجلات وحدة المعالجة المركزية قبل إجراء استدعاء النظام، وتستعيد السجلات عند العودة من استدعاء النظام، وتخزن أي خطأ يرجعه استدعاء النظام في errno(3).

يمكن العثور على الثوابت الرمزية لأرقام استدعاءات النظام في ملف الترويسة <sys/syscall.h>.

قيمة الإرجاع
تُعرّف قيمة الإرجاع بواسطة استدعاء النظام المُستدعَى. وبشكل عام، تشير قيمة الإرجاع 0 إلى النجاح. وتشير قيمة الإرجاع -1 إلى حدوث خطأ، ويُخزن رقم الخطأ في errno.

الأخطاء

ENOSYS
    رقم استدعاء النظام المطلوب غير مُنفّذ.

الأخطاء الأخرى خاصة باستدعاء النظام المُستدعَى.

التاريخ
ظهرت syscall() لأول مرة في 4BSD.

ملاحظات

  متطلبات خاصة بالبنية
لكل واجهة تطبيق ثنائية (ABI) خاصة ببنية معينة متطلباتها الخاصة حول كيفية تمرير وسائط استدعاء النظام إلى النواة. بالنسبة لاستدعاءات النظام التي تملك غلاف glibc (مثل معظم استدعاءات النظام)، تتولى glibc تفاصيل نسخ الوسائط إلى السجلات الصحيحة بطريقة مناسبة للبنية. ومع ذلك، عند استخدام syscall() لإجراء استدعاء نظام، قد يحتاج المستدعِي إلى التعامل مع التفاصيل المعتمدة على البنية؛ ويواجه هذا المتطلب بشكل شائع في بنى معينة ذات 32 بت.

على سبيل المثال، في بنية ARM ذات واجهة التطبيق الثنائية المدمجة (EABI)، يجب محاذاة القيمة ذات 64 بت (مثل long long) مع زوج سجلات زوجي. وبالتالي، عند استخدام syscall() بدلاً من الغلاف الذي توفره glibc، سيُستدعى استدعاء النظام readahead(2) كما يلي على بنية ARM مع EABI في وضع endian الصغير (little endian):

    syscall(SYS_readahead, fd, 0,
            (unsigned int) (offset & 0xFFFFFFFF),
            (unsigned int) (offset >> 32),
            count);

بما أن وسيط الإزاحة (offset) هو 64 بت، والوسيط الأول (fd) يُمرر في r0، يجب على المستدعِي تقسيم ومحاذاة القيمة ذات 64 بت يدويًا بحيث تُمرر في زوج السجلات r2/r3. وهذا يعني إدراج قيمة وهمية في r1 (الوسيط الثاني وهو 0). يجب أيضًا توخي الحذر لضمان أن التقسيم يتبع اتفاقيات endian (وفقًا لواجهة التطبيق الثنائية للغة سي للمنصة).

يمكن أن تحدث مشكلات مماثلة على MIPS مع O32 ABI، وعلى PowerPC و parisc مع ABI ذي 32 بت، وعلى Xtensa.

لاحظ أنه على الرغم من أن parisc C ABI يستخدم أيضًا أزواج سجلات محاذاة، إلا أنه يستخدم طبقة حشو (shim layer) لإخفاء المشكلة عن مساحة المستخدم.

استدعاءات النظام المتأثرة هي fadvise64_64(2)، و ftruncate64(2)، و posix_fadvise(2)، و pread64(2)، و pwrite64(2)، و readahead(2)، و sync_file_range(2)، و truncate64(2).

لا يؤثر هذا على استدعاءات النظام التي تقسم وتجمع القيم ذات 64 بت يدويًا مثل _llseek(2)، و preadv(2)، و preadv2(2)، و pwritev(2)، و pwritev2(2). مرحبًا بك في عالم الموروثات التاريخية الرائع.

  اتفاقيات استدعاء البنية
لكل بنية طريقتها الخاصة في استدعاء الوسائط وتمريرها إلى النواة. تفاصيل البنى المختلفة مدرجة في الجدولين أدناه.

يسرد الجدول الأول التعليمات المستخدمة للانتقال إلى وضع النواة (والتي قد لا تكون الطريقة الأسرع أو الأفضل للانتقال إلى النواة، لذا قد تضطر إلى الرجوع إلى vdso(7))، والسجل المستخدم للإشارة إلى رقم استدعاء النظام، والسجل (السجلات) المستخدم لإرجاع نتيجة استدعاء النظام، والسجل المستخدم للإشارة إلى خطأ.
البنية/ABI | التعليمة | النظام | Ret | Ret | الخطأ | ملاحظات
 |  | رقم الاستدعاء | val | val2
alpha | callsys | v0 | v0 | a4 | a3 | 1, 6
arc | trap0 | r8 | r0 | - | -
arm/OABI | swi NR | - | r0 | - | - | 2
arm/EABI | swi 0x0 | r7 | r0 | r1 | -
arm64 | svc #0 | w8 | x0 | x1 | -
blackfin | excpt 0x0 | P0 | R0 | - | -
i386 | int $0x80 | eax | eax | edx | -
ia64 | break 0x100000 | r15 | r8 | r9 | r10 | 1, 6
loongarch | syscall 0 | a7 | a0 | - | -
m68k | trap #0 | d0 | d0 | - | -
microblaze | brki r14,8 | r12 | r3 | - | -
mips | syscall | v0 | v0 | v1 | a3 | 1, 6
nios2 | trap | r2 | r2 | - | r7
parisc | ble 0x100(%sr2, %r0) | r20 | r28 | - | -
powerpc | sc | r0 | r3 | - | r0 | 1
powerpc64 | sc | r0 | r3 | - | cr0.SO | 1
riscv | ecall | a7 | a0 | a1 | -
s390 | svc 0 | r1 | r2 | r3 | - | 3
s390x | svc 0 | r1 | r2 | r3 | - | 3
superh | trapa #31 | r3 | r0 | r1 | - | 4, 6
sparc/32 | t 0x10 | g1 | o0 | o1 | psr/csr | 1, 6
sparc/64 | t 0x6d | g1 | o0 | o1 | psr/csr | 1, 6
tile | swint1 | R10 | R00 | - | R01 | 1
x86-64 | syscall | eax | rax | rdx | - | 5
x32 | syscall | eax | rax | rdx | - | 5
xtensa | syscall | a2 | a2 | - | -

ملاحظات:

[1] في عدد قليل من المعماريات، يُستخدم مسجل كقيمة منطقية (0 تشير إلى عدم وجود خطأ، و -1 تشير إلى وجود خطأ) للإشارة إلى فشل استدعاء النظام. ما تزال قيمة الخطأ الفعلية موجودة في مسجل الإرجاع. في sparc، تُستخدم بتة الحمل (csr) في مسجل حالة المعالج (psr) بدلاً من مسجل كامل. وفي powerpc64، تُستخدم بتة تجاوز المخلص (SO) في الحقل 0 من مسجل الحالة (cr0).

[2] NR هو رقم استدعاء النظام.

[3] بالنسبة لـ s390 و s390x، يمكن تمرير NR (رقم استدعاء النظام) مباشرة عبر svc NR إذا كان أقل من 256.

[4] تُدعم أرقام مصيدة (trap) إضافية في SuperH لأسباب تاريخية، ولكن trapa#31 هي واجهة تطبيق الثنائيات (ABI) "الموحدة" الموصى بها.

[5] تتشارك ABI الخاصة بـ x32 جدول استدعاءات النظام مع ABI الخاصة بـ x86-64، ولكن هناك بعض الفوارق الدقيقة:

    •   للإشارة إلى أن استدعاء النظام يُستدعى تحت ABI الخاصة بـ x32، تُجرى عملية OR منطقية لبتة إضافية، __X32_SYSCALL_BIT، مع رقم استدعاء النظام. تؤثر ABI المستخدمة من قبل العملية على بعض سلوكيات العملية، بما في ذلك معالجة الإشارات أو إعادة تشغيل استدعاء النظام.

    •   بما أن x32 لديه أحجام مختلفة للأنواع long والمؤشرات، فإن تخطيطات بعض الهياكل تختلف (ولكن ليس كلها؛ struct timeval أو struct rlimit هي 64 بت، على سبيل المثال). للتعامل مع هذا، أُضيفت استدعاءات نظام إضافية إلى جدول استدعاءات النظام، بدءاً من الرقم 512 (بدون __X32_SYSCALL_BIT). على سبيل المثال، عُرّف __NR_readv بالرقم 19 لـ ABI الخاصة بـ x86-64 وبالقيمة __X32_SYSCALL_BIT | 515 لـ ABI الخاصة بـ x32. معظم استدعاءات النظام الإضافية هذه متطابقة فعلياً مع استدعاءات النظام المستخدمة لتوفير توافق i386. ومع ذلك، هناك بعض الاستثناءات الملحوظة، مثل preadv2(2)، الذي يستخدم كيانات struct iovec بمؤشرات وأحجام من 4 بايت ("compat_iovec" بمصطلحات النواة)، ولكنه يمرر وسيط pos بحجم 8 بايت في مسجل واحد وليس اثنين، كما هو الحال في كل ABI أخرى.

[6] تستخدم بعض المعماريات (وهي Alpha و IA-64 و MIPS و SuperH و sparc/32 و sparc/64) مسجلاً إضافياً ("Retval2" في الجدول أعلاه) لإعادة قيمة إرجاع ثانية من استدعاء النظام pipe(2)؛ وتستخدم Alpha هذه التقنية في استدعاءات النظام الخاصة بالمعمارية getxpid(2) و getxuid(2) و getxgid(2) أيضًا. المعماريات الأخرى لا تستخدم مسجل قيمة الإرجاع الثانية في واجهة استدعاء النظام، حتى لو كانت معرفة في ABI الخاصة بـ System V.

يوضح الجدول الثاني المسجلات المستخدمة لتمرير وسائط استدعاء النظام.
البنية/ABI | arg1 | arg2 | arg3 | arg4 | arg5 | arg6 | arg7 | ملاحظات
alpha | a0 | a1 | a2 | a3 | a4 | a5 | -
arc | r0 | r1 | r2 | r3 | r4 | r5 | -
arm/OABI | r0 | r1 | r2 | r3 | r4 | r5 | r6
arm/EABI | r0 | r1 | r2 | r3 | r4 | r5 | r6
arm64 | x0 | x1 | x2 | x3 | x4 | x5 | -
blackfin | R0 | R1 | R2 | R3 | R4 | R5 | -
i386 | ebx | ecx | edx | esi | edi | ebp | -
ia64 | out0 | out1 | out2 | out3 | out4 | out5 | -
loongarch | a0 | a1 | a2 | a3 | a4 | a5 | a6
m68k | d1 | d2 | d3 | d4 | d5 | a0 | -
microblaze | r5 | r6 | r7 | r8 | r9 | r10 | -
mips/o32 | a0 | a1 | a2 | a3 | - | - | - | 1
mips/n32,64 | a0 | a1 | a2 | a3 | a4 | a5 | -
nios2 | r4 | r5 | r6 | r7 | r8 | r9 | -
parisc | r26 | r25 | r24 | r23 | r22 | r21 | -
powerpc | r3 | r4 | r5 | r6 | r7 | r8 | r9
powerpc64 | r3 | r4 | r5 | r6 | r7 | r8 | -
riscv | a0 | a1 | a2 | a3 | a4 | a5 | -
s390 | r2 | r3 | r4 | r5 | r6 | r7 | -
s390x | r2 | r3 | r4 | r5 | r6 | r7 | -
superh | r4 | r5 | r6 | r7 | r0 | r1 | r2
sparc/32 | o0 | o1 | o2 | o3 | o4 | o5 | -
sparc/64 | o0 | o1 | o2 | o3 | o4 | o5 | -
tile | R00 | R01 | R02 | R03 | R04 | R05 | -
x86-64 | rdi | rsi | rdx | r10 | r8 | r9 | -
x32 | rdi | rsi | rdx | r10 | r8 | r9 | -
xtensa | a6 | a3 | a4 | a5 | a8 | a9 | -

ملاحظات:

[1] تمرر اتفاقية استدعاء النظام mips/o32 المعاملات من 5 إلى 8 عبر مكدس المستخدم.

لاحظ أن هذه الجداول لا تغطي اتفاقية الاستدعاء بأكملها؛ فقد تفرغ بعض المعماريات سجلات أخرى غير مدرجة هنا دون تمييز.

أمثلة
    #define _GNU_SOURCE
    #include <signal.h>
    #include <sys/syscall.h>
    #include <sys/types.h>
    #include <unistd.h>

    int
    main(void)
    {
        pid_t tid;

        tid = syscall(SYS_gettid);
        syscall(SYS_tgkill, getpid(), tid, SIGHUP);
    }

انظر أيضًا
_syscall(2)، intro(2)، syscalls(2)، errno(3)، vdso(7)

ترجمة
تُرجمت هذه الصفحة من الدليل بواسطة زايد السعيدي <zayed.alsaidi@gmail.com>

هذه الترجمة هي وثيقة مجانية؛ راجع رخصة جنو العامة الإصدار 3 (https://www.gnu.org/licenses/gpl-3.0.html) أو ما بعده للاطلاع على شروط حقوق النشر. لا توجد أي ضمانات.

إذا وجدت أي أخطاء في ترجمة صفحة الدليل هذه، يرجى إرسال بريد إلكتروني إلى قائمة بريد المترجمين: kde-l10n-ar@kde.org.