برنامه نویسی ترکیبی C/ASM/C++

برنامه نویسی ترکیبی C/ASM/C++ (2)

تعریف متغیر در درون اسمبلی و دسترسی به آن از درون برنامه C:

      براي تعريف يك متغير در برنامه‌هاي اسمبلي پيش از اين با دو كلمه .bss و .usect آشنا شديد. جهت يادآوري مي‌توانيد به فصول اولیه کتاب كه فايل command‌ در آنها توضيح داده شد مراجعه كنيد.

يك فايل جديد ايجاد و آنرا با پسوند ".asm" (يك فايل از نوع اسمبلي ) ذخيره كرده و سپس به پروژه اضافه كنيد. اكنون در فايل اسمبلي، برنامه بعد را تايپ كنيد.

برنامه 1: يك برنامه اسمبلي نمونه براي تعريف يك متغير در يك Section با نام ASMSec

      .global         _varASM

_varASM     .usect       "ASMSec" , 1 ;

براي استفاده از اين متغير ، در يك فايل C برنامه زير را تايپ كنيد( فراموش نكنيد كه فايل را در شاخه پروژه کپی کنید تا به پروژه اضافه شود)

 

تمام label ها مانند _varASM بايد در برنامه‌هاي اسمبلي(*.asm) حتما از اول خط نوشته شوند. بقيه كلمات مانند .usect‌ يا دستورات بايد با يك TAB يا فاصله از سر خط شروع شوند.

برنامه 2: يك برنامه ساده C براي استفاده از متغيري كه در فايل اسمبلي تعريف شده است.

extern     char       varASM;

void     main()

{

       varASM = 6 ;

}

 

در برنامه‌نويسي C اگر متغيري در يك فايل تعريف نشده باشد (و در دیگر فایلها تعریف شده باشد) ولي در آن فايل از آن استفاده شود حتما بايد با كلمه extern تعريف گردد.

      varASM در فايل اسمبلي به اندازه يك واحد حافظه تعريف شده است. به ياد داريد كه واحد حافظه براي تمامي خانواده‌ها غير از سري 6000 معادل يك word است. براي سري 6000 واحد حافظه يك بايت است. به همين دليل نوع متغير در فايل اسمبلي char تعريف شده كه معادل يك واحد حافظه است.

      پروژه را Build كرده و سپس آنرا Load ‌ و اجرا كنيد. مي‌توانيد با گذاشتن Break Point در برنامه‌ها، اجرا را متوقف نماييد.

 برنامه C براي استفاده از متغيرهاي تعريف شده در فايل اسمبلي

ممکن است هنگام اجرای ( ونه در هنگام Load برنامه ) انواع خطاها در نرم افزار ظاهر شود. این خطاها در هنگام دسترسی به یکی از آدرسهایی که در برنامه وجود دارد ایجاد می شود. این خطا ناشی ازدسترسی به یک آدرس نادرست در فضای حافظه پردازنده است. در فصول قبلی کتاب دیدیم که برای دسترسی به هر خانه حافظه ابتدا باید در دیتا شیت پردازنده جدول مربوط به Memory Model را بررسی کنیم. در اینجا آدرس AD یک عدد دلخوه است و برای varASM نیز آدرسی انتخاب نشده و نرم افزار این متغیر را در یک آدرس با انتخاب خودش قرار داده است. این آدرس ها بسته به نوع پردازنده می توانند برای آن پردازنده یکی از نواحی غیر قابل قبول باشند. مثلا به فضایی اشاره کنند که جزو فضاهای آدرس دهی رزرو شده در پردازنده است. دسترسی به یک آدرس غیر مجاز ناشی از یک خطای کد نویسی است که در زمان کامپایل ممکن است قابل شناسائی نباشد و باید برنامه اجرا شود تا خود را نشان دهد. تنها به دلیل استفاده از شبیه ساز، هنگام اجرای برنامه، خطا یا هشدار در پنجره Consol ظاهر می‌شود. اگر از یک برد واقعی استفاده میکردید نرم افزار این خطا ها را نشان نمی‌‌داد. چون اجرا در خارج از کامپیوتر و بر روی برد صورت میگرفت و عملا نرم افزار CCS از آن خبردار نمی‍‌شد.

توجه

در بعضي از خانواده‌ها مانند سري 6XXX يك warning در نرم‌افزار CCS‌ ايجاد مي‌گردد و توصيه مي‌كند كه در تعريف متغير مشترك بين C و اسمبلي، از كلمه near‌يا far ‌استفاده شود. به صورت پيش فرض كلمه near تنها براي متغيرهاي درون .bss تعريف مي‌گردد. مثلا در سري‌هاي 6XXX آدرس‌هاي تمام متغيرهاي درون .bss با 16 بيت مشخص مي‌گردد.( دقت شود كل فضاي آدرس‌دهي در 6XXX 32 بيت است بنابراين وقتي آدرسها 16 بيتي تعريف گردند بايد 16 بيت دوم آدرس توسط بخش ديگري مشخص گردد). در اين حالت 16 بيت دوم فضاي آدرس با رجيستر داخلي   Data Page Pointer(DP) مشخص مي‌شود. اين روش هم سرعت بيشتري دارد و هم حجم برنامه‌هاي توليد شده كمتر است. چون براي ذخيره آدرس يك متغير به جاي 32 بيت از 16 بيت استفاده مي‌گردد.

به صورت پيش فرض در سري‌هاي 6XXX تمام structureها ، unionها ، classهاو آرايه‌ها به صورت far تعريف مي‌شوند. براي اطلاعات بيشتر مي‌توانيد به HELP‌ نرم‌افزار CCS‌ مراجعه كنيد.

      اكنون متغير varASM تعريف شده است ولي آدرس آن توسط خود نرم‌افزار اختصاص داده شده است. فراموش نشود كه هدف اصلي از تعريف متغير در اسمبلي، مشخص كردن يك آدرس دلخواه براي متغير بود. براي اين منظور بايد فايل command مناسب، نيز براي پروژه درست گردد.

هنگام ایجاد پروژه در CCS جدید اکثر موارد یک فایل command به صورت پیش‌فرض برای پروژه ایجاد می‌شود. چون می‌خواهیم فایل command جدید به پروژه اضافه کنیم. ابتدا اگر در شاخه پروژه یک فایل با پسوند ".cmd" دیدید ابتدا آنرا را حذف کنید. فقط به خاطر داشته باشید که در ادامه دوباره به این فایل مجدد نیاز خواهیم داشت. اكنون يك فايل ديگر با پسوند ".cmd" ايجاد و به پروژه اضافه كنيد. در اين فايل برنامه بعد را تايپ كنيد.[1]

MEMORY

{

      PAGE         0 :

           ASM         : origin = 0x123456   ,      length = 2

}

SECTIONS

{

           ASMSec     : {}   >         ASM

}

پروژه را Build كنيد[2]. پروژه تعداد زيادي خطا ايجاد مي‌كند( اگر پروژه شما خطا ايجاد نكرد احتمالا فايل ".cmd" يا RTS را به پروژه اضافه نكرده‌ايد). دقت كنيد كه تنها لينكر بايد خطاهايي از جنس زير توليد كرده باشد:

error #10099-D: program will not fit into available memory. placement with alignment fails for section ".text" size 0x420 .   Available memory ranges:

ASM   size: 0x2         unused: 0x1         max hole: 0x1      

يعني ASM به اندازه كافي فضا براي .text ندارد. اگر خطاها از نوع ديگري بودند بر روي آنها دوبار كليك كنيد تا به محل خطا رفته و مشكل را برطرف كنيد.

اكنون مي‌توان نگاهي دقيق تر به فايل command  انداخت :

نگاهي دقيق‌تر به مفهوم MEMORY در فايل command

      در فايل command بخشي وجود دارد به نام MEMORY . در اين بخش تعدادي فضا‌ي حافظه تعريف مي‌شود. در هر پروژه‌ طراح سخت افزار سيستم بايد اين بخش را تكميل كند. مثلا اگر برد شما پردازنده‌اي دارد كه 128 كيلو بايت در درون خود RAM‌( از آدرس 0 تا 0x20000 ) و يك حافظه كمكي به اندازه 1 مگا بايت ( از آدرس 0x10 0000 تا 0x20 0000 ) دارد ، در فايل command مي‌توان بخش MEMORY را به صورت زير نوشت:

MEMORY

{

            InternalRAM : origin= 0 ,       length= 0x20000

            ExternalRAM : origin=0x100000, length = 0x200000

}

در قسمت SECTIONS بايد ليست تمام section هاي برنامه را ذكر نمود. اگر section ي فراموش شود نرم‌افزار به شكل اتوماتيك آنرا در يكي از انواع حافظه‌هاي درون MEMORY قرار مي‌دهد.

SECTIONS

{

           .text                : {}       >          InternalRAM

           ASMSec           : {}       >          ExternalRAM

}

      خطايي كه نرم‌افزار ‍‍CCS توليد كرده به اين دليل است كه در فايل command، به نرم‌افزار گفته شده كه اين سيستم تنها يك حافظه به طول 2 !! و در آدرس 0x123456 دارد. طبیعی است در فضای 2 بایتی تقریبا هیچ کدام از SECTION ها (به غیر ازASMSec ) جا نمی‌شود. پس لينكر نمي‌تواند دیگر SECTION ها را در اين فضا جاي دهد. براي حل اين مشكل باید فايل command را به شكلی اصلاح نمود که حداقل یک فضای اضافه برای دیگر SECTION ها ( به غیر از ASMSec‌) در آن وجود داشته باشد. اما این فضا را در کجای حافظه باید قرار دهیم؟ یا برای پردازنده 6747 کجا مناسب .text است؟ پاسخ به این سئوالات را با بررسی صفحه Meomry Map دیتاشیت پردازنده می‌توان مشخص نمود. در سری 6747 در آدرس 0x80000000 یک حافظه با نام Shared Ram قرار دارد که از آن می توان مانند یک حافظه معمولی استفاده نمود[3].

اکنون برای حل مشکل دو راه حل دارید: راه حل اول تغیر فایل command ی که نوشته بودید به شکل بعد:

برنامه 3 : يك فايل CMD براي مشخص كردن آدرس ASMSec‌ در حافظه

MEMORY

{

            PAGE   0 :

            ASM        :     origin = 0x123456           ,     length = 2

            SHARED :  origin =   0x80000000         ,     length = 0x20000

}

SECTIONS

{

            ASMSec   :       {}   >       ASM

}

تمرين : در اينجا در بخش SECTIONS تنها يكي از section هاي برنامه تعريف شده است. اين روش نوشتن فايل command ‌ غير استاندارد است و ممكن است در بعضي از انواع پروژه‌ها اشكال ايجاد كند. اكنون فايل با پسوند ".map" را پيدا كرده و از روي آن تمام section ها برنامه را ، درون فايل command‌تعريف كنيد. با تعريف هر section يكي از warning هايي كه لينكر ايجاد مي‌كند كم شود.

روش دوم : در حالیکه فایل command خودتان را که قبلا نوشته بودید را تغیر نداده‌اید؛ فایل command ی که قبلا حذف کرده بودید را به پروژه باز برگردانید. حالا پروژه شما باید دو فایل command داشته باشد. در این حالت لینکر به دستورات درون هر دو فایل command یکی پس از دیگری عمل می‌کند. در واقع دو فایل command با هم or می‌شوند. در فایل command اولیه پروژه که همراه پروژه توسط نرم افزار به وجود آمده بود SECTION ها در آدرس‌های پیش فرض قرار گرفته بودند. اکنون چون هدف قرار دادن یک SECTION جدید در یک آدرس جدید است اینکار را در یک فایل جدید انجام می دهیم.[4]

      برنامه را Build‌، Load و Run كنيد. در محل خط varASM = 6 ; يك Break Point قرار داده و با كليك راست بر روي varASM آنرا به پنجره Expression اضافه كنيد. آدرس varASM را در اين پنجره مشاهده كنيد[5]. مطمئن شويد كه آدرس آن 0x123456‌ است. اگر اينگونه نبود فايل ".map" را باز نموده و محل section، با نام ASMSec را با كمك آن پيدا كنيد.

آدرس متغير varASM در فضاي حافظه 6XXX

 


 

دوشنبه, 24 مهر 1396 ساعت 08:44

تعریف مشترک متغیرهای در درون ‍C و اسمبلی

نوشته شده توسط

 تعریف مشترک متغیرهای در درون ‍C و اسمبلی

يك راه حل ديگر اما مطمئن براي قرار دادن متغيرها درآدرس‌هاي دلخواه استفاده از فايل command ( با پسوند ".cmd") است. ديديم كه فايل command يك وسيله مناسب براي مديريت حافظه پردازنده مي‌باشد. در اين فايل مي‌توان آدرس section ها را در فضاي حافظه مشخص كرد. يكي از امكاناتي كه در نرم‌افزارCCS وجود دارد اين است كه مثلا بتوان براي متغير AD يك section جداگانه تعريف كرد و سپس آن section را در فايلcommand در آدرس 0x3FEDC8 قرار داد. در ادامه چند روش مختلف براي اين منظور توضيح داده مي‌شود. اين روشها هيچ‌كدام مزيتي بر ديگري نداشته ولي با يادگيري هر كدام مي‌توانيد در كاربردهاي مختلف مناسب‌ترين روش را انتخاب كنيد.

      نوشتن همزمان برنامه‌ها به زبان C و اسمبلي كاربردهاي زيادي دارد. در بسياري از پروژه‌ها طراحان ترجيح مي‌دهند بخشي از پروژه را به زبان اسمبلي بنويسند. به طور مثال تعدادي از توابع سيستم كه بيشترين زمان پردازش را به خود اختصاص مي‌دهند به زبان اسمبلي نوشته شده ولي براي صرفه جويي در وقت بقيه توابع به زبان C نوشته مي‌شوند. در ادامه اين فصل با برخي از مفاهيمي كه براي نوشتن برنامه‌ها به زبان C واسمبلي نياز است آشنا خواهيد شد. بنابراين كاربرد مطالب اين فصل تنها محدود به تعريف متغير AD نبوده بلكه اصول برنامه‌نويسي همزمان C و اسمبلي به عنوان يكي از روشهاي پر كاربرد توضيح داده مي‌گردد.

نكته

تمام برنامه‌هاي اسمبلي را بايد در فايلهاي با پسوند ".asm" و برنامه‌هاي C را با ".c" و برنامه‌هاي C++ را با ".cpp" نوشت. همچنين پسوند ".C" ( حرف C بزرگ) باعث مي‌شود كامپايلر فايل را از نوع C++ در نظر بگيرد. نرم‌افزار CCS با توجه به پسوند نام فايلها آنها را كامپايل مي‌كند.

پيش از ادامه مطلب نياز است يك نكته مهم در برنامه‌نويسي مشترك C و اسمبلي مرور گردد.

توجه

هنگام نوشتن يك برنامه ‌در اسمبلي ممكن است نياز باشد تا يكي از متغيرهاي برنامه‌هاي C‌ در اسمبلي استفاده گردد و يا برعكس در يك برنامه‌C ، نياز به استفاده از متغيرهاي برنامه‌هاي اسمبلي ‌باشد. در اين شرايط نام متغير يا آدرس تابع در C و اسمبلي با هم فرق مي‌كند. تمام اسامي دراسمبلي يك عدد under line) _ ( در ابتداي نامشان اضافه مي‌گردد. مثلا اگر متغيري در درون C نامش var است در فايل اسمبلي براي استفاده از آن متغير بايد از نام _var استفاده شود. ويا برعكس اگر متغيري در اسمبلي وجود دارد كه از درونC هم به آن دسترسي وجود دارد بايد در اسمبلي با يك _ اضافه تعريف گردد. مثلا اگر متغير به نام _varASM در اسمبلي وجود دارد در C نام آن varASM خواهد بود.

عضویت در سایت

برای اطلاع از آخرین خبرهای دنیای DSPعضو شوید