سؤال

غالبًا ما أسمع المصطلحات "مرتبطة بشكل ثابت" و "مرتبط ديناميكيًا" ، وغالبًا ما تكون في إشارة إلى الكود المكتوب في ج, C ++ أو ج#. ما هم ، ما الذي يتحدثون عنه بالضبط ، وماذا يربطون؟

هل كانت مفيدة؟

المحلول

هناك (في معظم الحالات ، الرمز المفسر للخصم) مرحلتين في الحصول على رمز المصدر (ما تكتبه) إلى التعليمات البرمجية القابلة للتنفيذ (ما تقوم بتشغيله).

الأول هو التجميع الذي يحول رمز المصدر إلى وحدات كائن.

والثاني ، الارتباط ، هو ما يجمع بين وحدات الكائن معًا لتشكيل قابلة للتنفيذ.

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

عندما انت ثابتة ربط ملف إلى قابلة للتنفيذ ، يتم تضمين محتويات هذا الملف في وقت الرابط. بمعنى آخر ، يتم إدراج محتويات الملف فعليًا في القابل للتنفيذ الذي سيتم تشغيله.

عندما تربط ديناميكيا, ، يتم تضمين مؤشر إلى الملف الذي يتم ربطه في (اسم ملف الملف ، على سبيل المثال) في القابلة للتنفيذ ولا يتم تضمين محتويات الملف المذكور في وقت الرابط. إنه فقط عندما تكون لاحقًا يجري القابلة للتنفيذ التي يتم شراؤها هذه الملفات المرتبطة ديناميكيًا ولا يتم شراؤها إلا في نسخة في الذاكرة من القابل للتنفيذ ، وليس على القرص.

إنها في الأساس طريقة لربط مؤجل. هناك متساو أكثر الطريقة المؤجلة (تسمى الربط المتأخر على بعض الأنظمة) التي لن تجلب الملف المرتبط ديناميكيًا حتى تحاول بالفعل استدعاء وظيفة داخلها.

يتم "قفل" الملفات المرتبطة بشكل ثابت في وقت الرابط حتى لا تتغير أبدًا. يمكن أن يتغير الملف المرتبط ديناميكيًا المشار إليه بواسطة تنفيذ فقط عن طريق استبدال الملف على القرص.

هذا يسمح للتحديثات بالوظائف دون الحاجة إلى إعادة ربط الرمز ؛ يحمل اللودر روابط في كل مرة تقوم فيها بتشغيله.

هذا جيد وسيء - من ناحية ، يسمح بتحديثات أسهل وإصلاحات الأخطاء ، من ناحية أخرى ، يمكن أن يؤدي إلى توقف برامج العمل إذا كانت التحديثات غير متوافقة - وهذا مسؤول أحيانًا عن "DLL Hell" اللعين أذكر في أن التطبيقات يمكن كسرها إذا استبدلت مكتبة مرتبطة ديناميكيًا بمكتبة غير متوافقة (يجب أن يتوقع المطورون الذين يقومون بذلك أن يتم مطاردتهم ومعاقبتهم بشدة ، بالمناسبة).


ك مثال, ، دعونا نلقي نظرة على حالة المستخدم الذي يقوم بتجميعه main.c ملف لربط ثابت وديناميكي.

Phase     Static                    Dynamic
--------  ----------------------    ------------------------
          +---------+               +---------+
          | main.c  |               | main.c  |
          +---------+               +---------+
Compile........|.........................|...................
          +---------+ +---------+   +---------+ +--------+
          | main.o  | | crtlib  |   | main.o  | | crtimp |
          +---------+ +---------+   +---------+ +--------+
Link...........|..........|..............|...........|.......
               |          |              +-----------+
               |          |              |
          +---------+     |         +---------+ +--------+
          |  main   |-----+         |  main   | | crtdll |
          +---------+               +---------+ +--------+
Load/Run.......|.........................|..........|........
          +---------+               +---------+     |
          | main in |               | main in |-----+
          | memory  |               | memory  |
          +---------+               +---------+

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

في الحالة الديناميكية ، يرتبط البرنامج الرئيسي بمكتبة استيراد وقت التشغيل C (شيء يعلن ما هو موجود في المكتبة الديناميكية ولكنه ليس في الواقع حدد هو - هي). هذا يسمح للرابط بالارتباط على الرغم من أن الكود الفعلي مفقود.

بعد ذلك ، في وقت التشغيل ، يقوم محمل نظام التشغيل بربط في وقت متأخر من البرنامج الرئيسي باستخدام C Runtime DLL (مكتبة الارتباط الديناميكي أو المكتبة المشتركة أو غيرها من التسمية).

يمكن لمالك وقت التشغيل C الانخفاض في DLL جديد في أي وقت لتوفير التحديثات أو إصلاحات الأخطاء. كما ذُكر سابقًا ، فإن هذا له مزايا وعيوب.

نصائح أخرى

أعتقد أن إجابة جيدة على هذا السؤال يجب أن تشرح ما يربطه هو.

عند تجميع بعض رمز C (على سبيل المثال) ، يتم ترجمته إلى لغة الجهاز. مجرد سلسلة من البايتات التي ، عند تشغيلها ، تتسبب في إضافة المعالج ، وطرحه ، ومقارنة ، "goto" ، وقراءة الذاكرة ، وكتابة الذاكرة ، هذا النوع من الأشياء. يتم تخزين هذه الأشياء في ملفات الكائن (.O).

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

الآن في الأيام الأولى ، سيتعين على المبرمجين أن يثقبوا عنوان الذاكرة الذي توجد به هذه الروتين الفرعي. شيء مثل CALL 0x5A62. كان هذا مملاً ومشاكلًا في حالة حاجة إلى تغيير عناوين الذاكرة هذه.

لذلك ، كانت العملية آلية. تكتب برنامجًا يتصل printf(), ، والمترجم لا يعرف عنوان ذاكرة printf. لذلك يكتب المترجم فقط CALL 0x0000, ويضيف ملاحظة إلى ملف الكائن تقول "يجب استبدال هذا 0x0000 بموقع ذاكرة printf".

الربط الثابت يعني أن برنامج Linker (يسمى GNU واحد LD) يضيف printfرمز الجهاز مباشرة إلى ملفك القابل للتنفيذ ، ويغير 0x0000 إلى عنوان printf. يحدث هذا عند إنشاء قابلة للتنفيذ.

الربط الديناميكي يعني أن الخطوة أعلاه لا تحدث. الملف القابل للتنفيذ ساكن لديه ملاحظة تقول "يجب استبدال 0x000 بموقع ذاكرة printf". يحتاج محمل نظام التشغيل إلى العثور على رمز printf ، وتحميله في الذاكرة ، وتصحيح عنوان المكالمة ، في كل مرة يتم تشغيل البرنامج.

من الشائع للبرامج أن تسمي بعض الوظائف التي سيتم ربطها بشكل ثابت (وظائف المكتبة القياسية مثل printf عادة ما تكون مرتبطة بشكل ثابت) وغيرها من الوظائف المرتبطة ديناميكيا. تنضم "تلك" الثابتة إلى "القابلة للتنفيذ والديناميكية" "عندما يتم تشغيل القابلة للتنفيذ.

هناك مزايا وعيوب لكلا الطريقتين ، وهناك اختلافات بين أنظمة التشغيل. لكن بما أنك لم تسأل ، فسوف أنهي هذا هنا.

ترتبط المكتبات المرتبطة بشكل ثابت في وقت الترجمة. يتم تحميل المكتبات المرتبطة ديناميكيا في وقت التشغيل. يربط الثابتة المكتبة بتة قابلة للتنفيذ. ربط الديناميكي فقط الخبز في إشارة إلى المكتبة ؛ توجد أجزاء للمكتبة الديناميكية في مكان آخر ويمكن تبديلها لاحقًا.

لأن أيا من المشاركات أعلاه في الواقع تظهر كيف لربط شيء ثابت بشكل ثابت وترى أنك فعلت ذلك بشكل صحيح حتى أتناول هذه المشكلة:

برنامج C بسيط

#include <stdio.h>

int main(void)
{
    printf("This is a string\n");
    return 0;
}

ارتباط برنامج C بشكل ديناميكي

gcc simpleprog.c -o simpleprog

و اهرب file على الثنائي:

file simpleprog 

وهذا سيظهر أنه مرتبط ديناميكيًا على غرار:

"SimpleProg: ELF 64 بت LSB قابلة للتنفيذ ، x86-64 ، الإصدار 1 (SYSV) ، مرتبط ديناميكيًا (يستخدم libs المشتركة) ، لـ GNU/Linux 2.6.26 ، BuildId [SHA1] = 0xF71557261A8B04F686809D90D1C0C65C6028F0F ، لا struction"

بدلاً من ذلك ، دعونا نربط البرنامج بشكل ثابت هذه المرة:

gcc simpleprog.c -static -o simpleprog

سيتم تشغيل الملف على هذا الثنائي المرتبط بشكل ثابت:

file simpleprog 

"SimpleProg: ELF 64-bit LSB قابلة للتنفيذ ، x86-64 ، الإصدار 1 (GNU/Linux) ، مرتبطًا بشكل ثابت ، لـ GNU/Linux 2.6.26 ، BuildId [SHA1] = 0x8C0B12250801C5A7C7434647B7DC65A644D6132B ، لا struction"

ويمكنك أن ترى أنها مرتبطة بسعادة. للأسف ، ليس كل المكتبات سهلة الارتباط بشكل ثابت بهذه الطريقة وقد تتطلب جهد موسع باستخدام libtool أو ربط رمز الكائن ومكتبات C باليد.

لحسن الحظ ، مثل العديد من مكتبات C المدمجة musl تقدم خيارات ربط ثابتة للجميع تقريبًا إن لم يكن كلها من مكتباتهم.

حاليا strace الثنائي الذي أنشأته ويمكنك أن ترى أنه لا توجد مكتبات يمكن الوصول إليها قبل بدء البرنامج:

strace ./simpleprog

قارن الآن مع إخراج strace في البرنامج المرتبط ديناميكيًا وسترى أن Strace النسخة المرتبطة بشكل ثابت أقصر بكثير!

(لا أعرف C# ولكن من المثير للاهتمام أن يكون لديك مفهوم ربط ثابت للغة VM)

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

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

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top