پرش به محتوا

نام مستعار (علوم رایانه)

از ویکی‌پدیا، دانشنامهٔ آزاد

در رایانش ، نام مستعار وضعیتی را توصیف می کند که در آن می توان از طریق نام های مختلف در برنامه، به یک داده در حافظه دسترسی پیدا کرد. بنابراین، تغییر داده از طریق یک نام به طور ضمنی مقدار مربوط به همه نام های دیگر را نیز اصلاح می کند، که این موضوع ممکن است موزد انتظار برنامه نویس نباشید. در نتیجه، نام مستعار درک، تحلیل و بهینه سازی برنامه ها را دشوار می کند. تحلیل مستعار فرایندی است که قصد دارد اطلاعات کارآمدی را برای درک نام های مستعار در برنامه ها را بدست بیاورد.

نمونه ها[ویرایش]

سرریز بافر[ویرایش]

به عنوان مثال، بیشتر نسخه های زبان C بررسی محدوده ی آرایه را انجام نمی دهند. در نتیجه، فرد می تواند با سوءاستفاده از این ویژگی پیاده سازی کامپایلر و قراداد های زبان اسمبلی مربوط به معماری یک کامپیوتر، با نوشتن در بیرون محدوده ی یک آرایه (که نوعی سرریزی بافر است) به آثار استفاده از نام مستعار برسد. بر اساس مشخصات زبان C، این کار منجر به یک رفتار نامشخص می شود؛ هر چند برخی از پیاده‌سازی های زبان C آثار استفاده از نام مستعار را که در اینجا توضیح داده شد نشان می دهند.

اگر یک آرایه روی پشته ایجاد شود و یک متغیر در حافظه دقیقا بعد از آن آرایه قرار داشته باشد، برنامه نویس می تواند بیرون از آرایه را نمایه کرده و مستقیما مقدار متغیر را با استفاده از آرایه و عنصر مربوط به آن تغییر دهد. به طور مثال اگر یک آرایه از جنس int به اندازه ۲ در نظر بگیریم و آن را arr بنامیم، و یک متغیر دیگر از نوع int بعد از آن تعریف کنیم و آن را i بنامیم، اگر این دو در حافظه کنار همدیگر قرار داشته باشند، می توان با استفاده از arr[2] مقدار i را تغییر داد.

# include <stdio.h>

int main()
{
  int arr[2] = { 1, 2 };
  int i=10;

  /* خارج از محدوده ی آرایه می نویسیم که منجر به رفتاری پیش‌بینی نشده در سی استاندارد می شود و در برخی پیاده سازی های سی، در متغیر جدید می نویسد. */
  arr[2] = 20;

  printf("element 0: %d \t", arr[0]); // خروجی: ۱
  printf("element 1: %d \t", arr[1]); // خروجی: ۲
  printf("element 2: %d \t", arr[2]); // در صورت رخ دادن ایلیاسینگ، ۲۰ چاپ می شود
  printf("i: %d \t\t", i); // بدلیل ایلیاسینگ ممکن است مقدار ۲۰ چاپ شود اما اگر کامپایلر مقدار ۱۰ را در رجیستر ها ذخیره کرده باشد ممکن است ۱۰ چاپ شود
  /* اندازه آرایه ۲ است */
  printf("arr size: %d \n", (sizeof(arr) / sizeof(int)));
}

این در برخی از پیاده سازی های C ممکن است، چرا که یک آرایه بلوکی از حافظه ی به هم پیوسته است، و عناصر آرایه فقط از طریق فاصله شان با آدرس آغاز بلوک حافظه ضرب در اندازه هر عنصر قابل دسترسی هستند. از آن جاییکه C محدوده آرایه را بررسی نمی کند، آدرس دهی و اشاره به بیرون از یک آرایه ممکن است. دقت کنید که این نوع نام مستعار که ذکر شد یک رفتار نامشخص است. برای نمونه برخی از پیاده‌سازی ها ممکن است بین آرایه و متغیر های داخل پشته فاصله ایجاد کنند تا متغیر هایی را که اندازه شان مضربی از اندازه کلمه معماری سیستم هستند را جا دهند. زبان C استاندار به طور کلی مشخص نمی کند که داده ها چگونه در حافظه قرار بگیرند ( ISO/IEC ۹۸۹۹:۱۹۹۹، بخش ۶٫۲.۶٫۱).

این که یک کامپایلر آثار نام مستعار را برای دسترسی های که در بیرون از محدوده های یک آرایه می افتند را حذف کند، خطا نیست.

اشاره گرهای مستعار[ویرایش]

نوع دیگری از نام مستعار می تواند توسط زبان هایی که از چندین نام برای اشاره به یک موقعیت حافظه استفاده می کند رخ دهد (مثلا با استفاده از اشاره‌گر ها). این مثال از الگوریتم جابجایی XOR در زبان C را که یک تابع است ببینید؛ فرض می کند که اشاره‌گر هایی که به تابع ورودی داده شده است، مجزا هستند، اما اگر آن ها برابر باشند یا مستعار یکدیگر باشند،‌ عملکرد تابع شکست می خورد. این یک مشکل متداول در تپابعی است که اشاره‌گر ها را به عنوان ورودی قبول می کنند و باید میزان تحمل آن ها در برابر نام مستعار به دقت مستند شود،‌به ویژه برای توابعی که عملیات پیچیده ای را روی مناطق حافظه ارسال شده به آنها انجام می دهند.

نام مستعار مشخص شده[ویرایش]

عملکرد نام مستعار کنترل شده ممکن است در بعضی موارد مطلوب باشد (یعنی رفتاری که مشخص شده باشد، برخلاف آنچه که به خاطر ساختار حافظه در C اتفاق می افتد). این روالی معمول در Fortran است. زبان برنامه نویسی Perl در برخی از ساختار ها مانند foreach، نام نستعار را مشخص می کند. این کار اجازه می دهد تا برخی از ساختار های داده مستقیما با کد کمتری اصلاح شوند. برای مثال،

my @array = (1, 2, 3);

foreach my $element (@array) {
    $element++;
}

print "@array \n";


عبارت "4 3 2" را چاپ می‌کند. اگر کسی بخواهد اثرات نام مستعار را دور بزند، می تواند محتویات را به یک متغیر دیگر کپی کند و سپس متغیر جدید را تغیر دهد.

تداخل با بهینه‌ساز[ویرایش]

زمانی که وجود نام مستعار ممکن است، بهینه‌ساز ها معمولا مجبور هستند که فرض های محافظه کارانه ای را در مورد متغیر ها اتخاد کنند. برای مثال، آگاهی از مقدار یک متغیر (مثلا اینکهx برابر ۵ است) اجازه برخی بهینه‌سازی ها را می‌دهد (مثلا درهم کردن ثابت). با این حال، کامپایلر نمی‌تواند از این اطلاعات بعد از مقدار دهی به یک متغیر دیگر استفاده کند (برای مثال، در زبان سی، *y = 10) زیرا*y ممکن است نام مستعاری برای x باشد. این اتفاق ممکن است بعد از مقدار دهی ای مانند y = &x رخ دهد. در نتیجه، مقدار دهی به *y، باعث تغییر مقدار x هم می‌شود.

روش بهینه‌سازی دیگری که تحت تأثیر نام مستعار تحت قرار می گیرد ، تغییر ترتیب کد است. اگر کامپایلر تصمیم بگیرد که *y نام مستعار x نیست ، کدی که مقدار x را استفاده می‌کند یا تغییر می‌دهد، در صورتی که باعث بهبود زمانبندی یا انجام بهینه سازی های حلقه بیشتر شود، می تواند قبل از انتساب *y = 10 بیاید.

برای فعال کردن چنین بهینه سازی هایی به روشی قابل پیش بینی، استاندارد ISO برای زبان برنامه نویسی C (از جمله نسخه جدیدتر C99، نگاه کنید به بخش ۶٫۵ ، بند ۷) مخشص می کند که دسترسی به یک مکان از حافظه با استفاده از نشانگرهایی با نوع های متفاوت ممنوع است. بنابراین یک کامپایلر ممکن است فرض کند که چنین اشاره گرهایی نام مستعار نیستند. این قانون ، که به عنوان قانون نام مستعار سختگیرانه شناخته می شود، گاهی اوقات افزایش چشمگیر عملکرد را امکان‌پذیر می کند، [۱] اما معلوم شده است که برخی از کدهای معتبر را خراب می کند. چندین پروژه نرم افزاری عمداً این بخش از استاندارد C99 را نقض می کنند. به عنوان مثال، Python 2.x این کار را برای پیاده‌سازی شمارش مرجع انجام داد، [۲] و برای فعال کردن این بهینه‌سازی نیاز به تغییراتی در ساختارهای اصلی شی در پایتون ۳ داشت. هسته لینوکس این کار را انجام می دهد زیرا نام مستعار سختگیرانه باعث ایجاد مشکل با بهینه‌سازی کد درون خطی می شود. [۳] در چنین مواردی ، هنگامی که برنامه با gcc کامپایل می شود، برای جلوگیری از بهینه‌سازی های ناخواسته که می توانند کدهای غیر منتظره ای ایجاد کنند، از گزینه fno-strict-aliasing- استفاده می شود.

نام مستعار سخت افزاری[ویرایش]

اصطلاح نام مستعار همچنین برای توصیف وضعیتی استفاده می شود که به دلیل انتخاب نوعی طراحی سخت افزار یا خرابی سخت‌افزار، از یک یا چند بیت آدرس موجود در فرآیند انتخاب حافظه استفاده نشود. [۴] اگر تعداد بیت آدرس بیش از آنچه برای پشتیبانی از دستگاه (های) حافظه نصب شده لازم است وجود داشته باشد، این یک تصمیم طراحی است. در صورت خرابی، ممکن است یک یا چند بیت آدرس با هم کوتاه شوند، یا مجبور شوند ولتاژ زمین (0 منطقی) یا ولتاژ تغذیه (1 منطقی) را بگیرند.

مثال

برای این مثال ، با فرض یک طراحی حافظه با ۸ تایی که فقط به ۳ خط آدرس (یا بیت) نیاز دارد، بیت های آدرس (با نام های A0 تا A2) رمز گشایی می شوند تا مکان های حافظه منحصر به فرد را به صورت زیر و به صورت استاندارد شمارنده دودویی انتخاب کنند:

A2 A1 A0 محل حافظه
0 0 0 0
0 0 1 1
0 1 0 2
0 1 1 3
1 0 0 4
1 0 1 5
1 1 0 6
1 1 1 7

در جدول بالا ، هر یک از ۸ ترکیب منحصر به فرد بیت آدرس ، مکان حافظه متفاوتی را انتخاب می کند. با این حال ، اگر یک بیت آدرس (مثلاً A2) قرار است کوتاه شود ، جدول به صورت زیر اصلاح می شود:

A2 A1 A0 محل حافظه
0 0 0 0
0 0 1 1
0 1 0 2
0 1 1 3
0 0 0 0
0 0 1 1
0 1 0 2
0 1 1 3

در این حالت ، با صفر بودن A2، چهار مکان حافظه اول تکراری می شوند و دوباره به عنوان چهار مکان دوم ظاهر می شوند و مکان های حافظه ۴ تا ۷ از دسترس شده اند.

اگر این تغییر در یک بیت آدرس متفاوت رخ دهد، نتایج رمزگشایی متفاوت خواهد بود، اما به طور کلی نتیجه یکسان خواهد بود: از دست دادن یک بیت آدرس، فضای حافظه موجود را به نصف کاهش می دهد، در نتیجه فضای باقی مانده تکراری (مستعار) می شود.

مطالب بیشتر[ویرایش]

منابع[ویرایش]

  1. Mike Acton (2006-06-01). "Understanding Strict Aliasing".
  2. Neil Schemenauer (2003-07-17). "ANSI strict aliasing and Python".
  3. Linus Torvalds (2003-02-26). "Re: Invalid compilation without -fno-strict-aliasing".
  4. Michael Barr (2012-07-27). "Software Based Memory Testing".

لینک های خارجی[ویرایش]