تعرّفنا في المقال السابق من سلسلة مدخل لعلم الحاسوب على الخطوات الثلاث لبناء ملف قابل للتنفيذ هي: التصريف 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.
اقرأ أيضًا
- المقال التالي: الملفات القابلة للتنفيذ في نظام التشغيل وتمثيلها باستخدام الصيغة ELF
- المقال السابق: كيفية إنشاء ملف قابل للتنفيذ Executable File من شيفرة برمجية مصدرية Source Code
- كيفية تصريف وبناء البرامج المكتوبة بلغة Cpp
- أنظمة التصريف المستخدمة لبناء البرامج المكتوبة بلغة Cpp وأهم أخطاء عملية البناء
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.