Consulting Services
تدوينات مصغرةلغة سي و متحكمات

أسهل طريقة لحساب حجم تابع في لغة سي

إن حساب حجم تابع function ليس بسهولة استخدام العملية خلال compile-time وقت الترجمة ()sizeof . هناك طرق متعددة لحساب حجم التابع خلال التنفيذ run-time ولكن لكي نبقي الأمور سهلة فمن الأفضل التحقق من حجم التابع من الرابط linker والذي يجب أن تتوفر لديه هذه المعلومة.

 

لنتعرف على الأدوات التي سنستخدمها:

 

1- الملف “map.”المولّد بواسطة GCC/G++ linker:

 

يحتوي هذا الملف على الرموز symbols التي لدينا في الكود/الفيرموير سواءً في الفلاش أو الرام أو أي منطقة ذاكرة معرّفة أخرى. إن الاقتباس التالي هو من ترجمة compiling واحد من الأمثلة الموجودة في nRF52 SDK. إذا كنت تريد التجريب كل ما عليك فعله هو استخدام الأمر make default من المسار التالي examples\peripheral\gpiote\pca10040\blank\armgcc. سنجد في العمود الأول عنوان البدء وفي العمود الثاني الحجم بالنظام الست عشري وفي العمود الثالث اسم الملف الغرض object file الذي يحوي هذا الرمز.

.text.bsp_board_led_invert
                0x00000380       0x24 _build/nrf52832_xxaa/boards.c.o
                0x00000380                bsp_board_led_invert
 .text.bsp_board_init
                0x000003a4       0x5c _build/nrf52832_xxaa/boards.c.o
                0x000003a4                bsp_board_init  

يمكنك البحث في هذا الملف على اسم الرمز حتى نجده، مثلاً نجد أن التابع bsp_board_led_invert بطول 36 بايت.

 

2- الملف “out.”المولّد بواسطة GCC/G++ linker:

 

قد من الصعب أحياناً أن نجد رمز معيّن في الملف “map.” وهنا تأتي الأداة nm الموجودة في GCC tool-chain والتي تعرض جدولاً بجميع الرموز ولأجل هذا الغرض يجب استعمال الملف “out.” أو “elf.”. هذه الأداة بإمكانها عرض الرموز وترتيبها حسب الحجم أيضاً. لدينا الملف “out.” من خرج ترجمة المشروع المشار له سابقاً ولعرض الرموز وأحجامها بالترتيب فإنه يمكننا استخدام التعليمة التالية (انتبه لاستخدام التعليمة بناءً على حالتك، أستخدم ARM GCC في حالتي)

arm-none-eabi-nm -S --size-sort -t d nrf52832_xxaa.out

وهذا اقتباس من الخرج

00001024 00000030 T app_error_handler_bare
00000896 00000036 T bsp_board_led_invert
00003460 00000040 T exit
00000720 00000040 T Reset_Handler
00001056 00000052 W app_error_fault_handler
00000780 00000052 t gpioIntHandler
00000832 00000064 T main
00003500 00000076 T __libc_init_array
536871056 00000076 b m_cb
00000932 00000090 T bsp_board_init
536870916 00000096 d impure_data
00001108 00000136 T nrfx_gpiote_init
00001568 00000196 T nrfx_gpiote_in_event_enable
00002448 00000200 T TIMER0_IRQHandler
00001244 00000324 T nrfx_gpiote_in_init
00000000 00000512 T __isr_vector
00001764 00000684 T GPIOTE_IRQHandler
00002648 00000812 T SystemInit
536871144 00008192 N __HeapBase

في العمود الأول العنوان بشكل عشري وثم الحجم أيضاً بشكل عشري وثم اسم الرمز.

 

أسماء للرموز غريبة؟

 

لو وجدت أسماء غريبة للرموز وهي غالباً مجموعة من المحارف التي تسبق وتلي اسم الرمز المعروف لديك فهذا ما يسمى بـ mangling  على سبيل المثال إن تابع مثل get_event سيصبح كالتالي:

__ZN2os9get_eventENS_17enum_task_id_typeE

لماذا؟ هذا لأن المترجم يحتاج لأن تكون أسماء التوابع والمتغيرات فريدة خاصة عندما نستعمل المتحولات والتوابع الـstatic والتي قد تستخدم نفس الاسم ولكن بتوابع مختلفة أو ملفات مختلفة فعلى المترجم أن يميّز بينها. ونفس الفكرة تنطبق على الـ overloading في ++C كذلك.

لاستعادة الاسم الاصلي de-mangle تستخدم الأداة c++filt

arm-none-eabi-c++filt __ZN2os9get_eventENS_17enum_task_id_typeE

Yahya Tawil

مؤسس عتاديات وأسعى لدعم المحتوى العربي عن النظم المضمنة في الويب العربي. خبرتي في مجال النظم المضمّنة تتركز في كتابة البرامج المضمنة وتصميم الدارات المطبوعة والمخططات وإنشاء المحتوى.

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *

هذا الموقع يستخدم Akismet للحدّ من التعليقات المزعجة والغير مرغوبة. تعرّف على كيفية معالجة بيانات تعليقك.

زر الذهاب إلى الأعلى