Yusefnejad

یوسف نژاد

Yusefnejad

یوسف نژاد

تو مطلب «ساخت اسمبلی های مدیریت شده» نحوه تولید یه اسمبلی شرح داده شد. برای این فرایند یه مثالی هم آورده شد که درنهایت فایل اجرایی program.exe برای اون تولید شد. خوب حالا ممکنه این سوال پیش بیاد که این فایل تولید شده دقیقا چیه و از چه قسمتهایی تشکیل شده؟ تو این مطلب سعی شده تا به این سوالات پاسخ داده بشه.

فایل یه اسمبلی مدیریت شده همونطور که تو قسمت اول سری مطالب CLR به زبان ساده توضیح داده شد، از 4 قسمت اصلی تشکیل شده:

1- هدر (+)PE32

2- هدر CLR

3- متادیتا

4- IL

هدر PE32 (برای سیستم های 32 بیتی) یا +PE32 (برای سیستم های 64 بیتی) شامل اطلاعات استانداردیه که سیستم عامل ویندوز به اونا برای اجرای یه فایل اجرایی احتیاج داره. (اطلاعات بیشتر درباره فایلهای PE: ! و ! و !)

هدر CLR بلوک کوچیکی از داده های موردنیاز برای اجرای یه فایل تو محیط CLR هست. این هدر از قسمتهای زیر تشکیل شده:

- نسخه های Major و Minor (یعنی نسخه دقیق) CLRای که ماژول مربوطه برای اون ساخته شده.

- چندتا فلگ برای اعمال برخی تنظیمات خاص.

- یه توکن با نام MethodDef که نقطه آغازین و ورودی برنامه (همون متد Main) رو معرفی میکنه، درصورتیکه ماژول یه فایل اجرایی باشه.

- یه امضای دیجیتالی درصورتیکه به اسمبلی یه نام قوی داده شده باشه.

- و درنهایت اندازه و آدرس جداول متادیتای ماژول.

(یه مطلب خلاصه و مفید درباره اجزای مختلف اسمبلی های مدیریت شده)

متادیتای یه اسمبلی، بلوکی از داده های باینریه که شامل چند تا جدول مجزا از هم میشه. در مجموع سه دسته جدول تو این بلوک داده وجود داره:

- جداول تعریف (definition tables)

- جداول منبع (reference tables)

- جداول مانیفست (manifest tables)

در ادامه اطلاعات مربوط به «جداول تعریف» رایج نشون داده شده:

نام جدول توضیح
ModuleDef همیشه یه ورودی برای معرفی و شناسایی ماژول داره. این ورودی شامل نام فایل به همراه پسوندش بدون آدرس مسیر فایل و آی دی نسخه ماژول (Module Version ID) به فرمت GUID که توسط کامپایلر تولید میشه، هست.
ذخیره این داده ها باعث میشه تا در صورت تغییر نام فایل ماژول اطلاعات اولیه و اصلی اون همیشه در دسترس باشن. هرچند باید از تغییر نام فایل یه ماژول پرهیز کرد چون ممکنه مانع بارگذاری ماژول توسط CLR بشه.
TypeDef به ازای هر نوع تعریف شده تو ماژول یه ورودی تو این جدول ثبت میشه. هر ورودی شامل نام نوع، نوع پایه یا والد، و برخی فلگ ها مثل public و private، ایندکسهای متدها تو جدول MethodDef، ایندکسهای فیلدها تو جدول FieldDef، ایندکسهای پراپرتیها تو جدول PropertyDef، و ایندکسهای ایونتها تو جدول EventDef.
MethodDef برای هر متد تعریف شده تو اسمبلی یه ورودی تو این جدول ذخیره میشه. هر ورودی شامل نام متد، فلگهای متد (private, public, abstract, virtual و  ...)، امضای متد، و آدرس کد IL اون. هر ورودی تو این جدول میتونه به ورودی های جدول ParamDef برای معرفی اطلاعات بیشتر راجع به پارامترهای متد ریفرنس داشته باشه.
FieldDef تمامی فیلدهای تعریف شده تو ماژول در این جدول یه رکورد خواهند داشت. هر رکورد این جدول شامل نام و نوع فیلد مربوطه به همراه فلگهای اون (private, public و ...) هست.
ParamDef پارامترهای موجود تو ماژول تو این جدول ثبت میشن. هر ورودی این جدول شامل نام و نوع و فلگهای پارامتر مربوطه (in, out و ...) هست.
PropertyDef به ازای هر پارامتر تعریف شده تو ماژول یه ورودی تو این جدول درج میشه. این ورودی ها شامل فلگها، نام و نوع پراپرتی مربوطه میشن.
EventDef برای هر ایونت موجود تو ماژول یه ورودی تو این جدول ثبت میشه. هر ورودی شامل نام و فلگهای رویداد مربوطه هست.

هنگام کامپایل کد توسط کامپایلر، هرچیزی که تو کد برنامه تعریف شده باعث تولید یه رکورد تو یکی از این «جداول تعریف» متادیتا میشه.

علاوه بر اجزایی که کد مربوطه مستقیما تعریف و پیاده سازی کرده، برای اجزای اسمبلی های ریفرنس داده شده هم تو این جداول متادیتا داده هایی درج میشه. این داده های متادیتا شامل یکسری جداول منبع (reference tables) هستن که رکوردهایی از اجزای ریفرنس داده شده رو نگهداری میکنن. تو جدول زیر برخی از انواع رایج این داده های متادیتا (جداول منبع) معرفی شدن:

نام جدول توضیح
AssemblyRef به ازای هر اسمبلی ریفرنس داده شده یه ورودی تو این جدول ثبت میشه. هر ورودی حاوی اطلاعات موردنیاز برای بایند به اسمبلی مربوطه و بارگذاری اون توسط CLR هست: نام اسمبلی (بدون مسیر و پسوند فایل)، نسخه اسمبلی، کالچر یا فرهنگ، و توکن کلید عمومی درصورت وجود. علاوه بر این داده ها، هر ورودی شامل چند فلگ مخصوص و یه مقدار هش که با استفاده از محتوای کلی اسمبلی تولید شده، هست.
ModuleRef به ازای هر ماژول PE که نوع های ریفرنس داده شده رو پیاده سازی کرده یه رکورد تو این جدول درج میشه. هر ورودی شامل نام و پسوند فایل ماژول (بدون مسیر اون) هست. از این جدول برای فراخوانی نوع های پیاده شده تو اسمبلی های چند فایله استفاده میشه.
TypeRef برای هر نوع ریفرنس داده شده یه ورودی تو این جدول ذخیره میشه. تو هر ورودی نام نوع و یه ریفرنس به جایی که نوع رو میشه پیدا کرد ثبت میشه. اگه نوع مربوطه تو یه نوع دیگه تعریف شده باشه، این ریفرنس به یه ورودی TypeRef (جدول منبع) دیگه ارجاع خواهد داشت. اگه نوع مربوطه تو همون ماژول پیاده شده باشه، این ریفرنس به یه ورودی ModuleDef (جدول تعریف) ارجاع خواهد داشت. اگه نوع مربوطه تو یه ماژول دیگه از اسمبلی جاری پیاده شده باشه، این ریفرنس به یه ورودی ModuleRef (جدول منبع) ارجاع خواهد داشت. اگه نوع مربطه تو یه اسمبلی دیگه پیاده شده باشه، این ریفرنس به یه ورودی AssemblyRef (جدول منبع) ارجاع خواهد داشت.
MemberRef به ازای هر عضو ریفرنس داده شده (فیلد، متد، پراپرتی و ایونت) یه ورودی تو این جدول ثبت میشه. هر ورودی شامل نام و امضای عضو میشه و به یه ورودی تو جدول TypeRef برای نوعی که عضو مربوطه توش پیاده شده اشاره میکنه.

علاوه بر این جداول اشاره شده، جداول بسیار دیگری هم تو متادیتا وجود دارن که بدلیل اهمیت کمترشون و مجال کم این مطلب ارائه نمیشن. این جداول بیشتر برای نمایش گوشه ای از داده های متادیتایی که کامپایلرها برای استفاده CLR تولید میکنن آورده شدن. درضمن درباره داده های مانیفست بعدا بحث خواهد شد.


مشاهده متادیتا


ابزارهای مختلفی برای مشاهده و بررسی متادیتای یه اسمبلی مدیریت شده وجود داره. یکی از ساده ترین و پرکاربردترین این ابزارها همون ILDasm.exe یا IL Disassembler هست. برای اجرای اون میشه از خط فرمان توسعه ویژوال استودیو کمک گرفت. آدرس محل نصب این ابزار معمولا تو مسیر نصب SDKهای ویندوز هست. این SDKها همراه ویژوال استودیو نصب میشن. با اجرای این ابزار پنجره زیر نمایش داده میشه:

با استفاده منوی File و گزینه Open میشه اسمبلی موردنظر رو انتخاب و بارگذاری کرد. البته با استفاده از دستور زیر هم میشه بصورت مستقیم یه اسمبلی (برنامه ای که تو مطلب قبلی نشون داده شد) رو باز کرد:

ildasm d:\p.exe

پس از بارگذاری اسمبلی پنجره این ابزار به شکل زیر اطلاعات رو نمایش میده:

همونطور که مشاهده میشه اطلاعات مختلفی از اسمبلی و نوع ها و اعضای تعریف شده تو اون نمایش داده میشه. بخشی که اینجا اهمیت داده نمایش متادیتای اسمبلیه. برای اینکار میشه از منوی View گزینه آخر یعنی MetaInfo و بازهم گزینه آخر !Show رو انتخاب کرد یا کلیدهای Ctrl+M رو فشرد. با اینکار پنجره زیر نمایش داده میشه:

همونطور که مشاهده میشه، اطلاعات متادیتای اسمبلی و جداول اشاره شده تو این پنجره نشون داده میشه. البته برای تولید این داده های مرتب شده، ابزار ILDasm پردازش های خاصی روی داده های خام متادیتا انجام میده تا برای انسان قابل درک باشه. درواقع این داده ها بدین صورت تمیز و مرتب و قابل خوندن توسط انسان تو اسمبلی ذخیره نمیشن.

نیازی نیست تا همه اطلاعات نشون داده شده تو این ابزار رو کاملا درک کرد. اما آشنایی هرچه بیشتر با قسمتهای مختلف این برنامه و اطلاعاتی که نمایش میده میتونه تو برخی مواقع راهگشا باشه. بنابراین مطالعه بیشتر در این زمینه به خوانندگان واگذار میشه.

اما یکی از اطلاعات جالبی که با استفاده از این ابزار میشه بدست آورد، آمار کلی اسمبلی بصورت زیره که با استفاده از منوی View گزینه Statistics بدست میاد:

تو این پنجره میشه اندازه فایل اسمبلی به بایت، و اندازه قسمتهای مختلف این فایل به بایت و درصد از کل رو مشاهده کرد. البته با توجه به مقدار کم کد اسمبلی مثال ما، بیشتر حجم فایل اون توسط داده های هدر PE و هدر CLR اشغال شده و کل کد IL اسمبلی تنها 41 بایت رو اشغال کرده. اما تو پروژه های واقعی و بزرگتر این درصدها کاملا برعکس میشن. هدر PE که عملا شامل یکسری داده های ثابته و هدر CLR هم در مقایسه با کدهای یه پروژه واقعی حجم بسیار کمی داره.


.: اطلاعات کاملتر درباره متادیتای یه اسمبلی: ! و ! و ! و ! :.

  • یوسف نژاد

Metadata

NET Framework.

نظرات  (۰)

هیچ نظری هنوز ثبت نشده است

ارسال نظر

ارسال نظر آزاد است، اما اگر قبلا در بیان ثبت نام کرده اید می توانید ابتدا وارد شوید.
شما میتوانید از این تگهای html استفاده کنید:
<b> یا <strong>، <em> یا <i>، <u>، <strike> یا <s>، <sup>، <sub>، <blockquote>، <code>، <pre>، <hr>، <br>، <p>، <a href="" title="">، <span style="">، <div align="">
تجدید کد امنیتی
آخرین نظرات