Scroll to navigation

RTLD-AUDIT(7) Miscellaneous Information Manual RTLD-AUDIT(7)

الاسم

rtld-audit - واجهة برمجة تطبيقات التدقيق للرابط الديناميكي

موجز

#define _GNU_SOURCE             /* See feature_test_macros(7) */
#include <link.h>

الوصف

يوفر الرابط الديناميكي لجنو (رابط وقت التشغيل) واجهة برمجة تطبيقات تدقيق تسمح للتطبيق بالإشعار عند حدوث أحداث ربط ديناميكي مختلفة. تشبه واجهة برمجة التطبيقات هذه إلى حد كبير واجهة التدقيق التي يوفرها رابط وقت تشغيل Solaris. تُعرّف الثوابت والنماذج الأولية اللازمة بتضمين <link.h>.

لاستخدام هذه الواجهة، ينشئ المبرمج مكتبة مشتركة تطبق مجموعة قياسية من أسماء الدوال. لا يلزم تنفيذ جميع الدوال: في معظم الحالات، إذا لم يكن المبرمج مهتمًا بفئة معينة من أحداث التدقيق، فلا حاجة لتوفير تنفيذ لدالة التدقيق المقابلة.

لاستخدام واجهة التدقيق، يجب تعريف متغير البيئة LD_AUDIT ليحتوي على قائمة مفصولة بنقطتين من المكتبات المشتركة، يمكن لكل منها تنفيذ (أجزاء من) واجهة برمجة تطبيقات التدقيق. عند حدوث حدث قابل للتدقيق، تُستدعى الدالة المقابلة في كل مكتبة، بالترتيب الذي تظهر به المكتبات.

la_version()

unsigned int la_version(unsigned int version);

هذه هي الدالة الوحيدة التي يجب تعريفها بواسطة مكتبة التدقيق: تؤدي المصافحة الأولية بين الرابط الديناميكي ومكتبة التدقيق. عند استدعاء هذه الدالة، يمرر الرابط الديناميكي، في version، أعلى إصدار من واجهة التدقيق التي يدعمها الرابط.

يعيد التنفيذ النموذجي لهذه الدالة ببساطة الثابت LAV_CURRENT، الذي يشير إلى إصدار <link.h> المستخدم لبناء وحدة التدقيق. إذا لم يدعم الرابط الديناميكي هذا الإصدار من واجهة التدقيق، سيرفض تفعيل وحدة التدقيق هذه. إذا أعادت الدالة صفرًا، لن يفعل الرابط الديناميكي أيضًا وحدة التدقيق هذه.

لتمكين التوافق العكسي مع الروابط الديناميكية الأقدم، يمكن لوحدة التدقيق فحص وسيط version وإعادة إصدار أقدم من LAV_CURRENT، بافتراض أن الوحدة يمكنها تعديل تنفيذها لمطابقة متطلبات الإصدار السابق من واجهة التدقيق. لا ينبغي لدالة la_version إعادة قيمة version دون فحوصات إضافية لأنها قد تتوافق مع واجهة لا تطابق تعريفات <link.h> المستخدمة لبناء وحدة التدقيق.

la_objsearch()

char *la_objsearch(const char *name, uintptr_t *cookie,
                   unsigned int flag);

يستدعي الرابط الديناميكي هذه الدالة لإعلام مكتبة التدقيق بأنه على وشك البحث عن كائن مشترك. وسيط name هو اسم الملف أو اسم المسار الذي سيُبحث عنه. يُعرّف cookie الكائن المشترك الذي بدأ البحث. يُضبط flag على إحدى القيم التالية:

هذا هو الاسم الأصلي الذي يُبحث عنه. عادةً، يأتي هذا الاسم من إدخال ELF DT_NEEDED، أو هو وسيط filename المعطى لـ dlopen(3).
name أُنشئ باستخدام دليل محدد في LD_LIBRARY_PATH.
name أُنشئ باستخدام دليل محدد في قائمة ELF DT_RPATH أو DT_RUNPATH.
name وُجد عبر خبيئة ldconfig(8) (/etc/ld.so.cache).
name وُجد عبر بحث في أحد الأدلة المبدئية.
name خاص بكائن آمن (غير مستخدم على لينكس).

كنتيجة لدالتها، تُرجع la_objsearch() اسم المسار الذي ينبغي على الرابط الديناميكي استخدامه للمعالجة اللاحقة. إذا أُرجع NULL، يُتجاهل اسم المسار هذا للمعالجة اللاحقة. إذا كانت مكتبة التدقيق هذه تهدف ببساطة إلى مراقبة مسارات البحث، ينبغي إرجاع name.

la_activity()

void la_activity( uintptr_t *cookie, unsigned int flag);

يستدعي الرابط الديناميكي هذه الدالة لإعلام مكتبة التدقيق بأن نشاط خريطة الوصل يحدث. يُحدد cookie الكائن في رأس خريطة الوصل. عندما يستدعي الرابط الديناميكي هذه الدالة، يُضبط flag على إحدى القيم التالية:

تُضاف كائنات جديدة إلى خريطة الوصل.
تُزال كائنات من خريطة الوصل.
اكتمل نشاط خريطة الوصل: أصبحت الخريطة متسقة مرة أخرى.

la_objopen()

unsigned int la_objopen(struct link_map *map, Lmid_t lmid,
                        uintptr_t *cookie);

يستدعي الرابط الديناميكي هذه الدالة عند تحميل كائن مشترك جديد. وسيطة map هي مؤشر لبنية خريطة وصل تصف الكائن. يحتوي حقل lmid على إحدى القيم التالية:

خريطة الوصل جزء من النطاق الأولي.
خريطة الوصل جزء من نطاق جديد طُلب عبر dlmopen(3).

cookie هو مؤشر لمعرّف لهذا الكائن. يُقدم المعرّف لاستدعاءات لاحقة لدوال في مكتبة التدقيق من أجل تحديد هذا الكائن. يُهيأ هذا المعرّف للإشارة إلى خريطة وصل الكائن، لكن يمكن لمكتبة التدقيق تغيير المعرّف إلى قيمة أخرى قد تفضلها لاستخدامها في تحديد الكائن.

كقيمة إرجاعها، تُرجع la_objopen() قناع بتات يُنشأ بإجراء عملية OR على صفر أو أكثر من الثوابت التالية، والتي تسمح لمكتبة التدقيق باختيار الكائنات التي ستُراقب بواسطة la_symbind*():

تدقيق ارتباطات الرموز بهذا الكائن.
تدقيق ارتباطات الرموز من هذا الكائن.

قيمة إرجاع 0 من la_objopen() تشير إلى أنه لا ينبغي تدقيق أي ارتباطات رموز لهذا الكائن.

la_objclose()

unsigned int la_objclose(uintptr_t *cookie);

يستدعي الرابط الديناميكي هذه الدالة بعد تنفيذ أي كود إنهاء للكائن، قبل تفريغ الكائن. وسيطة cookie هي المعرّف الذي حُصل عليه من استدعاء سابق لـ la_objopen().

في التطبيق الحالي، يتم تجاهل القيمة التي يعيدها la_objclose().

la_preinit()

void la_preinit(uintptr_t *cookie);

يستدعي الرابط الديناميكي هذه الدالة بعد تحميل جميع الكائنات المشتركة، قبل تمرير التحكم إلى التطبيق (أي قبل استدعاء main()). لاحظ أن main() قد لا يزال يقوم لاحقًا بتحميل الكائنات ديناميكيًا باستخدام dlopen(3).

la_symbind*()

uintptr_t la_symbind32(Elf32_Sym *sym, unsigned int ndx,
                       uintptr_t *refcook, uintptr_t *defcook,
                       unsigned int *flags, const char *symname);
uintptr_t la_symbind64(Elf64_Sym *sym, unsigned int ndx,
                       uintptr_t *refcook, uintptr_t *defcook,
                       unsigned int *flags, const char *symname);

يستدعي الرابط الديناميكي إحدى هذه الدوال عند حدوث ربط رمز بين كائنين مشتركين تم وضع علامة عليهما لإشعار التدقيق بواسطة la_objopen(). تُستخدم الدالة la_symbind32() على المنصات 32-بت؛ وتُستخدم الدالة la_symbind64() على المنصات 64-بت.

الوسيطة sym هي مؤشر إلى بنية توفر معلومات حول الرمز الذي يتم ربطه. يظهر تعريف البنية في <elf.h>. من بين حقول هذه البنية، يشير st_value إلى العنوان الذي يتم ربط الرمز به.

تعطي الوسيطة ndx فهرس الرمز في جدول الرموز للكائن المشترك المرتبط.

تحدد الوسيطة refcook الكائن المشترك الذي يقوم بمرجع الرمز؛ هذا هو نفس المعرف الذي يتم توفيره للدالة la_objopen() التي أعادت LA_FLG_BINDFROM. تحدد الوسيطة defcook الكائن المشترك الذي يعرف الرمز المشار إليه؛ هذا هو نفس المعرف الذي يتم توفيره للدالة la_objopen() التي أعادت LA_FLG_BINDTO.

تشير الوسيطة symname إلى سلسلة تحتوي على اسم الرمز.

الوسيطة flags هي قناع بت يوفر معلومات حول الرمز ويمكن استخدامه لتعديل التدقيق الإضافي لهذا الإدخال في PLT (جدول ربط الإجراءات). قد يوفر الرابط الديناميكي قيم البت التالية في هذه الوسيطة:

نتج الربط عن استدعاء لـ dlsym(3).
أعاد استدعاء سابق لـ la_symbind*() قيمة بديلة لهذا الرمز.

افتراضيًا، إذا نفذت مكتبة التدقيق دالتي la_pltenter() و la_pltexit() (انظر أدناه)، فسيتم استدعاء هذه الدوال، بعد la_symbind()، لإدخالات PLT، في كل مرة يتم فيها مرجع الرمز. يمكن إجراء عملية OR للأعلام التالية في *flags لتغيير هذا السلوك الافتراضي:

لا تستدع la_pltenter() لهذا الرمز.
لا تستدع la_pltexit() لهذا الرمز.

قيمة الإرجاع لـ la_symbind32() و la_symbind64() هي العنوان الذي يجب تمرير التحكم إليه بعد إرجاع الدالة. إذا كانت مكتبة التدقيق تراقب ببساطة ربط الرموز، فيجب أن تعيد sym->st_value. قد يتم إرجاع قيمة مختلفة إذا رغبت المكتبة في توجيه التحكم إلى موقع بديل.

la_pltenter()

يعتمد الاسم الدقيق وأنواع الوسائط لهذه الدالة على منصة العتاد. (يتم توفير التعريف المناسب بواسطة <link.h>.) إليك التعريف لـ x86-32:

Elf32_Addr la_i86_gnu_pltenter(Elf32_Sym *sym, unsigned int ndx,
                 uintptr_t *refcook, uintptr_t *defcook,
                 La_i86_regs *regs, unsigned int *flags,
                 const char *symname, long *framesizep);

تُستدعى هذه الدالة قبل استدعاء مدخل PLT مباشرة، بين كائنين مشتركين تم وضع علامة عليهما لإشعار الربط.

sym و ndx و refcook و defcook و symname هي كما في la_symbind*().

يشير وسيط regs إلى بنية (مُعرّفة في <link.h>) تحتوي على قيم السجلات المستخدمة لاستدعاء مدخل PLT هذا.

يشير وسيط flags إلى قناع بت ينقل معلومات حول مدخل PLT هذا، ويمكن استخدامه لتعديل التدقيق اللاحق له، كما في la_symbind*().

يشير وسيط framesizep إلى مخبأ long int يمكن استخدامه لتعيين حجم الإطار المستخدم لاستدعاء مدخل PLT هذا بشكل صريح. إذا أعادت استدعاءات مختلفة لـ la_pltenter() لهذا الرمز قيماً مختلفة، فتُستخدم القيمة القصوى المُعادة. تُستدعى دالة la_pltexit() فقط إذا تم تعيين هذا المخبأ بشكل صريح إلى قيمة مناسبة.

قيمة إرجاع la_pltenter() هي كما في la_symbind*().

la_pltexit()

يعتمد الاسم الدقيق وأنواع الوسائط لهذه الدالة على منصة العتاد. (يتم توفير التعريف المناسب بواسطة <link.h>.) إليك التعريف لـ x86-32:

unsigned int la_i86_gnu_pltexit(Elf32_Sym *sym, unsigned int ndx,
                 uintptr_t *refcook, uintptr_t *defcook,
                 const La_i86_regs *inregs, La_i86_retval *outregs,
                 const char *symname);

تُستدعى هذه الدالة عندما يعود مدخل PLT، الذي أُنشئ بين كائنين مشتركين تم وضع علامة عليهما لإشعار الربط. تُستدعى الدالة قبل عودة التحكم إلى مستدعي مدخل PLT مباشرة.

sym و ndx و refcook و defcook و symname هي كما في la_symbind*().

يشير وسيط inregs إلى بنية (مُعرّفة في <link.h>) تحتوي على قيم السجلات المستخدمة لاستدعاء مدخل PLT هذا. يشير وسيط outregs إلى بنية (مُعرّفة في <link.h>) تحتوي على قيم الإرجاع لاستدعاء مدخل PLT هذا. يمكن للمستدعي تعديل هذه القيم، وستكون التغييرات مرئية لمستدعي مدخل PLT.

في التطبيق الحالي لـ GNU، يتم تجاهل قيمة إرجاع la_pltexit().

الإصدارات

تشبه واجهة API هذه إلى حد كبير واجهة Solaris API الموصوفة في دليل Solaris Linker and Libraries Guide، في الفصل Runtime Linker Auditing Interface.

المعايير

لا يوجد.

ملاحظات

لاحظ الاختلافات التالية عن واجهة API لتدقيق الرابط الديناميكي في Solaris:

واجهة Solaris la_objfilter() غير مدعومة في تطبيق GNU.
دالتا Solaris la_symbind32() و la_pltexit() لا توفران وسيط symname.
دالة Solaris la_pltexit() لا توفر وسيطي inregs و outregs (لكنها توفر وسيط retval مع قيمة إرجاع الدالة).

العلل

في إصدارات glibc حتى 2.9، يؤدي تحديد أكثر من مكتبة تدقيق في LD_AUDIT إلى تعطل وقت التشغيل. يُقال إن هذا أُصلح في glibc 2.10.

أمثلة

#include <link.h>
#include <stdio.h>
unsigned int
la_version(unsigned int version)
{

printf("la_version(): version = %u; LAV_CURRENT = %u\n",
version, LAV_CURRENT);
return LAV_CURRENT; } char * la_objsearch(const char *name, uintptr_t *cookie, unsigned int flag) {
printf("la_objsearch(): name = %s; cookie = %p", name, cookie);
printf("; flag = %s\n",
(flag == LA_SER_ORIG) ? "LA_SER_ORIG" :
(flag == LA_SER_LIBPATH) ? "LA_SER_LIBPATH" :
(flag == LA_SER_RUNPATH) ? "LA_SER_RUNPATH" :
(flag == LA_SER_DEFAULT) ? "LA_SER_DEFAULT" :
(flag == LA_SER_CONFIG) ? "LA_SER_CONFIG" :
(flag == LA_SER_SECURE) ? "LA_SER_SECURE" :
"???");
return name; } void la_activity (uintptr_t *cookie, unsigned int flag) {
printf("la_activity(): cookie = %p; flag = %s\n", cookie,
(flag == LA_ACT_CONSISTENT) ? "LA_ACT_CONSISTENT" :
(flag == LA_ACT_ADD) ? "LA_ACT_ADD" :
(flag == LA_ACT_DELETE) ? "LA_ACT_DELETE" :
"???"); } unsigned int la_objopen(struct link_map *map, Lmid_t lmid, uintptr_t *cookie) {
printf("la_objopen(): loading \"%s\"; lmid = %s; cookie=%p\n",
map->l_name,
(lmid == LM_ID_BASE) ? "LM_ID_BASE" :
(lmid == LM_ID_NEWLM) ? "LM_ID_NEWLM" :
"???",
cookie);
return LA_FLG_BINDTO | LA_FLG_BINDFROM; } unsigned int la_objclose (uintptr_t *cookie) {
printf("la_objclose(): %p\n", cookie);
return 0; } void la_preinit(uintptr_t *cookie) {
printf("la_preinit(): %p\n", cookie); } uintptr_t la_symbind32(Elf32_Sym *sym, unsigned int ndx, uintptr_t *refcook,
uintptr_t *defcook, unsigned int *flags, const char *symname) {
printf("la_symbind32(): symname = %s; sym->st_value = %p\n",
symname, sym->st_value);
printf(" ndx = %u; flags = %#x", ndx, *flags);
printf("; refcook = %p; defcook = %p\n", refcook, defcook);
return sym->st_value; } uintptr_t la_symbind64(Elf64_Sym *sym, unsigned int ndx, uintptr_t *refcook,
uintptr_t *defcook, unsigned int *flags, const char *symname) {
printf("la_symbind64(): symname = %s; sym->st_value = %p\n",
symname, sym->st_value);
printf(" ndx = %u; flags = %#x", ndx, *flags);
printf("; refcook = %p; defcook = %p\n", refcook, defcook);
return sym->st_value; } Elf32_Addr la_i86_gnu_pltenter(Elf32_Sym *sym, unsigned int ndx,
uintptr_t *refcook, uintptr_t *defcook, La_i86_regs *regs,
unsigned int *flags, const char *symname, long *framesizep) {
printf("la_i86_gnu_pltenter(): %s (%p)\n", symname, sym->st_value);
return sym->st_value; }

انظر أيضًا

ldd(1), dlopen(3), ld.so(8), ldconfig(8)

ترجمة

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

هذه الترجمة هي وثيقة مجانية؛ راجع رخصة جنو العامة الإصدار 3 أو ما بعده للاطلاع على شروط حقوق النشر. لا توجد أي ضمانات.

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

17 مايو 2025 صفحات دليل لينكس 6.18