عملية لتقليل حجم الملف القابل للتنفيذ

StackOverflow https://stackoverflow.com/questions/200292

  •  03-07-2019
  •  | 
  •  

سؤال

أقوم بإنتاج ملف سداسي عشري ليتم تشغيله على معالج ARM والذي أريد الاحتفاظ به أقل من 32 كيلو بايت.إنها حاليًا أكبر بكثير من ذلك وأتساءل عما إذا كان لدى شخص ما بعض النصائح حول أفضل طريقة لتقليل حجمها؟

وإليكم ما قمت به حتى الآن

  1. لذلك قمت بتشغيل "الحجم" عليه لتحديد حجم الملف السداسي.
  2. ثم "الحجم" مرة أخرى لمعرفة حجم كل ملف من ملفات الكائنات التي ترتبط بإنشاء الملفات السداسية.يبدو أن غالبية الحجم يأتي من مكتبات خارجية.
  3. ثم استخدمت "readelf" لمعرفة الوظائف التي تستهلك أكبر قدر من الذاكرة.
  4. لقد بحثت في الكود لمعرفة ما إذا كان بإمكاني إلغاء المكالمات إلى هذه الوظائف.

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

إذن ما هي الخطوات التالية؟

الرد على الإجابات:

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

المحلول

القائمة العامة:

  • تأكد من تعطيل خيارات تصحيح أخطاء المترجم والرابط
  • التجميع والربط مع تشغيل كافة خيارات الحجم (-Os في دول مجلس التعاون الخليجي)
  • يجري strip على الملف القابل للتنفيذ
  • قم بإنشاء ملف خريطة وتحقق من أحجام وظيفتك.يمكنك إما الحصول على الرابط الخاص بك لإنشاء ملف الخريطة الخاص بك (-M عند استخدام ld)، أو يمكنك استخدام objdump على الملف القابل للتنفيذ النهائي (لاحظ أن هذا سيعمل فقط على ملف قابل للتنفيذ غير مُجرد!) لن يحل هذا المشكلة فعليًا، ولكنه سيُعلمك بأسوأ المخالفين.
  • يستخدم nm للتحقق من الرموز التي يتم استدعاؤها من كل ملف من ملفات الكائنات الخاصة بك.من المفترض أن يساعد هذا في العثور على الوظائف التي لا تريد الاتصال بها.

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

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

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

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

نصائح أخرى

هناك تحسين آخر قد يوفر عليك العمل وهو -ffunction-sections, -Wl,--gc-sections، على افتراض أنك تستخدم مجلس التعاون الخليجي.ومع ذلك، لن يلزم إخبار سلسلة الأدوات الجيدة بذلك.

توضيح:يربط GNU ld الأقسام، ويصدر مجلس التعاون الخليجي مقطعًا واحدًا لكل وحدة ترجمة ما لم تخبره بخلاف ذلك.لكن في C++، العقد الموجودة في الرسم البياني للتبعية هي كائنات ووظائف.

فقط للتحقق مرة أخرى والتوثيق للرجوع إليه في المستقبل، ولكن هل تستخدم تعليمات Thumb؟إنها إصدارات 16 بت من التعليمات العادية.في بعض الأحيان قد تحتاج إلى تعليماتين بحجم 16 بت، لذلك لن يوفر ذلك 50% من مساحة الكود.

يجب أن يأخذ الرابط اللائق الوظائف المطلوبة فقط.ومع ذلك، قد تحتاج إلى إعدادات المترجم والرابط لحزم الوظائف للربط الفردي.

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

في معظم المشاريع المضمنة بعمق، لا تحتاج إلى "printf()" متعدد الاستخدامات أو تخصيص ذاكرة ديناميكي (تحتوي العديد من وحدات التحكم على ذاكرة وصول عشوائي (RAM) تبلغ 32 كيلو بايت أو أقل).

بدلاً من مجرد استخدام "printf ()" أستخدم "printf ()" مخصصًا بسيطًا جدًا، يمكن لهذه الوظيفة طباعة الأرقام بالتنسيق السداسي العشري أو العشري فقط وليس أكثر.يتم تخصيص معظم بنيات البيانات مسبقًا في وقت الترجمة.

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

يجب أن تكون طريقة أفضل للقيام بذلك بالرغم من ذلك.

لدى Andrew EdgeCombe قائمة رائعة، ولكن إذا كنت تريد حقًا حذف كل بايت أخير، sstrip هي أداة جيدة مفقودة من القائمة ويمكنها تقليل عدد قليل من الكيلوبايتات الإضافية.

على سبيل المثال، عند التشغيل strip بحد ذاتها، يمكن أن يحلق ~ 2 كيلو بايت.

من ملف README القديم (راجع التعليقات الموجودة أعلى ملف هذا ملف مصدر غير مباشر):

sstrip is a small utility that removes the contents at the end of an ELF file that are not part of the program's memory image.

Most ELF executables are built with both a program header table and a section header table. However, only the former is required in order for the OS to load, link and execute a program. sstrip attempts to extract the ELF header, the program header table, and its contents, leaving everything else in the bit bucket. It can only remove parts of the file that occur at the end, after the parts to be saved. However, this almost always includes the section header table, and occasionally a few random sections that are not used when running a program.

لاحظ أنه نظرًا لبعض المعلومات التي يزيلها، فإن الملف القابل للتنفيذ sstrip'd هو يشاع أن لديك مشاكل مع بعض الأدوات.تمت مناقشة هذا الأمر أكثر في تعليقات المصدر.

أيضًا...للحصول على قراءة مسلية/مجنونة حول كيفية جعل أصغر حجم ممكن قابلاً للتنفيذ، هذا المقال يستحق القراءة.

للإجابة على هذه الحاجة المحددة:

•I want to omit those functions (if possible) but I can't find what's calling them!! Could be called from any number of library functions I guess.

إذا كنت تريد تحليل قاعدة التعليمات البرمجية الخاصة بك لمعرفة من الذي يستدعي ماذا، ومن الذي يتم استدعاء وظيفة معينة وأشياء من هذا القبيل، فهناك أداة رائعة تسمى "فهم لغة C" مقدمة من SciTools.

https://scitools.com/

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

أنها توفر تقييمًا لفترة زمنية محدودة، ثم يجب عليك شراء ترخيص.

هل يمكن أن ننظر إلى شيء من هذا القبيل ضغط قابل للتنفيذ.

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