شرح لغة c إنتاج واستخدام مكتبة الارتباط الثابت ومكتبة الارتباط الديناميكي

الادارة كريم

مشرف سابق
مجموعة الاعضاء

لغة C إنتاج واستخدام مكتبة الارتباط الثابت ومكتبة الارتباط الديناميكي

. مقدمة موجزة عن مكتبة الوظائف

ببساطة ، مكتبة الوظائف هي مجموعة من الوظائف المعيارية المكتوبة مسبقًا ، والتي يمكن استخدامها من قبل المبرمجين الآخرين. في البداية ، لم تكن هناك مكتبة وظائف ، وكان على كل مبرمج كتابة برنامج من الصفر ، وبمرور الوقت ، تراكمت بعض مكتبات الوظائف عالية الجودة بشكل تدريجي. في وقت لاحق ، جمعت المنظمات مكتبات وظيفية مختلفة معًا ، ومعايرتها وفرزها ، وشكلت مكتبة وظائف موحدة ، وهي مكتبة الوظائف القياسية الحالية ، مثلglibc
1.1 توفير شكل مكتبة الوظائف: مكتبة الارتباط الديناميكي ومكتبة الارتباط الثابتة

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


  • تشكل الشركات التجارية الكود المصدري لمكتبة الوظائف بعد التجميع فقط وعدم الربط.oالملف الهدف ، ثم استخدمarأداة سوف.oملف في.aملف الأرشيف ، هذا.aيسمى ملف الأرشيف بملف مكتبة الارتباط الثابت. عن طريق النشر.aملفات المكتبة و.hملفات الرأس لتوفير مكتبات ثابتة للعملاء لاستخدامها ؛
  • حصل العميل.aمع.hبعد الملف ، مرر.hيعرف ملف الرأس النموذج الأولي لوظيفة المكتبة في المكتبة ، ثم بمفردها.cيتم استدعاء ملفات المكتبة هذه مباشرة في الملف ، وسوف ينتقل الرابط إلى.aأخرج الوظيفة المترجمة للوظيفة المطلوبة في الملف.oترتبط مقاطع الكود الثنائي لتشكيل البرنامج القابل للتنفيذ النهائي.
1.1.2 مكتبة الارتباط الديناميكي


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

gccيستخدم البرنامج المترجم والمرتبط مكتبات ديناميكية بشكل افتراضي. للربط الثابت ، تحتاج إلى استخدام صريح-staticلفرض ربط ثابت. يجب الانتباه إلى استخدام وظائف المكتبة:

  1. قم بتضمين ملف الرأس المقابل
  2. انتبه إلى النموذج الأولي للوظيفة عند استدعاء وظائف المكتبة
  3. تحتاج بعض وظائف المكتبة إلى استخدام إضافي عند الارتباط-lxxxلتحديد الارتباط
  4. إذا لم تكن مكتبة نظام ، فاحرص على استخدامها-Lحدد عنوان المكتبة
إذا استخدمنا مكتبة وظائف الرياضياتsqrtوظيفة:

  1. يتم تحديد وظيفة العملية الحسابية الحقيقية في:/usr/include/x86_64-linux-gnu/bits/mathcalls.h
  2. عند استخدام وظائف مكتبة الرياضيات ، ما عليك سوى تضمينهاmath.hعلبة
#include <stdio.h> #include <math.h> int main(void) { double x = 16.0; double y = sqrt(x); printf("y = %lf\n", y); return 0; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
الطلاب الذين درسوا لغة سي يعرفون أن الإجابة هي4.000000ولكن ما هي نتيجة التجميع المباشر؟ ننظر إلى الصورة أدناه:
3c44013b2f3438938c6740dd760b6425.png

سنجد أنه تم الإبلاغ عن خطأ عند الارتباط! التقرير صحيح'sqrt'مرجع غير محدد ، أي أن الدالة sqrt لها تصريح (بتنسيقmath.hفي) هناك مراجع (فيmath.c) ، ولكن لا يوجد تعريف ، فلا يمكن للرابط العثور على جسم الوظيفة. لماذا هو كذلك؟ نظرًا لوجود العديد من وظائف المكتبة ، يستغرق الرابط وقتًا طويلاً للبحث في دليل وظيفة المكتبة. من أجل تحسين السرعة ، يبحث الرابط فقط عن عدد قليل من المكتبات الأكثر استخدامًا بشكل افتراضي.إذا تم استدعاء الوظائف في بعض المكتبات غير الشائعة ، يحتاج المبرمج إلى إعطاء اسم المكتبة بشكل صريح ليتم توسيعه عند الارتباط.
عند الارتباط ، يمكنك استخدام -lxxx لتوجيه الرابط للعثور على وظائف في libxxx.a (ثابت) أو libxxx.so (متحرك)
27a124c4589d6443a5e626cd9f36f245.png

يمكننا أن نرى أن ملف-lmبعد ذلك ، تم ربطه بنجاح. وفي نفس الوقت ، يمكننا أيضًا أن نرى أن حجم الملف القابل للتنفيذ الذي تم إنشاؤه بواسطة ارتباط ثابت لا يماثل حجم الارتباط الديناميكي! ! !
ثانيًا ، قم بإنشاء واستخدام مكتبة ارتباط ثابتة

2.1 الإنتاج

قم بإنشاء ملفملف المصدرمعملف رأس .hإلى جانبMakefile:
touch mylib1.c mylib1.h Makefile
  • 1
قم بتحرير المحتوى المقابل لملف الرأس والملف المصدر ، كما هو موضح في الشكل:
a5a390ed3105e05905d4b0a00298aa01.png

بعد ذلك ، قم فقط بالتجميع بدون ارتباط وإنشاء.oملف ؛ ثم استخدمarيتم حزم الأدوات في.aأرشفة الملفات: عند الحزم ، انتبه إلى أن اسم المكتبة لا يكون عشوائيًا بشكل عامlib + اسم المكتبة، لاحقة.aيشير إلى أنه ملف مكتبة مرتبط بشكل ثابت. متجانسMakefileالمقطع هو كما يلي:
lib: gcc -c mylib1.c -o mylib1.o ar -rc libmylib1.a mylib1.o
  • 1
  • 2
  • 3
قم بتنفيذ البرنامج النصي المقابل لإكمال إنتاج المكتبة الثابتة
a8c78b2875e69807cefe6653657d0c1d.png

2.2 الإصدار

الافراج عن ما يسمى.aالملفات و.hيتم وضع الملفات في مجلد منفصل لاستخدامها لاحقًا. كما تظهر الصورة
4cdc4722570a88d654ab628255ae7cc9.png

3.3 الاستخدام

نحن نبني منطقتنا في المجلد المنشور.cملف ، يمكنك استدعاء وظائف المكتبة مباشرة!
touch main.c Makefile
  • 1
نضيف المحتوى التالي إلى الوظيفة الرئيسية:
#include "mylib1.h" int main(void) { myprint(); return 0; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
في1.2عند استخدام الدوال الرياضية ، نعلم أن الرابط سيبحث فقط عن عدد قليل من المكتبات الأكثر استخدامًا. ولن يتم البحث في المكتبات التي نصدرها بالتأكيد ، لذلك نحتاج إلى إضافة-lxxxانتقل إلى التحديد
all: gcc main.c -o main.elf -lmylib1
  • 1
  • 2
bc4cda00382a339ad48883416b3568a4.png

سنجد أنه لا يزال يتعذر ربط هذا بشكل صحيح ، وستظهر رسالة الخطأ التالية:/ usr / bin / ld: لا يمكن العثور على -lmylib1، نعلم من رسالة الخطأ أن الرابط يبحث فقط عن مكتبة الارتباط في الدليل المحدد بواسطة النظام افتراضيًا. لذلك تحتاج إلى استخدام -L لتحديد عنوان المكتبة ، نقوم بتعديل ملف Makefile على النحو التالي:
all: gcc main.c -o main.elf -lmylib1 -L.
  • 1
  • 2
فيما بينها.هذا يعني أنه في الدليل الحالي ، يمكننا أن نرى أن البرنامج قد تم تجميعه وربطه بنجاح
d6af607fdd1807bdb8a68df5c28e2dd7.png

ثالثًا ، قم بإنشاء واستخدام مكتبة الارتباط الديناميكي

3.1 الإنتاج والإصدار

يشبه إنتاج مكتبة الارتباط الديناميكي فكرة المكتبة الثابتة ، لكن اسم اللاحقة هو.so(windowsالتالي هوdll)،بواسطةgccلحزم بدلا من ذلكar،متجانسMakefileكما يلي:
lib: gcc -c mylib2.c -o mylib2.o -fPIC gcc mylib2.o -o libmylib2.so -shared
  • 1
  • 2
  • 3
فيما بينها:

  • -fPICإنه رمز مستقل عن الموضع ، يعمل في مرحلة التجميع ويخبر المترجم بإنشاء رمز مستقل عن الموضع(Position-Independent Code). أي أنه لا يوجد عنوان مطلق في الكود الذي تم إنشاؤه ، ويتم استخدام جميع العناوين النسبية ، ويمكن تنفيذه بشكل صحيح عندما يتم تحميله بواسطة المُحمل إلى أي مكان في الذاكرة. هذا هو بالضبط ما تتطلبه المكتبة المشتركة. عندما يتم تحميل المكتبة المشتركة ، لا يتم إصلاح موقعها في الذاكرة.
  • -sharedوهي مرتبطة حسب المكتبة المشتركة
انشر عند النشرlibxxx.soمعxxx.hنعم ، لن أكررها هنا
3.2 الاستخدام

من خلال تجربة المكتبات الثابتة ، نعلم أن تعليمات التجميع والربط يجب أن تكون:
all: gcc main.c -o main.elf -lmylib2 -L.
  • 1
  • 2
يمكننا أن نرى أن البرنامج قد تم تجميعه وربطه بنجاح
c1bb46333d629c445adea71dcbb203a7.png

ولكن حدث خطأ أثناء التشغيل وتم الإبلاغ عن رسالة خطأ:error while loading shared libraries: libmylib2.so: cannot open shared object file: No such file or directory
هذا بسببيجب تحميل مكتبة الارتباط الديناميكي عند تشغيلها(وجدت بيئة وقت التشغيل الارتباط الديناميكي عند تنفيذ البرنامجlibxxx. so، لذلك سوف تذهبالدليل الثابت/usr/libتحميل libxxx، إذا فشل التحميل ، ستتم طباعة رسالة الخطأ أعلاه. )
المحلول


  1. ضع libaston.so في الدليل الثابت / usr / lib
cp libmylib2.so /usr/lib
  • 1
كتالوج ثابت بشكل عام/usr/libتُستخدم لتخزين مكتبة الارتباط الديناميكي التي تأتي مع النظام ، ولا ينصح المستخدمون بتعديل المحتويات بأنفسهم

  1. استخدم متغير البيئة LD_LIBRARY_PATH
يقوم نظام التشغيل بتحميل دليل ثابت/usr/libمن قبل ، سوف أذهب أولاًLD_LIBRARY_PATHابحث عن الدليل المحدد بواسطة متغير البيئة هذا ، إذا وجده ، فلا تذهب/usr/libتحت الدليل ، إذا لم تجده ، فانتقل/usr/libتحت. حتى تستطيعlibaston.soتصدير الدليل إلى متغير البيئةLD_LIBRARY_PATHفي.
export LD_LIBRARY_PATH=D_LIBRARY_PATH:\ /mnt/hgfs/VMShare/C/6.PreprocessFunction/funclib/dynamiclib/publib
  • 1
  • 2
6795b09a286edd4cb6eb53810df79543.png

يمكننا أن نجد أنه يمكن تشغيل البرنامج مباشرة بعد استيراد متغيرات البيئة
3.3 ldd الأمر

lddيمكن للأمر تحليل المكتبات المشتركة التي يستخدمها البرنامج قبل تنفيذ برنامج يستخدم المكتبات المشتركة ، والتحقق مما إذا كان يمكن العثور على هذه المكتبات المشتركة ، مثل المثال أعلاه بعد إضافة المكتبة المشتركة ، وكلها مستخدمة.soيمكن حلها إلى عنوان
ed030e2dae8127ddeb8e9fe7afdd9c3f.png

إذا قمنا بتعيين متغير البيئة على فارغ:
export LD_LIBRARY_PATH=
  • 1
7eeb2b7405dcc91c60bf8dec5151e878.png

يمكننا أن نرى main.elfمرتبطlibmylib2.soفيnot foundالحالة ، لا يمكن تنفيذها بشكل صحيح
 

أعلى