اذهب إلى المحتوى

تطبيق عملي لبناء برنامج تنفيذي من شيفرة مصدرية بلغة C


Ola Abbas

تعرّفنا في المقال السابق من سلسلة مدخل لعلم الحاسوب على الخطوات الثلاث لبناء ملف قابل للتنفيذ هي: التصريف Compiling والتجميع Assembling والربط Linking، وسنطبّق في هذا المقال هذه الخطوات عمليًا لبناء ملف قابل للتنفيذ.

تابع فيما الخطوات التي جرى اتخاذها لبناء تطبيق بسيط خطوة بخطوة. لاحظ أن الأمر gcc يشغّل برنامجَ تشغيلٍ driver program يخفي معظم الخطوات عنك، وهذا هو ما تريده بالضبط في ظل الظروف العادية، لأن الأوامر والخيارات الدقيقة للحصول على ملف قابلٍ للتنفيذ على نظام حقيقي يمكن أن تكون معقدة للغاية وخاصةً بكل معمارية على حدة.

سنشرح عملية التصريف في المثالين التاليين، حيث سنستخدم ملفين مصدريين مكتوبين بلغة C، إذ يعرّف أحدهما الدالة الرئيسية main()‎ التي تُعَد نقطة الدخول الأولية، ويصرّح الملف الآخر عن دالة مساعدة، وهناك متغير عام واحد.

إليك مثال مرحبًا بالعالم Hello World:

#include <stdio.h>

‫/* نحتاج نموذجًا أوليًا ليعرف المصرّف نوع الدالة‫ function()‎ */
int function(char *input);

‫/* ‫بما أن هذا المتغير ساكن static، فيمكننا تعريفه في كلٍّ من الملفين hello.c وfunction.c */
static int i = 100;

/* هذا متغير عام */
int global = 10;

int main(void)
{
  ‫/* ‫يجب أن تعيد الدالة function()‎ قيمة المتغير العام global */
  int ret = function("Hello, World!");
  exit(ret);
}

إليك مثال على دالة:

#include <stdio.h>

static int i = 100;

/* مُصرّح عنه بأنه خارجي‫ extern لأنه مُعرَّف في الملف hello.c */
extern int global;

int function(char *input)
{
  printf("%s\n", input);
  return global;
}

التصريف Compiling

لكل المصرِّفات خيارٌ لتنفيذ الخطوة الأولى من التصريف فقط مثل استخدام الراية ‎-S لوضع الخرج في ملف يحمل اسم ملف الدخل نفسه ولكن مع اللاحقة ‎.s، وبالتالي يمكننا عرض الخطوة الأولى باستخدام الأمر gcc -S كما هو موضح في المثال التالي:

$ gcc -S hello.c
$ gcc -S function.c
$ cat function.s
  .file   "function.c"
  .pred.safe_across_calls p1-p5,p16-p63
  .section        .sdata,"aw",@progbits
  .align 4
  .type   i#, @object
  .size   i#, 4
i:
  data4   100
  .section        .rodata
  .align 8
.LC0:
  stringz "%s\n"
  .text
  .align 16
  .global function#
  .proc function#
function:
  .prologue 14, 33
  .save ar.pfs, r34
  alloc r34 = ar.pfs, 1, 4, 2, 0
  .vframe r35
  mov r35 = r12
  adds r12 = -16, r12
  mov r36 = r1
  .save rp, r33
  mov r33 = b0
  .body
  ;;
  st8 [r35] = r32
  addl r14 = @ltoffx(.LC0), r1
  ;;
  ld8.mov r37 = [r14], .LC0
  ld8 r38 = [r35]
  br.call.sptk.many b0 = printf#
  mov r1 = r36
  ;;
  addl r15 = @ltoffx(global#), r1
  ;;
  ld8.mov r14 = [r15], global#
  ;;
  ld4 r14 = [r14]
  ;;
  mov r8 = r14
  mov ar.pfs = r34
  mov b0 = r33
  .restore sp
  mov r12 = r35
  br.ret.sptk.many b0
  ;;
  .endp function#
  .ident  "GCC: (GNU) 3.3.5 (Debian 1:3.3.5-11)"

تُعَد عملية التجميع Assembly معقدة قليلًا، ولكن يجب أن تكون قادرًا على معرفة مكان تعريف المتغير i بوصفه data4 أي 4 بايتات أو 32 بتًا بحجم النوع int، ومكان تعريف الدالة function (بالشكل function:‎) واستدعاء الدالة printf()‎.

أصبح لدينا الآن ملفا تجميع جاهزين لتجميعهما في شيفرة الآلة البرمجية machine code.

التجميع Assembly

التجميع هو عملية مباشرة إلى حد ما، ويُطلَق على المجمّع as ويأخذ وسائطًا بطريقة مماثلة للأمر gcc.

إليك مثال عن التجميع:

$ as -o function.o function.s
$ as -o hello.o hello.s
$ ls
function.c  function.o  function.s  hello.c  hello.o  hello.s

تنتج عن عملية التجميع التعليمات المُصرَّفة Object Code، حيث تكون هذه الشيفرة جاهزةً لربطها مع بعضها البعض في الملف النهائي القابل للتنفيذ. يمكنك تخطي الاضطرار إلى استخدام المُجمِّع يدويًا من خلال استدعاء المصرِّف مع الراية ‎-c التي تحوّل ملف الدخل مباشرةً إلى شيفرة كائن، وتضعها في ملف له البادئة نفسها ولكن مع اللاحقة ‎.o.

لا يمكننا فحص شيفرة التعليمات المُصرَّفة مباشرةً لأنها في صيغة ثنائية، ولكن يمكننا استخدام بعض الأدوات لفحص ملفات التعليمات المُصرَّفة مثل الأداة readelf --symbols التي ستعرض الرموز الموجودة في ملف الكائن كما يلي:

$ readelf --symbols ./hello.o

Symbol table '.symtab' contains 15 entries:
  Num:    Value          Size Type    Bind   Vis      Ndx Name
    0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
    1: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS hello.c
    2: 0000000000000000     0 SECTION LOCAL  DEFAULT    1
    3: 0000000000000000     0 SECTION LOCAL  DEFAULT    3
    4: 0000000000000000     0 SECTION LOCAL  DEFAULT    4
    5: 0000000000000000     0 SECTION LOCAL  DEFAULT    5
    6: 0000000000000000     4 OBJECT  LOCAL  DEFAULT    5 i
    7: 0000000000000000     0 SECTION LOCAL  DEFAULT    6
    8: 0000000000000000     0 SECTION LOCAL  DEFAULT    7
    9: 0000000000000000     0 SECTION LOCAL  DEFAULT    8
   10: 0000000000000000     0 SECTION LOCAL  DEFAULT   10
   11: 0000000000000004     4 OBJECT  GLOBAL DEFAULT    5 global
   12: 0000000000000000    96 FUNC    GLOBAL DEFAULT    1 main
   13: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND function
   14: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND exit

$ readelf --symbols ./function.o

Symbol table '.symtab' contains 14 entries:
  Num:    Value          Size Type    Bind   Vis      Ndx Name
    0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
    1: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS function.c
    2: 0000000000000000     0 SECTION LOCAL  DEFAULT    1
    3: 0000000000000000     0 SECTION LOCAL  DEFAULT    3
    4: 0000000000000000     0 SECTION LOCAL  DEFAULT    4
    5: 0000000000000000     0 SECTION LOCAL  DEFAULT    5
    6: 0000000000000000     4 OBJECT  LOCAL  DEFAULT    5 i
    7: 0000000000000000     0 SECTION LOCAL  DEFAULT    6
    8: 0000000000000000     0 SECTION LOCAL  DEFAULT    7
    9: 0000000000000000     0 SECTION LOCAL  DEFAULT    8
   10: 0000000000000000     0 SECTION LOCAL  DEFAULT   10
   11: 0000000000000000   128 FUNC    GLOBAL DEFAULT    1 function
   12: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND printf
   13: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND global

يُعَد هذا الخرج معقدًا للغاية، ولكن يجب أن تكون قادرًا على فهم الكثير منه مثل:

  • لاحظ الرمز الذي يحمل الاسم i في الخرج hello.o، حيث يُسبَق هذا الرمز بالكلمة LOCAL أي أنه محلي، لأننا صرّحنا عنه بأنه ساكن static، وبالتالي يُميَّز على أنه محلي لملف الكائن.
  • لاحظ المتغير global في الخرج نفسه المُعرَّف على أنه متغير عام GLOBAL، مما يعني أنه مرئي خارج هذا الملف، وتكون الدالة الرئيسية main()‎ مرئية من خارج الملف.
  • لاحظ أن الرمز function له النوع UND أو غير مُعرَّف Undefined من أجل استدعاء الدالة function()‎، أي أن الأمر متروك للرابط Linker للعثور على عنوان الدالة.
  • لاحظ الرموز الموجودة في الملف function.c وكيفية ملاءمتها مع الخرج.

الربط Linking

يُعَد استدعاء الرابط المُسمَّى ld عمليةً معقدة للغاية على نظام حقيقي، لذلك نترك عملية الربط للأمر gcc، ولكن يمكننا التعرّف على ما يفعله داخليًا باستخدام الراية ‎-v التي ترمز إلى Verbose أي مُفصَّلة.

إليك مثال عن عملية الربط:

/usr/lib/gcc-lib/ia64-linux/3.3.5/collect2 -static 
/usr/lib/gcc-lib/ia64-linux/3.3.5/../../../crt1.o 
/usr/lib/gcc-lib/ia64-linux/3.3.5/../../../crti.o 
/usr/lib/gcc-lib/ia64-linux/3.3.5/crtbegin.o 
-L/usr/lib/gcc-lib/ia64-linux/3.3.5 
-L/usr/lib/gcc-lib/ia64-linux/3.3.5/../../.. 
hello.o 
function.o 
--start-group 
-lgcc 
-lgcc_eh 
-lunwind 
-lc 
--end-group 
/usr/lib/gcc-lib/ia64-linux/3.3.5/crtend.o 
/usr/lib/gcc-lib/ia64-linux/3.3.5/../../../crtn.o

أول شيء تلاحظه هو استدعاء برنامج بالاسم collect2 وهو عبارة عن مُغلِّف للرابط ld، ويستخدم الأمر gcc داخليًا. الشيء الآخر الذي ستلاحظه هو ملفات الكائنات التي تبدأ بالرمز crt أي أنها مُحدَّدة للرابط. يُوفّر الأمر gcc ومكتبات النظام هذه الدوال التي تحتوي على الشيفرة البرمجية المطلوبة لبدء البرنامج. لا تُعَد الدالة الرئيسية main()‎ أول دالة مُستدعاة عند تشغيل البرنامج، بل تُستدعَى أولًا الدالة ‎_start الموجودة في ملفات الكائنات crt، حيث تضبط هذه الدالة بعض الإعدادات العامة التي لا يجب أن يقلق مبرمجو التطبيقات بشأنها.

يُعَد تسلسل المسار الهرمي معقدًا للغاية، ولكن يمكننا أن نرى أن الخطوة الأخيرة هي ربط بعض ملفات الكائنات الإضافية وهي:

  • crt1.o: توفره مكتبات النظام libc، ويحتوي على الدالة ‎_start التي تُعَد أول شيء يُستدعَى في البرنامج.
  • crti.o: توفّره مكتبات النظام.
  • crtbegin.o
  • crtsaveres.o
  • crtend.o
  • crtn.o

يمكنك أن ترى بعد ذلك أننا نربط ملفي الكائنات hello.o وfunction.o، ثم نحدّد بعض المكتبات الإضافية باستخدام رايات ‎-l، حيث تُعَد هذه المكتبات خاصةً بالنظام ومطلوبة لكل برنامج. الراية الرئيسية هي الراية ‎-lc التي تجلب مكتبة C التي تحتوي على جميع الدوال المشتركة مثل الدالة printf()‎. نربط بعد ذلك مرة أخرى بعض ملفات كائنات النظام التي تطبّق بعض عمليات التنظيف بعد انتهاء البرامج. تُعَد هذه التفاصيل معقدة، إلا أن مفهومها واضح ومباشر.

سنربط بعد ذلك جميع ملفات التعليمات المُصرَّفة مع بعضها البعض في ملف واحد قابل للتنفيذ وجاهز للتشغيل.

الملف القابل للتنفيذ Executable

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

إليك مثال عن ملف قابل للتنفيذ:

ianw@lime:~/programs/csbu/wk7/code$ gcc -o program hello.c function.c
ianw@lime:~/programs/csbu/wk7/code$ readelf --symbols ./program

Symbol table '.dynsym' contains 11 entries:
  Num:    Value          Size Type    Bind   Vis      Ndx Name
    0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
    1: 6000000000000de0     0 OBJECT  GLOBAL DEFAULT  ABS _DYNAMIC
    2: 0000000000000000   176 FUNC    GLOBAL DEFAULT  UND printf@GLIBC_2.2 (2)
    3: 600000000000109c     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_start
    4: 0000000000000000   704 FUNC    GLOBAL DEFAULT  UND exit@GLIBC_2.2 (2)
    5: 600000000000109c     0 NOTYPE  GLOBAL DEFAULT  ABS _edata
    6: 6000000000000fe8     0 OBJECT  GLOBAL DEFAULT  ABS _GLOBAL_OFFSET_TABLE_     7: 60000000000010b0     0 NOTYPE  GLOBAL DEFAULT  ABS _end
    8: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _Jv_RegisterClasses
    9: 0000000000000000   544 FUNC    GLOBAL DEFAULT  UND __libc_start_main@GLIBC_2.2 (2)
   10: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__

Symbol table '.symtab' contains 127 entries:
  Num:    Value          Size Type    Bind   Vis      Ndx Name
    0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
    1: 40000000000001c8     0 SECTION LOCAL  DEFAULT    1
    2: 40000000000001e0     0 SECTION LOCAL  DEFAULT    2
    3: 4000000000000200     0 SECTION LOCAL  DEFAULT    3
    4: 4000000000000240     0 SECTION LOCAL  DEFAULT    4
    5: 4000000000000348     0 SECTION LOCAL  DEFAULT    5
    6: 40000000000003d8     0 SECTION LOCAL  DEFAULT    6
    7: 40000000000003f0     0 SECTION LOCAL  DEFAULT    7
    8: 4000000000000410     0 SECTION LOCAL  DEFAULT    8
    9: 4000000000000440     0 SECTION LOCAL  DEFAULT    9
    10: 40000000000004a0     0 SECTION LOCAL  DEFAULT   10
    11: 40000000000004e0     0 SECTION LOCAL  DEFAULT   11
    12: 40000000000005e0     0 SECTION LOCAL  DEFAULT   12
    13: 4000000000000b00     0 SECTION LOCAL  DEFAULT   13
    14: 4000000000000b40     0 SECTION LOCAL  DEFAULT   14
    15: 4000000000000b60     0 SECTION LOCAL  DEFAULT   15
    16: 4000000000000bd0     0 SECTION LOCAL  DEFAULT   16
    17: 4000000000000ce0     0 SECTION LOCAL  DEFAULT   17
    18: 6000000000000db8     0 SECTION LOCAL  DEFAULT   18
    19: 6000000000000dd0     0 SECTION LOCAL  DEFAULT   19
    20: 6000000000000dd8     0 SECTION LOCAL  DEFAULT   20
    21: 6000000000000de0     0 SECTION LOCAL  DEFAULT   21
    22: 6000000000000fc0     0 SECTION LOCAL  DEFAULT   22
    23: 6000000000000fd0     0 SECTION LOCAL  DEFAULT   23
    24: 6000000000000fe0     0 SECTION LOCAL  DEFAULT   24
    25: 6000000000000fe8     0 SECTION LOCAL  DEFAULT   25
    26: 6000000000001040     0 SECTION LOCAL  DEFAULT   26
    27: 6000000000001080     0 SECTION LOCAL  DEFAULT   27
    28: 60000000000010a0     0 SECTION LOCAL  DEFAULT   28
    29: 60000000000010a8     0 SECTION LOCAL  DEFAULT   29
    30: 0000000000000000     0 SECTION LOCAL  DEFAULT   30
    31: 0000000000000000     0 SECTION LOCAL  DEFAULT   31
    32: 0000000000000000     0 SECTION LOCAL  DEFAULT   32
    33: 0000000000000000     0 SECTION LOCAL  DEFAULT   33
    34: 0000000000000000     0 SECTION LOCAL  DEFAULT   34
    35: 0000000000000000     0 SECTION LOCAL  DEFAULT   35
    36: 0000000000000000     0 SECTION LOCAL  DEFAULT   36
    37: 0000000000000000     0 SECTION LOCAL  DEFAULT   37
    38: 0000000000000000     0 SECTION LOCAL  DEFAULT   38
    39: 0000000000000000     0 SECTION LOCAL  DEFAULT   39
    40: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS /build/buildd/glibc-2.3.2
    41: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS /build/buildd/glibc-2.3.2
    42: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS /build/buildd/glibc-2.3.2
    43: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS /build/buildd/glibc-2.3.2
    44: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS /build/buildd/glibc-2.3.2
    45: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS /build/buildd/glibc-2.3.2
    46: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS <command line>
    47: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS /build/buildd/glibc-2.3.2
    48: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS <command line>
    49: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS <built-in>
    50: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS abi-note.S
    51: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS /build/buildd/glibc-2.3.2
    52: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS abi-note.S
    53: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS /build/buildd/glibc-2.3.2
    54: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS abi-note.S
    55: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS <command line>
    56: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS /build/buildd/glibc-2.3.2
    57: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS <command line>
    58: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS <built-in>
    59: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS abi-note.S
    60: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS init.c
    61: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS /build/buildd/glibc-2.3.2
    62: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS /build/buildd/glibc-2.3.2
    63: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS initfini.c
    64: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS /build/buildd/glibc-2.3.2
    65: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS <command line>
    66: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS /build/buildd/glibc-2.3.2
    67: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS <command line>
    68: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS <built-in>
    69: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS /build/buildd/glibc-2.3.2
    70: 4000000000000670   128 FUNC    LOCAL  DEFAULT   12 gmon_initializer
    71: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS /build/buildd/glibc-2.3.2
    72: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS /build/buildd/glibc-2.3.2
    73: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS initfini.c
    74: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS /build/buildd/glibc-2.3.2
    75: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS <command line>
    76: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS /build/buildd/glibc-2.3.2
    77: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS <command line>
    78: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS <built-in>
    79: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS /build/buildd/glibc-2.3.2
    80: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS auto-host.h
    81: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS <command line>
    82: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS <built-in>
    83: 6000000000000fc0     0 NOTYPE  LOCAL  DEFAULT   22 __CTOR_LIST__
    84: 6000000000000fd0     0 NOTYPE  LOCAL  DEFAULT   23 __DTOR_LIST__
    85: 6000000000000fe0     0 NOTYPE  LOCAL  DEFAULT   24 __JCR_LIST__
    86: 6000000000001088     8 OBJECT  LOCAL  DEFAULT   27 dtor_ptr
    87: 40000000000006f0   128 FUNC    LOCAL  DEFAULT   12 __do_global_dtors_aux    
    88: 4000000000000770   128 FUNC    LOCAL  DEFAULT   12 __do_jv_register_classes
    89: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS hello.c
    90: 6000000000001090     4 OBJECT  LOCAL  DEFAULT   27 i
    91: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS function.c
    92: 6000000000001098     4 OBJECT  LOCAL  DEFAULT   27 i
    93: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS auto-host.h
    94: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS <command line>
    95: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS <built-in>
    96: 6000000000000fc8     0 NOTYPE  LOCAL  DEFAULT   22 __CTOR_END__
    97: 6000000000000fd8     0 NOTYPE  LOCAL  DEFAULT   23 __DTOR_END__
    98: 6000000000000fe0     0 NOTYPE  LOCAL  DEFAULT   24 __JCR_END__
    99: 6000000000000de0     0 OBJECT  GLOBAL DEFAULT  ABS _DYNAMIC
    100: 4000000000000a70   144 FUNC    GLOBAL HIDDEN   12 __do_global_ctors_aux
    101: 6000000000000dd8     0 NOTYPE  GLOBAL DEFAULT  ABS __fini_array_end
    102: 60000000000010a8     8 OBJECT  GLOBAL HIDDEN   29 __dso_handle
    103: 40000000000009a0   208 FUNC    GLOBAL DEFAULT   12 __libc_csu_fini
    104: 0000000000000000   176 FUNC    GLOBAL DEFAULT  UND printf@@GLIBC_2.2
    105: 40000000000004a0    32 FUNC    GLOBAL DEFAULT   10 _init
    106: 4000000000000850   128 FUNC    GLOBAL DEFAULT   12 function
    107: 40000000000005e0   144 FUNC    GLOBAL DEFAULT   12 _start
    108: 6000000000001094     4 OBJECT  GLOBAL DEFAULT   27 global
    109: 6000000000000dd0     0 NOTYPE  GLOBAL DEFAULT  ABS __fini_array_start
    110: 40000000000008d0   208 FUNC    GLOBAL DEFAULT   12 __libc_csu_init
    111: 600000000000109c     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_start
    112: 40000000000007f0    96 FUNC    GLOBAL DEFAULT   12 main
    113: 6000000000000dd0     0 NOTYPE  GLOBAL DEFAULT  ABS __init_array_end
    114: 6000000000000dd8     0 NOTYPE  WEAK   DEFAULT   20 data_start
    115: 4000000000000b00    32 FUNC    GLOBAL DEFAULT   13 _fini
    116: 0000000000000000   704 FUNC    GLOBAL DEFAULT  UND exit@@GLIBC_2.2
    117: 600000000000109c     0 NOTYPE  GLOBAL DEFAULT  ABS _edata
    118: 6000000000000fe8     0 OBJECT  GLOBAL DEFAULT  ABS _GLOBAL_OFFSET_TABLE_   
    119: 60000000000010b0     0 NOTYPE  GLOBAL DEFAULT  ABS _end
    120: 6000000000000db8     0 NOTYPE  GLOBAL DEFAULT  ABS __init_array_start
    121: 6000000000001080     4 OBJECT  GLOBAL DEFAULT   27 _IO_stdin_used
    122: 60000000000010a0     8 OBJECT  GLOBAL DEFAULT   28 __libc_ia64_register_back
    123: 6000000000000dd8     0 NOTYPE  GLOBAL DEFAULT   20 __data_start
    124: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _Jv_RegisterClasses
    125: 0000000000000000   544 FUNC    GLOBAL DEFAULT  UND __libc_start_main@@GLIBC_
    126: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__

إليك بعض الأشياء التي يجب ملاحظتها:

  • لاحظ طريقة بناء الملف القابل للتنفيذ السهلة.
  • لاحظ وجود نوعين من جداول الرموز هما: dynsym وsymtab. سنشرح كيفية عمل رموز dynsym لاحقًا، ولكن لاحظ أن بعضها يحمل الرمز @.
  • لاحظ الرموز العديدة المُضمَّنة من ملفات الكائنات الإضافية، حيث يبدأ الكثير منها بالرمز __ لتجنب التعارض مع الأسماء التي يختارها المبرمج. اقرأ واختر الرموز التي ذكرناها سابقًا من ملفات الكائنات واكتشف إن تغيرت بأيّ شكل من الأشكال.

ترجمة -وبتصرُّف- للقسم A practical example من فصل The Toolchain من كتاب Computer Science from the Bottom Up لصاحبه Ian Wienand.

اقرأ أيضًا


تفاعل الأعضاء

أفضل التعليقات

لا توجد أية تعليقات بعد



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...