মাইক্রোকন্ট্রোলার কীভাবে বুট এবং স্টার্টআপ হয়, ধাপে ধাপে?


17

সি কোডটি যখন কোনও মাইক্রোকন্ট্রোলারে লিখিত, সংকলিত এবং আপলোড করা হয়, তখন মাইক্রোকন্ট্রোলার চলতে শুরু করে। তবে আমরা যদি ধীরে ধীরে এই আপলোডিং এবং স্টার্টআপ প্রক্রিয়াটি ধাপে ধাপে নিই তবে এমসইউয়ের ভিতরে আসলে কী ঘটছে (মেমরি, সিপিইউ, বুটলোডার) সম্পর্কে আমার কিছু বিভ্রান্তি আছে। যদি কেউ আমাকে জিজ্ঞাসা করে তবে আমি কি উত্তর দেব তা এখানে (সম্ভবত খুব ভুল) রয়েছে:

  1. সংকলিত বাইনারি কোডটি ইউএসবির মাধ্যমে রম ফ্ল্যাশ (বা EEPROM) করতে লেখা হয় is
  2. বুটলোডার এই কোডটির কিছু অংশ র‌্যামে অনুলিপি করে। যদি সত্য হয় তবে বুট-লোডার কীভাবে কীভাবে অনুলিপি করতে পারবেন (রমের কোন অংশটি র‍্যামে অনুলিপি করতে হবে)?
  3. সিপিইউ রম এবং র‌্যাম থেকে কোডের নির্দেশাবলী এবং ডেটা আনতে শুরু করে

এটা কি ভুল?

এই পর্যায়ে মেমরি, বুটলোডার এবং সিপিইউ কীভাবে যোগাযোগ করে সে সম্পর্কে কিছু তথ্যের সাথে বুট করার এবং প্রারম্ভের এই প্রক্রিয়াটির সংক্ষিপ্ত বিবরণ দেওয়া সম্ভব?

পিসি কীভাবে বায়োএসের মাধ্যমে বুট হয় তার অনেকগুলি প্রাথমিক ব্যাখ্যা আমি পেয়েছি। তবে আমি মাইক্রোকন্ট্রোলার স্টার্টআপ প্রক্রিয়াটির সাথে আটকে আছি।

উত্তর:


31

1) সংকলিত বাইনারি প্রম / ফ্ল্যাশ হ্যাঁ লিখিত হয়। ইউএসবি, সিরিয়াল, আই 2 সি, জেট্যাগ ইত্যাদি ডিভাইসের উপর নির্ভর করে যে ডিভাইসটি সমর্থন করে তা বুট প্রক্রিয়াটি বোঝার জন্য অপ্রয়োজনীয়।

2) এটি সাধারণত কোনও মাইক্রোকন্ট্রোলারের ক্ষেত্রে সত্য নয়, প্রাথমিক ব্যবহারের ক্ষেত্রে র‌্যাম / ফ্ল্যাশ এবং র‌্যামে ডেটা থাকতে হবে। আর্কিটেকচার যাই হোক না কেন। নন-মাইক্রোকন্ট্রোলার, আপনার পিসি, আপনার ল্যাপটপ, আপনার সার্ভারের জন্য প্রোগ্রামটি নন-ভোল্টাইল (ডিস্ক) থেকে রামে অনুলিপি করা হয় তারপর সেখান থেকে চালানো হবে। কিছু মাইক্রোকন্ট্রোলার আপনাকে র‌্যামও ব্যবহার করতে দেয়, এমনকি যেগুলি হার্ভার্ড দাবি করে এমনকি এটি সংজ্ঞা লঙ্ঘন করে বলে মনে হয়। হার্ভার্ড সম্পর্কে কিছুই নেই যা আপনাকে দিকনির্দেশের দিকে ম্যাম ম্যাপিং থেকে বিরত রাখে, ক্ষমতা শেষ হওয়ার পরে আপনাকে নির্দেশাবলী পাওয়ার জন্য কেবল একটি ব্যবস্থা থাকা দরকার (যা সংজ্ঞা লঙ্ঘন করে, তবে হার্ভার্ড সিস্টেমগুলি অন্য কার্যকর হওয়ার জন্য এটি করতে হবে) মাইক্রোকন্ট্রোলার হিসাবে)।

3) সাজানো।

প্রতিটি সিপিইউ একটি ডিজিস্টিনিস্টিক হিসাবে "বুট" করে, যেমন নকশা করা হয়। সর্বাধিক সাধারণ উপায় একটি ভেক্টর টেবিল যেখানে পাওয়ার আপ হওয়ার পরে চালানোর জন্য প্রথম নির্দেশাবলীর ঠিকানাটি রিসেট ভেক্টরে রয়েছে, হার্ডওয়্যার পরে যে ঠিকানাটি পড়ে তা চালানো শুরু করার জন্য সেই ঠিকানাটি ব্যবহার করে। অন্য সাধারণ উপায়টি হ'ল প্রসেসরটি কোনও সুপরিচিত ঠিকানায় ভেক্টর টেবিল ছাড়া চালানো শুরু করে। কখনও কখনও চিপে "স্ট্র্যাপস" থাকে, এমন কিছু পিন থাকে যা রিসেট প্রকাশের আগে আপনি উচ্চ বা নিম্নটি ​​বেঁধে রাখতে পারেন, যুক্তিটি বিভিন্ন উপায়ে বুট করার জন্য ব্যবহার করে। আপনাকে সিপিইউ পৃথক করতে হবে, প্রসেসরের কোরটি সিস্টেমের বাকি অংশ থেকে। সিপিইউ কীভাবে পরিচালিত হয় তা বুঝুন এবং তারপরে বুঝতে পারবেন যে চিপ / সিস্টেম ডিজাইনারদের সিপিইউর বাইরের চারপাশে সেটআপ ঠিকানা ডিকোডার রয়েছে যাতে সিপাস ঠিকানা জায়গার কিছু অংশ একটি ফ্ল্যাশ দিয়ে যোগাযোগ করে, এবং কিছুটি ভেড়ার সাথে এবং কিছু পেরিফেরাল (uart, i2c, spi, gpio, ইত্যাদি) সহ। আপনি চাইলে সেই একই সিপিইউ কোরটি নিতে পারেন এবং এটিকে অন্যভাবে মোড়ানো করতে পারেন। আপনি যখন বাহু বা মাইপস ভিত্তিক কিছু কিনবেন তখন আপনি এটি পাবেন। আর্ম এবং মিপস সিপু কোর তৈরি করে, যা চিপ লোকেরা তাদের নিজস্ব জিনিসপত্র চারপাশে কেনে এবং জড়িয়ে রাখে, বিভিন্ন কারণে তারা সেই জিনিসটিকে ব্র্যান্ড থেকে ব্র্যান্ডের সাথে সামঞ্জস্যপূর্ণ করে না। মূল কারণের বাইরে যখন কিছু আসে তখন খুব কমই জেনেরিক আর্ম প্রশ্ন করতে পারে।

একটি মাইক্রোকন্ট্রোলার একটি চিপে একটি সিস্টেম হওয়ার চেষ্টা করে, তাই এর নন-অস্থির মেমরি (ফ্ল্যাশ / রোম), উদ্বায়ী (শ্রম) এবং সিপিইউ পেরিফেরিয়ালের মিশ্রণের পাশাপাশি একই চিপে থাকে। তবে চিপটি অভ্যন্তরীণভাবে এমনভাবে ডিজাইন করা হয়েছে যে ফ্ল্যাশটি সিপিইউর ঠিকানা স্পেসে ম্যাপ করা থাকে যা সেই সিপিইউর বুটের বৈশিষ্ট্যের সাথে মেলে। উদাহরণস্বরূপ, যদি সিপিইউতে 0xFFFC ঠিকানায় একটি রিসেট ভেক্টর থাকে, তবে দরকারী প্রোগ্রামগুলির জন্য ঠিকানার জায়গাতে পর্যাপ্ত ফ্ল্যাশ / রোমের পাশাপাশি ফ্ল্যাশ / রোম থাকা দরকার যা সেই ঠিকানার প্রতিক্রিয়া জানায় 1 এই প্রয়োজনীয়তাগুলি পূরণ করতে একটি চিপ ডিজাইনার 0xF000 থেকে শুরু করে 0x1000 বাইট বেছে নিতে পারেন। এবং সম্ভবত তারা একটি কম ঠিকানা বা সম্ভবত 0x0000, এবং মাঝখানে কোথাও পেরিফেরিয়াল কিছু পরিমাণ র‌্যাম লাগিয়েছে।

সিপিইউর আরেকটি স্থাপত্য সম্ভবত শূন্যের থেকে সম্পাদন শুরু করতে পারে, সুতরাং তাদের বিপরীতটি করা দরকার, ফ্ল্যাশটি স্থাপন করা উচিত যাতে এটি শূন্যের কাছাকাছি কোনও অ্যাড্রেস রেঞ্জের উত্তর দেয়। উদাহরণস্বরূপ 0x0000 থেকে 0x0FFF বলুন। এবং তারপরে কিছুটা ভেড়া রেখে দিন।

চিপ ডিজাইনাররা জানেন কীভাবে সিপিইউ বুট হয় এবং তারা সেখানে অ-উদ্বায়ী স্টোরেজ স্থাপন করে (ফ্ল্যাশ / রোম)। তারপরে সফ্টওয়্যার ভাবার লোকেরা সেই সিপিইউর সুপরিচিত আচরণের সাথে মেলে বুট কোডটি লিখতে পারে। আপনাকে রিসেট ভেক্টরটিতে রিসেট ভেক্টরের ঠিকানা এবং আপনার বুট কোডটি রিসেট ভেক্টরে সংজ্ঞায়িত ঠিকানায় রাখতে হবে। সরঞ্জামচেন এখানে আপনাকে ব্যাপক সাহায্য করতে পারে। কখনও কখনও, পয়েন্ট সহ ক্লিক করুন এবং আইডস বা অন্যান্য স্যান্ডবক্সগুলিতে ক্লিক করুন তারা আপনার জন্য সবচেয়ে বেশি কাজ করতে পারে আপনি যা করেন তা হ'ল উচ্চ স্তরের ভাষায় (সি) এপিআই কল করুন।

তবে, এটি করা হয়ে গেলে ফ্ল্যাশ / রোমে লোড হওয়া প্রোগ্রামটি সিপিইউর হার্ডওয়ার্ড বুট আচরণের সাথে মেলে। আপনার প্রোগ্রামের প্রধান অংশ () এর সি অংশ আগে এবং আপনি যদি আপনার প্রবেশ বিন্দু হিসাবে প্রধান ব্যবহার করেন তবে কিছু কাজ করতে হবে। এসি প্রোগ্রামার ধরে নেয় যে যখন প্রাথমিক মান সহ একটি ভেরিয়েবল ঘোষণা করে তখন তারা আশা করে যে এটি বাস্তবে কাজ করবে। ওয়েল, ভেরিয়েবলগুলি, কনস্টের চেয়ে ভিন্ন, রামে থাকে তবে আপনার যদি প্রাথমিক মান সহ একটি থাকে তবে প্রাথমিক মানটি অ-উদ্বায়ী র‌্যামে থাকতে হবে। সুতরাং এটি .ডাটা বিভাগ এবং সি বুটস্ট্র্যাপের ফ্ল্যাশ থেকে রামে ড্যাটা স্টাফ অনুলিপি করা প্রয়োজন (যেখানে সাধারণত সরঞ্জামচেইন আপনার জন্য নির্ধারিত হয়)। কোনও প্রাথমিক মান ছাড়াই আপনি যে গ্লোবাল ভেরিয়েবলগুলি ঘোষণা করেন তা আপনার প্রোগ্রামটি শুরুর আগে শূন্য বলে ধরে নেওয়া হয় যদিও আপনার সত্যিকার অর্থে এটি অনুমান করা উচিত নয় এবং কৃতজ্ঞতার সাথে কিছু সংকলক অবিচ্ছিন্ন ভেরিয়েবল সম্পর্কে সতর্ক করতে শুরু করেছেন। এটি .bss বিভাগ, এবং সি বুটস্ট্র্যাপ শূন্যগুলি যা মেষ হিসাবে প্রকাশিত হয়, সামগ্রী, শূন্যগুলি অ-উদ্বায়ী মেমরিতে সংরক্ষণ করতে হয় না, তবে সূচনা ঠিকানা এবং কতগুলি হয়। আবার টুলচেন আপনাকে এখানে ব্যাপক সাহায্য করে। এবং সর্বশেষে খালি ন্যূনতম আপনাকে স্ট্যাক পয়েন্টার সেটআপ করতে হবে কারণ সি প্রোগ্রামগুলি স্থানীয় ভেরিয়েবলগুলি রাখতে সক্ষম হবে এবং অন্যান্য ফাংশনগুলি কল করতে পারে expect তারপরে সম্ভবত অন্য কিছু চিপ নির্দিষ্ট জিনিস হয়ে গেছে, বা আমরা বাকী চিপ নির্দিষ্ট জিনিসগুলি সিতে ঘটতে দেব অ-উদ্বায়ী মেমরিতে সঞ্চয় করতে হবে না, তবে শুরু করার ঠিকানা এবং কতগুলি। আবার টুলচেন আপনাকে এখানে ব্যাপক সাহায্য করে। এবং সর্বশেষে খালি ন্যূনতম আপনাকে স্ট্যাক পয়েন্টার সেটআপ করতে হবে কারণ সি প্রোগ্রামগুলি স্থানীয় ভেরিয়েবলগুলি রাখতে সক্ষম হবে এবং অন্যান্য ফাংশনগুলি কল করতে পারে expect তারপরে সম্ভবত অন্য কিছু চিপ নির্দিষ্ট জিনিস হয়ে গেছে, বা আমরা বাকী চিপ নির্দিষ্ট জিনিসগুলি সিতে ঘটতে দেব অ-উদ্বায়ী মেমরিতে সঞ্চয় করতে হবে না, তবে শুরু করার ঠিকানা এবং কতগুলি। আবার টুলচেন আপনাকে এখানে ব্যাপক সাহায্য করে। এবং সর্বশেষে খালি ন্যূনতম আপনাকে স্ট্যাক পয়েন্টার সেটআপ করতে হবে কারণ সি প্রোগ্রামগুলি স্থানীয় ভেরিয়েবলগুলি রাখতে সক্ষম হবে এবং অন্যান্য ফাংশনগুলি কল করতে পারে expect তারপরে সম্ভবত অন্য কিছু চিপ নির্দিষ্ট জিনিস হয়ে গেছে, বা আমরা বাকী চিপ নির্দিষ্ট জিনিসগুলি সিতে ঘটতে দেব

আর্ম থেকে কর্টেক্স-এম সিরিজ কোরগুলি এটি আপনার জন্য কিছু করবে, স্ট্যাক পয়েন্টারটি ভেক্টর টেবিলের মধ্যে রয়েছে, রিসেটের পরে চালানো কোডটি চিহ্নিত করার জন্য একটি রিসেট ভেক্টর রয়েছে, যাতে আপনাকে যা করতে হবে তা বাদ দিয়ে অন্য ভেক্টর টেবিল তৈরি করতে (যা আপনি সাধারণত যেভাবেই asm ব্যবহার করেন) আপনি asm ছাড়াই খাঁটি সি যেতে পারেন। এখন আপনি আপনার .ডাটা অনুলিপি করতে পারবেন না বা আপনার .bss শূন্য হয়েছে তাই আপনি যদি কর্টেক্স-এম ভিত্তিক কোনও কিছুতে asm ছাড়াই চেষ্টা করতে চান তবে আপনাকে নিজেরাই এটি করতে হবে। বড় বৈশিষ্ট্যটি রিসেট ভেক্টর নয়, তবে ভ্যাক্টরগুলিকে বাধা দেয় যেখানে হার্ডওয়্যার অস্ত্রের প্রস্তাবিত সি কলিং কনভেনশন অনুসরণ করে এবং আপনার জন্য নিবন্ধগুলি সংরক্ষণ করে এবং সেই ভেক্টরের জন্য সঠিক রিটার্ন ব্যবহার করে, যাতে আপনাকে প্রতিটি হ্যান্ডলারের চারপাশে ডান অ্যাসেমটি আবৃত করতে না হয় ( বা আপনার লক্ষ্যটির জন্য সরঞ্জামচেইন এটি আপনার জন্য জড়ানোর জন্য নির্দিষ্ট কৌশল রয়েছে specific

চিপ নির্দিষ্ট জিনিসগুলি উদাহরণস্বরূপ হতে পারে, মাইক্রোকন্ট্রোলারগুলি প্রায়শই ব্যাটারি ভিত্তিক সিস্টেমে ব্যবহৃত হয়, তাই খুব কম শক্তি তাই বেশিরভাগ পেরিফেরাল বন্ধ হয়ে রিসেট থেকে বেরিয়ে আসে এবং আপনাকে এই সাব সিস্টেমগুলির প্রতিটি চালু করতে হবে যাতে আপনি সেগুলি ব্যবহার করতে পারেন । Uarts, gpio, ইত্যাদি প্রায়শই একটি স্ফটিক বা অভ্যন্তরীণ দোলক থেকে সরাসরি স্বল্প-ইশ ঘড়ির গতি ব্যবহার করা হয়। এবং আপনার সিস্টেম ডিজাইনে দেখাতে পারে যে আপনার একটি দ্রুত ঘড়ি দরকার, তাই আপনি এটি আরম্ভ করুন। আপনার ঘড়িটি ফ্ল্যাশ বা র‌্যামের জন্য খুব দ্রুত হতে পারে তাই আপনাকে ঘড়ির উপরের চাপ দেওয়ার আগে ওয়েট স্টেটগুলি পরিবর্তন করতে হতে পারে। ইউআর্ট, অথবা ইউএসবি বা অন্যান্য ইন্টারফেস সেটআপ করা দরকার। তাহলে আপনার অ্যাপ্লিকেশনটি এটি করতে পারে।

একটি কম্পিউটার ডেস্কটপ, ল্যাপটপ, সার্ভার এবং একটি মাইক্রোকন্ট্রোলার তারা কীভাবে বুট / কাজ করে তা আলাদা নয়। এগুলি বাদ দিয়ে তারা বেশিরভাগই একটি চিপে থাকে না। বায়োস প্রোগ্রামটি প্রায়শই সিপিইউ থেকে আলাদা চিপ ফ্ল্যাশ / রোমে থাকে। যদিও সম্প্রতি x86 সিপাস একই প্যাকেজে সাপোর্ট চিপস ব্যবহার করত তার আরও বেশি বেশি টানছে (পিসিআই কন্ট্রোলার ইত্যাদি) তবে আপনার এখনও আপনার বেশিরভাগ র‌্যাম এবং রোম অফ চিপ বন্ধ রয়েছে তবে এটি এখনও একটি সিস্টেম এবং এটি এখনও ঠিক কাজ করে একটি উচ্চ স্তরে একই। সিপিইউ বুট প্রক্রিয়াটি সুপরিচিত, বোর্ড ডিজাইনাররা ফ্ল্যাশ / রোমটিকে ঠিকানার জায়গাতে রেখে দেয় যেখানে সিপিইউ বুট হয়। এই প্রোগ্রামটি (একটি x86 পিসিতে বিআইওএসের অংশ) উপরে বর্ণিত সমস্ত জিনিস করে, এটি বিভিন্ন পেরিফেরিয়ালগুলি শুরু করে, এটি ড্রামকে আরম্ভ করে, পিসি বাসগুলি গণনা করে, ইত্যাদি। বায়োস সেটিংসের উপর ভিত্তি করে ব্যবহারকারী বা প্রায়শই আমরা সেমিওস সেটিংস কল করে যা ব্যবহারকারীর দ্বারা প্রায়শই বেশ কনফিগার করা যায়, কারণ সেই সময়ে প্রযুক্তিটি কী ব্যবহৃত হত what কিছু যায় আসে না, এমন কিছু ব্যবহারকারীর সেটিংস রয়েছে যা আপনি যেতে পারেন এবং বায়োস বুট কোডটি কীভাবে পরিবর্তিত হয় তা কীভাবে তা জানাতে পরিবর্তন করতে পারেন।

বিভিন্ন লোকেরা বিভিন্ন পরিভাষা ব্যবহার করবে। একটি চিপ বুট, এটি প্রথম কোড চালিত হয়। কখনও কখনও বুটস্ট্র্যাপ বলা হয়। লোডার শব্দের সাহায্যে বুটলোডারটির অর্থ হ'ল আপনি যদি হস্তক্ষেপ করতে কিছু না করেন তবে এটি একটি বুটস্ট্র্যাপ যা আপনাকে জেনেরিক বুটিং থেকে আরও বড় কিছুতে নিয়ে যায়, আপনার অ্যাপ্লিকেশন বা অপারেটিং সিস্টেম। তবে লোডার অংশটি বোঝায় যে আপনি বুট প্রক্রিয়াটি বাধাগ্রস্থ করতে পারেন এবং তারপরে সম্ভবত অন্যান্য পরীক্ষার প্রোগ্রামগুলি লোড করতে পারেন। যদি আপনি এমবেডেড লিনাক্স সিস্টেমে উদাহরণস্বরূপ কখনও ইউবুট ব্যবহার করেন, আপনি একটি কী চাপতে পারেন এবং সাধারণ বুটটি থামাতে পারেন তবে আপনি একটি পরীক্ষার কার্নেলটিকে রামে ডাউনলোড করতে পারেন এবং ফ্ল্যাশটিতে থাকা একের পরিবর্তে এটি বুট করতে পারেন, বা আপনি আপনার ডাউনলোড করতে পারেন নিজস্ব প্রোগ্রাম, বা আপনি নতুন কার্নেলটি ডাউনলোড করতে পারেন তারপরে বুটলোডার এটি ফ্ল্যাশ করতে লিখতে পারে যাতে পরের বার আপনি এটি বুট করে নতুন স্টাফটি চালায়।

যতক্ষণ না সিপিইউ নিজেই, মূল প্রসেসর, যা পেরিফেরিয়াল থেকে ফ্ল্যাশ থেকে রাম জানে না। বুটলোডার, অপারেটিং সিস্টেম, অ্যাপ্লিকেশন সম্পর্কে কোনও ধারণা নেই। এটি সিপিইউতে কার্যকর করার জন্য নির্দেশাবলীর একটি ক্রম মাত্র। এগুলি একে অপরের থেকে বিভিন্ন প্রোগ্রামিং কার্যকে পৃথক করার সফ্টওয়্যার শর্তাদি। একে অপরের থেকে সফ্টওয়্যার ধারণা।

কিছু মাইক্রোকন্ট্রোলারগুলির একটি পৃথক ফ্ল্যাশ বা ফ্ল্যাশের পৃথক স্থানে চিপ বিক্রেতার দ্বারা সরবরাহিত একটি পৃথক বুটলোডার রয়েছে যা আপনি সংশোধন করতে পারবেন না। এক্ষেত্রে প্রায়শই একটি পিন বা পিনের সেট থাকে (আমি তাদের স্ট্র্যাপ বলি) যে রিসেট প্রকাশের আগে আপনি এগুলিকে উচ্চ বা নীচে বেঁধে রাখলে আপনি যুক্তি এবং / অথবা সেই বুটলোডারকে কী করতে হবে তা বলছেন, উদাহরণস্বরূপ একটি স্ট্র্যাপ সমন্বয় হতে পারে চিপটিকে সেই বুটলোডারটি চালানোর জন্য বলুন এবং ফ্ল্যাশটিতে ডেটা প্রোগ্রাম করার জন্য ইউআর্টে অপেক্ষা করুন। স্ট্রিপগুলি অন্য উপায়ে সেট করুন এবং চিপ বিক্রেতাদের বুটলোডার নয়, আপনার প্রোগ্রাম বুট করে চিপের ফিল্ড প্রোগ্রামিংয়ের জন্য অনুমতি দেয় বা আপনার প্রোগ্রাম ক্র্যাশ হয়ে পুনরুদ্ধার করে। কখনও কখনও এটি খাঁটি যুক্তি যা আপনাকে ফ্ল্যাশ প্রোগ্রাম করার অনুমতি দেয়। আজকাল এটি বেশ সাধারণ,

বেশিরভাগ মাইক্রোকন্ট্রোলারদের রামের চেয়ে অনেক বেশি ফ্ল্যাশ হওয়ার কারণটি হ'ল প্রাথমিক ব্যবহারের ক্ষেত্রে প্রোগ্রামটি সরাসরি ফ্ল্যাশ থেকে চালানো হয় এবং কেবল স্ট্যাক এবং ভেরিয়েবলগুলি coverাকতে পর্যাপ্ত মেষ থাকে। যদিও কিছু ক্ষেত্রে আপনি রাম থেকে প্রোগ্রামগুলি চালনা করতে পারেন যা আপনাকে ডান সংকলন করতে হবে এবং ফ্ল্যাশ সংরক্ষণ করতে হবে তারপরে কল করার আগে অনুলিপি করুন।

সম্পাদনা

flash.s

.cpu cortex-m0
.thumb

.thumb_func
.global _start
_start:
stacktop: .word 0x20001000
.word reset
.word hang
.word hang
.word hang

.thumb_func
reset:
    bl notmain
    b hang

.thumb_func
hang:   b .

notmain.c

int notmain ( void )
{
    unsigned int x=1;
    unsigned int y;
    y = x + 1;

    return(0);
}

flash.ld

MEMORY
{
    bob : ORIGIN = 0x00000000, LENGTH = 0x1000
    ted : ORIGIN = 0x20000000, LENGTH = 0x1000
}
SECTIONS
{
    .text : { *(.text*) } > bob
    .rodata : { *(.rodata*) } > bob
    .bss : { *(.bss*) } > ted
    .data : { *(.bss*) } > ted AT > bob
}

সুতরাং এটি কর্টেক্স-এম 0 এর জন্য একটি উদাহরণ, কর্টেক্স-এমএস সমস্ত এই উদাহরণ হিসাবে যতটা কাজ করে। নির্দিষ্ট চিপ, উদাহরণস্বরূপ, আর্ম অ্যাড্রেস স্পেসে 0x00000000 ঠিকানায় অ্যাপ্লিকেশন ফ্ল্যাশ এবং 0x20000000 এ র্যাম রয়েছে।

কর্টেক্স-এম বুটগুলি যেভাবে ঠিকানাতে 0x0000 এ 32 বিট শব্দ হয় তা স্ট্যাক পয়েন্টার সূচনা করার ঠিকানা। আমার এই উদাহরণের জন্য খুব বেশি স্ট্যাকের দরকার নেই তাই 0x20001000 যথেষ্ট হবে, স্পষ্টতই সেই ঠিকানার নীচে ভেড়া থাকতে হবে (বাহুটি যেভাবে ধাক্কা দেয়) এটি কি প্রথমে সাবট্র্যাক্ট করে ধাক্কা দেয় তাই যদি আপনি 0x20001000 সেট করেন তবে স্ট্যাকের প্রথম আইটেমটি ঠিকানায় 0x2000FFFC এ রয়েছে আপনাকে 0x2000FFFC ব্যবহার করতে হবে না)। ঠিকানা 0x0004 এ 32 বিট শব্দটি হ'ল রিসেট হ্যান্ডলারের ঠিকানা, মূলত প্রথম কোড যা রিসেটের পরে চলে। তারপরে আরও বিঘ্নিত এবং ইভেন্ট হ্যান্ডলার রয়েছে যা সেই কর্টেক্স এম কোর এবং চিপের সাথে সুনির্দিষ্ট, সম্ভবত আপনি 128 বা 256 এর মতো ব্যবহার করেন, যদি আপনি তাদের ব্যবহার না করেন তবে আপনাকে তাদের জন্য টেবিল সেটআপ করতে হবে না, আমি কয়েকজনকে বিক্ষোভের জন্য ফেলেছি উদ্দেশ্য।

এই উদাহরণে আমাকে .ডাটা বা .bss নিয়ে কাজ করার দরকার নেই কারণ আমি ইতিমধ্যে জানি যে কোডগুলি দেখে এই বিভাগগুলিতে কিছুই নেই। যদি সেখানে থাকে তবে আমি এটি মোকাবেলা করব এবং এক সেকেন্ডের মধ্যেই যাব।

সুতরাং স্ট্যাকটি সেটআপ, চেক, ড্যাটা যত্ন নেওয়া, চেক, বিএসএস, চেক, যাতে সি বুটস্ট্র্যাপ স্টাফ সম্পন্ন হয়, সি এর জন্য প্রবেশ ফাংশনে শাখা করতে পারে কারণ কিছু সংকলক যদি ফাংশনটি দেখেন তবে অতিরিক্ত জাঙ্ক যোগ করবেন প্রধান () এবং প্রধান পথে, আমি সেই সঠিক নামটি ব্যবহার করি না, আমি এখানে আমার সি এন্ট্রি পয়েন্ট হিসাবে নোটমেন () ব্যবহার করেছি। সুতরাং রিসেট হ্যান্ডলার কল করুন notmain () তবে / যদি notmain () ফেরত দেয় তবে এটি ঝুলতে চলে যায় যা কেবল অসীম লুপ, সম্ভবত খারাপ নামকরণ।

আমি দৃ master়ভাবে এই সরঞ্জামগুলিতে দক্ষতা অর্জনে বিশ্বাস করি, অনেক লোকই তা করেন না তবে আপনি যেটি পাবেন তা হ'ল প্রতিটি খালি ধাতব বিকাশকারী তার নিজের কাজটি করে, প্রায় সম্পূর্ণ স্বাধীনতার কারণে, আপনি অ্যাপস বা ওয়েব পৃষ্ঠাগুলি তৈরির মতো দূরবর্তীভাবে সীমাবদ্ধ নন not । তারা আবার তাদের নিজস্ব কাজ করে। আমি নিজের বুটস্ট্র্যাপ কোড এবং লিঙ্কার স্ক্রিপ্টটি পছন্দ করি। অন্যরা সরঞ্জামচেনের উপর নির্ভর করে, বা বিক্রেতার স্যান্ডবক্সে খেলেন যেখানে বেশিরভাগ কাজ অন্য কারও দ্বারা করা হয় (এবং যদি কিছু কিছু ভেঙে যায় তবে আপনি আঘাতের জগতে রয়েছেন, এবং খালি ধাতব জিনিসগুলি প্রায়শই এবং নাটকীয় উপায়ে ভেঙে যায়)।

সুতরাং আমি প্রাপ্ত gnu সরঞ্জামগুলির সাথে একত্রিত, সংকলন এবং লিঙ্কিং:

00000000 <_start>:
   0:   20001000    andcs   r1, r0, r0
   4:   00000015    andeq   r0, r0, r5, lsl r0
   8:   0000001b    andeq   r0, r0, fp, lsl r0
   c:   0000001b    andeq   r0, r0, fp, lsl r0
  10:   0000001b    andeq   r0, r0, fp, lsl r0

00000014 <reset>:
  14:   f000 f802   bl  1c <notmain>
  18:   e7ff        b.n 1a <hang>

0000001a <hang>:
  1a:   e7fe        b.n 1a <hang>

0000001c <notmain>:
  1c:   2000        movs    r0, #0
  1e:   4770        bx  lr

সুতরাং বুটলোডার কীভাবে জানেন যে স্টাফ রয়েছে। কারণ সংকলকটি কাজটি করেছিল। প্রথম ক্ষেত্রে এসেম্ব্লার ফ্ল্যাশ.এস এর জন্য কোড তৈরি করে এবং এটি করে লেবেলগুলি কোথায় রয়েছে তা জানেন (লেবেলগুলি ঠিক ফাংশনের নাম বা ভেরিয়েবলের নাম ইত্যাদির মতো ঠিক ঠিকানা) তাই আমাকে বাইটগুলি গণনা করতে এবং ভেক্টরটি পূরণ করতে হয়নি টেবিলটি ম্যানুয়ালি, আমি একটি লেবেলের নাম ব্যবহার করেছি এবং সমাবেশটি আমার জন্য এটি করেছিল। এখন আপনি জিজ্ঞাসা করুন, যদি রিসেটটি 0x14 ঠিকানা হয় তবে এসেম্ব্লার কেন ভেক্টর টেবিলে 0x15 রাখে। ভাল এটি একটি কর্টেক্স-এম এবং এটি বুট হয় এবং কেবল থাম্ব মোডে চলে। আর্মের সাহায্যে আপনি যখন কোনও ঠিকানায় শাখা করেন যদি থাম্ব মোডে শাখা করা হয় lsbit সেট করা দরকার, যদি আর্ম মোডটি পুনরায় সেট করা হয়। সুতরাং আপনি সর্বদা যে বিট সেট প্রয়োজন। আমি সরঞ্জামগুলি এবং লেবেলের আগে .thumb_func লাগিয়ে জানি, যদি সেই লেবেলটি ভেক্টর টেবিলের মতো ব্যবহার করা হয় বা ব্রাঞ্চ করার জন্য বা যে কোনও ক্ষেত্রে। টুলচেইন lsbit সেট করতে জানে। সুতরাং এটি 0x14 | 1 = 0x15 এখানে আছে। একইভাবে ফাঁসি জন্য। এখন বিচ্ছিন্নকরণকারী কল করতে notx () কল করার জন্য 0x1D দেখায় না তবে যন্ত্রগুলি সঠিকভাবে নির্দেশিকাটি তৈরি করেছে তা নিয়ে চিন্তা করবেন না।

এখন সেই কোডটি নোমেনে, সেই স্থানীয় ভেরিয়েবলগুলি ব্যবহৃত হয় না, তারা ডেড কোড। সংকলক এমনকি y সেট করে ব্যবহার করে তা বলে মন্তব্য করে।

ঠিকানার জায়গাগুলি নোট করুন, এই জিনিসগুলি সমস্ত 0x0000 ঠিকানায় শুরু হয় এবং সেখান থেকে যান যাতে ভেক্টর টেবিলটি সঠিকভাবে স্থাপন করা হয়, টেক্সট বা প্রোগ্রাম স্পেসটিও সঠিকভাবে স্থাপন করা হয়, কীভাবে আমি notmain.c এর কোডের সামনে ফ্ল্যাশ পেয়েছি by সরঞ্জামগুলি জানা, একটি সাধারণ ভুল হ'ল সঠিক না হওয়া এবং ক্রাশ হওয়া এবং শক্ত পোড়া না করা। আইএমও আপনাকে প্রথম বার বুট করার আগে জিনিসগুলি ঠিকঠাক স্থাপন করা হয়েছে তা নিশ্চিত করতে আলাদা করতে হবে, একবার আপনার যদি সঠিক জায়গায় জিনিস থাকে তবে আপনাকে অবশ্যই প্রতিবার পরীক্ষা করতে হবে না। কেবল নতুন প্রকল্পগুলির জন্য বা তারা স্তব্ধ হয়ে থাকে।

এখন এমন কিছু যা কিছু লোককে অবাক করে তোলে তা হল যে কোনও দুটি কম্পাইলার একই ইনপুট থেকে একই আউটপুট উত্পাদন করবে বলে আশা করার কোনও কারণ নেই। এমনকি বিভিন্ন সেটিংস সহ একই সংকলক। ঝাঁকুনি ব্যবহার করে, llvm সংকলকটি অপটিমাইজেশন সহ এবং ছাড়াই এই দুটি আউটপুট পাই

llvm / ঝনঝন অপ্টিমাইজড

00000000 <_start>:
   0:   20001000    andcs   r1, r0, r0
   4:   00000015    andeq   r0, r0, r5, lsl r0
   8:   0000001b    andeq   r0, r0, fp, lsl r0
   c:   0000001b    andeq   r0, r0, fp, lsl r0
  10:   0000001b    andeq   r0, r0, fp, lsl r0

00000014 <reset>:
  14:   f000 f802   bl  1c <notmain>
  18:   e7ff        b.n 1a <hang>

0000001a <hang>:
  1a:   e7fe        b.n 1a <hang>

0000001c <notmain>:
  1c:   2000        movs    r0, #0
  1e:   4770        bx  lr

অপ্টিমাইজড না

00000000 <_start>:
   0:   20001000    andcs   r1, r0, r0
   4:   00000015    andeq   r0, r0, r5, lsl r0
   8:   0000001b    andeq   r0, r0, fp, lsl r0
   c:   0000001b    andeq   r0, r0, fp, lsl r0
  10:   0000001b    andeq   r0, r0, fp, lsl r0

00000014 <reset>:
  14:   f000 f802   bl  1c <notmain>
  18:   e7ff        b.n 1a <hang>

0000001a <hang>:
  1a:   e7fe        b.n 1a <hang>

0000001c <notmain>:
  1c:   b082        sub sp, #8
  1e:   2001        movs    r0, #1
  20:   9001        str r0, [sp, #4]
  22:   2002        movs    r0, #2
  24:   9000        str r0, [sp, #0]
  26:   2000        movs    r0, #0
  28:   b002        add sp, #8
  2a:   4770        bx  lr

সুতরাং এটি একটি মিথ্যা যা সংকলকটি সংযোজনটিকে অপ্টিমাইজ করেছিল, তবে এটি ভেরিয়েবলগুলির জন্য স্ট্যাকের উপর দুটি আইটেম বরাদ্দ করেছিল, যেহেতু এগুলি স্থানীয় ভেরিয়েবলগুলি তারা মেষের মধ্যে থাকে তবে স্ট্যাকের উপর স্থির ঠিকানাগুলিতে নয়, গ্লোবালগুলির সাথে দেখবে যে পরিবর্তন। তবে সংকলকটি বুঝতে পেরেছিল যে এটি সংকলনের সময় y নির্ণয় করতে পারে এবং রান সময় এটি গণনা করার কোনও কারণ নেই তাই এটি কেবল এক্স এর জন্য বরাদ্দ হওয়া স্ট্যাক স্পেসে 1 এবং y এর জন্য বরাদ্দকৃত স্ট্যাক স্পেসের জন্য 2 রাখে। সংকলক অভ্যন্তরীণ সারণীর সাহায্যে এই স্থানটিকে "বরাদ্দ" দেয় আমি ভেরিয়েবল ওয়য়ের জন্য স্ট্যাক প্লাস 0 এবং ভেরিয়েবল এক্সের জন্য স্ট্যাক প্লাস 4 ঘোষণা করি। সংস্থাপকটি কোডটি সি স্ট্যান্ডার্ড বা সি প্রোগ্রামারের এক্সপেটেশন অনুসারে যতক্ষণ তা প্রয়োগ করতে পারে তাই এটি করতে পারে। কম্পাইলারটি ফাংশনটির সময়কালের জন্য স্ট্যাক + 4 এ x রেখে যাওয়ার কোনও কারণ নেই,

যদি আমি এসেম্বেলারে একটি ফাংশন ডামি যুক্ত করি

.thumb_func
.globl dummy
dummy:
    bx lr

এবং তারপর এটি কল

void dummy ( unsigned int );
int notmain ( void )
{
    unsigned int x=1;
    unsigned int y;
    y = x + 1;
    dummy(y);
    return(0);
}

আউটপুট পরিবর্তন

00000000 <_start>:
   0:   20001000    andcs   r1, r0, r0
   4:   00000015    andeq   r0, r0, r5, lsl r0
   8:   0000001b    andeq   r0, r0, fp, lsl r0
   c:   0000001b    andeq   r0, r0, fp, lsl r0
  10:   0000001b    andeq   r0, r0, fp, lsl r0

00000014 <reset>:
  14:   f000 f804   bl  20 <notmain>
  18:   e7ff        b.n 1a <hang>

0000001a <hang>:
  1a:   e7fe        b.n 1a <hang>

0000001c <dummy>:
  1c:   4770        bx  lr
    ...

00000020 <notmain>:
  20:   b510        push    {r4, lr}
  22:   2002        movs    r0, #2
  24:   f7ff fffa   bl  1c <dummy>
  28:   2000        movs    r0, #0
  2a:   bc10        pop {r4}
  2c:   bc02        pop {r1}
  2e:   4708        bx  r1

এখন যেহেতু আমাদের নেস্ট করা ফাংশন রয়েছে, নোটমাইন ফাংশনটির তার রিটার্ন ঠিকানাটি সংরক্ষণ করা দরকার, যাতে এটি নেস্টেড কলের জন্য রিটার্ন ঠিকানাটি ক্লোবার করতে পারে। এটি কারণ বাহুটি রিটার্নের জন্য একটি রেজিস্টার ব্যবহার করে, যদি এটি স্ট্যাকটি ব্যবহার করে যেমন একটি x86 বা অন্য কিছু ভালভাবে বলে ... এটি এখনও স্ট্যাকটি ভিন্নভাবে ব্যবহার করবে। এখন আপনি জিজ্ঞাসা করলেন কেন এটি r4 চাপল? ঠিক আছে, কলিং কনভেনশনটি খুব বেশি কাল আগে স্ট্যাকটি 32 বিটের পরিবর্তে একটি শব্দের বাউন্ডারের পরিবর্তে 64 বিট (দুই শব্দ) বাউন্ডারি ধরে রাখার জন্য পরিবর্তিত হয়েছিল। সুতরাং তাদের স্ট্যাকটি সারিবদ্ধ রাখতে কিছুটা চাপ দেওয়া দরকার, তাই সংকলক নির্বিচারে কোনও কারণে r4 বেছে নিয়েছিল, কেন তা বিবেচ্য নয়। আর 4-এ পপিং একটি বাগ হবে যদিও এই টার্গেটের কলিং কনভেনশন অনুসারে আমরা একটি ফাংশন কলের ক্লোবার আর 4 না, আমরা r3 এর মাধ্যমে আর0 ক্লোবার করতে পারি। r0 হল রিটার্ন মান value দেখে মনে হচ্ছে এটি লেজ অপটিমাইজেশন করছে doing

তবে আমরা দেখতে পাই যে এক্স এবং ওয়াই ম্যাথটি 2 এর একটি হার্ডকোডযুক্ত মানটিকে ডামি ফাংশনে পাস করার জন্য অনুকূলিত করা হয়েছে (ডামি একটি পৃথক ফাইলে বিশেষভাবে কোড করা হয়েছিল, এই ক্ষেত্রে asm তে, যাতে সংকলকটি সম্পূর্ণরূপে ফাংশন কলটিকে অনুকূল করতে পারে না, যদি আমার একটি ডামি ফাংশন থাকে যা কেবলমাত্র সিটিতে notmain.c এ ফিরে আসে optim অপটিমাইজারটি এক্স, ওয়াই এবং ডামি ফাংশন কলটি সরিয়ে ফেলত কারণ তারা সমস্ত মৃত / অব্যর্থ কোড)।

এছাড়াও নোট করুন যেহেতু ফ্ল্যাশ.এস কোডটি বৃহত্তর নোটমেন পেয়ে গেছে অন্যথায় এবং টুলচেইন আমাদের জন্য সমস্ত ঠিকানা প্যাচিংয়ের যত্ন নিয়েছে যাতে আমাদের ম্যানুয়ালি এটি করতে হবে না।

রেফারেন্সের জন্য অপ্রচলিত ঝনঝন

00000020 <notmain>:
  20:   b580        push    {r7, lr}
  22:   af00        add r7, sp, #0
  24:   b082        sub sp, #8
  26:   2001        movs    r0, #1
  28:   9001        str r0, [sp, #4]
  2a:   2002        movs    r0, #2
  2c:   9000        str r0, [sp, #0]
  2e:   f7ff fff5   bl  1c <dummy>
  32:   2000        movs    r0, #0
  34:   b002        add sp, #8
  36:   bd80        pop {r7, pc}

অপ্টিমাইজড ঝনঝন

00000020 <notmain>:
  20:   b580        push    {r7, lr}
  22:   af00        add r7, sp, #0
  24:   2002        movs    r0, #2
  26:   f7ff fff9   bl  1c <dummy>
  2a:   2000        movs    r0, #0
  2c:   bd80        pop {r7, pc}

এই সংকলক লেখক স্ট্যাকটি সারিবদ্ধ করার জন্য ডামি ভেরিয়েবল হিসাবে r7 ব্যবহার করতে পছন্দ করেছেন, এটি স্ট্যাক ফ্রেমে কিছু না থাকলেও এটি r7 ব্যবহার করে একটি ফ্রেম পয়েন্টার তৈরি করছে। মূলত নির্দেশটি অপ্টিমাইজ করা যেতে পারে। তবে এটি পপটি তিনটি নির্দেশ না দিয়ে ফিরে ব্যবহার করেছিল, সম্ভবত আমার উপরই আমি বাজি ধরেছিলাম যে আমি ডান কমান্ড লাইন অপশন (প্রসেসরের নির্দিষ্ট করে) দিয়ে জিসিসি পেতে পারি।

এটি বেশিরভাগ আপনার বাকি প্রশ্নের উত্তর দেওয়া উচিত

void dummy ( unsigned int );
unsigned int x=1;
unsigned int y;
int notmain ( void )
{
    y = x + 1;
    dummy(y);
    return(0);
}

আমার এখন গ্লোবাল আছে। সুতরাং তারা অপটিমাইজড না হয়ে থাকলে .Data বা .bss এ প্রবেশ করে।

আমরা চূড়ান্ত আউটপুট দেখার আগে এর মধ্যবর্তী বস্তু তাকান

00000000 <notmain>:
   0:   b510        push    {r4, lr}
   2:   4b05        ldr r3, [pc, #20]   ; (18 <notmain+0x18>)
   4:   6818        ldr r0, [r3, #0]
   6:   4b05        ldr r3, [pc, #20]   ; (1c <notmain+0x1c>)
   8:   3001        adds    r0, #1
   a:   6018        str r0, [r3, #0]
   c:   f7ff fffe   bl  0 <dummy>
  10:   2000        movs    r0, #0
  12:   bc10        pop {r4}
  14:   bc02        pop {r1}
  16:   4708        bx  r1
    ...

Disassembly of section .data:
00000000 <x>:
   0:   00000001    andeq   r0, r0, r1

এখন এটি থেকে কোনও তথ্য অনুপস্থিত তবে এটি কী চলছে তার একটি ধারণা দেয়, লিঙ্কারটি হ'ল বস্তু গ্রহণ করে এবং তাদের সাথে লিঙ্ক করা তথ্য সরবরাহ করে (এই ক্ষেত্রে ফ্ল্যাশ.ল্ড) যেখানে এটি বলে যে টেক্সট এবং কোথায়। তথ্য এবং যেমন যায়। সংকলক এই জাতীয় জিনিস জানে না, এটি কেবল এটি উপস্থাপিত কোডের উপর দৃষ্টি নিবদ্ধ করতে পারে, কোনও বাহ্যিক সংযোগ পূরণ করার জন্য এটি কোনও লিঙ্কারের জন্য একটি ছিদ্র ছেড়ে দিতে হয়। যে কোনও ডেটাতে things জিনিসগুলিকে একসাথে যুক্ত করার উপায় ছেড়ে যেতে হবে, তাই সমস্ত সংখ্যার ঠিকানা এখানে শূন্যের ভিত্তিতে কেবল কারণ সংকলক এবং এই বিচ্ছিন্নকরণকারী জানেন না। লিঙ্কার জিনিস রাখার জন্য এখানে ব্যবহার করে এমন অন্য তথ্য এখানে দেখানো হয়নি। এখানে কোডটি যথেষ্ট পর্যায়ে স্বাধীন তাই লিঙ্কার তার কাজটি করতে পারে।

এরপরে আমরা সংযুক্ত আউটপুটটির কমপক্ষে একটি বিচ্ছিন্নতা দেখতে পাই

00000020 <notmain>:
  20:   b510        push    {r4, lr}
  22:   4b05        ldr r3, [pc, #20]   ; (38 <notmain+0x18>)
  24:   6818        ldr r0, [r3, #0]
  26:   4b05        ldr r3, [pc, #20]   ; (3c <notmain+0x1c>)
  28:   3001        adds    r0, #1
  2a:   6018        str r0, [r3, #0]
  2c:   f7ff fff6   bl  1c <dummy>
  30:   2000        movs    r0, #0
  32:   bc10        pop {r4}
  34:   bc02        pop {r1}
  36:   4708        bx  r1
  38:   20000004    andcs   r0, r0, r4
  3c:   20000000    andcs   r0, r0, r0

Disassembly of section .bss:

20000000 <y>:
20000000:   00000000    andeq   r0, r0, r0

Disassembly of section .data:

20000004 <x>:
20000004:   00000001    andeq   r0, r0, r1

সংকলকটি মূলত র্যামে দুটি 32 বিট ভেরিয়েবলের জন্য বলেছে। একটি .bss এ আছে কারণ আমি এটি আরম্ভ করি নি তাই এটি শূন্য হিসাবে অনুমান করা হয়। অন্যটি .ডাটা কারণ আমি এটি ঘোষণার ভিত্তিতে শুরু করেছি।

এখন এটি বিশ্বব্যাপী পরিবর্তনশীল বলে ধরে নেওয়া হচ্ছে যে অন্যান্য ফাংশনগুলি সেগুলি সংশোধন করতে পারে। সংকলক কখন নোমেন বলা যায় সে সম্পর্কে কোনও অনুমান করে না তাই এটি যেটি দেখতে পারে তার সাথে y = x + 1 গণিতটি অনুকূল করতে পারে না, সুতরাং এটি রানটাইম করতে হবে। এটি রাম থেকে পড়তে হবে দুটি ভেরিয়েবল এগুলি যুক্ত করে ফিরে সংরক্ষণ করতে হবে।

এখন পরিষ্কারভাবে এই কোড কাজ করবে না। কেন? কারণ এখানে যেমন দেখানো হয়েছে আমার বুটস্ট্র্যাপটি নোমেন কল করার আগে র‌্যাম প্রস্তুত করে না, তাই চিপ যখন জেগেছিল তখন 0x20000000 এবং 0x20000004 এ যা কিছু আবর্জনা ছিল তা হ'ল y এবং x এর জন্য ব্যবহৃত হবে।

এখানে যে প্রদর্শন করতে যাচ্ছি না। আপনি আমার আরও দীর্ঘায়িত ঝাঁকুনি পড়তে পারেন .ডাটা এবং .bss এবং কেন আমি কখনই আমার খালি ধাতব কোডে এগুলি প্রয়োজন হয় না, তবে আপনি যদি মনে করেন যে অন্য কারও কাছে এটি আশা করার চেয়ে আপনি সরঞ্জামগুলি অর্জন করতে এবং দক্ষতা অর্জন করতে চান তবে .. ।

https://github.com/dwelch67/raspberrypi/tree/master/bssdata

লিঙ্কার স্ক্রিপ্ট এবং বুটস্ট্র্যাপগুলি কিছুটা সংকলক নির্দিষ্ট করে তাই আপনি একটি সংকলকের এক সংস্করণ সম্পর্কে যা কিছু শিখেন তা পরবর্তী সংস্করণে বা অন্য কোনও সংকলক সহ টস করতে পারে, তারপরেও আমি .ডাটা এবং .bss প্রস্তুতিতে প্রচুর পরিশ্রম না লাগানোর আরেকটি কারণ reason শুধু এই অলস হতে:

unsigned int x=1;

আমি বরং এটি করতে চাই

unsigned int x;
...
x = 1;

এবং সংকলকটি এটি আমার জন্য পাঠ্য দিন। কখনও কখনও এটি ফ্ল্যাশ সেভ করে কখনও কখনও এটি বেশি জ্বলতে থাকে। টুলচেন সংস্করণ বা অন্য একটি সংকলক থেকে প্রোগ্রাম এবং পোর্ট করা সবচেয়ে স্পষ্টভাবে সহজ। অনেক বেশি নির্ভরযোগ্য, কম ত্রুটিযুক্ত প্রবণ। হ্যাঁ, সি স্ট্যান্ডার্ডের সাথে খাপ খায় না।

এখন যদি আমরা এই স্থির গ্লোবালগুলি তৈরি করি?

void dummy ( unsigned int );
static unsigned int x=1;
static unsigned int y;
int notmain ( void )
{
    y = x + 1;
    dummy(y);
    return(0);
}

আমরা হব

00000020 <notmain>:
  20:   b510        push    {r4, lr}
  22:   2002        movs    r0, #2
  24:   f7ff fffa   bl  1c <dummy>
  28:   2000        movs    r0, #0
  2a:   bc10        pop {r4}
  2c:   bc02        pop {r1}
  2e:   4708        bx  r1

স্পষ্টত those ভেরিয়েবলগুলি অন্য কোড দ্বারা সংশোধন করা যায় না, তাই সংকলক এখন সংকলন সময়ে ডেড কোডটিকে অপ্টিমাইজ করতে পারে, যেমনটি এর আগে করেছিল।

unoptimized

00000020 <notmain>:
  20:   b580        push    {r7, lr}
  22:   af00        add r7, sp, #0
  24:   4804        ldr r0, [pc, #16]   ; (38 <notmain+0x18>)
  26:   6800        ldr r0, [r0, #0]
  28:   1c40        adds    r0, r0, #1
  2a:   4904        ldr r1, [pc, #16]   ; (3c <notmain+0x1c>)
  2c:   6008        str r0, [r1, #0]
  2e:   f7ff fff5   bl  1c <dummy>
  32:   2000        movs    r0, #0
  34:   bd80        pop {r7, pc}
  36:   46c0        nop         ; (mov r8, r8)
  38:   20000004    andcs   r0, r0, r4
  3c:   20000000    andcs   r0, r0, r0

এই সংকলকটি যা স্থানীয়দের জন্য স্ট্যাক ব্যবহার করেছিল, এখন গ্লোবালগুলির জন্য র‌্যাম ব্যবহার করে এবং লিখিত হিসাবে এই কোডটি নষ্ট হয়ে গেছে কারণ আমি .Data বা .bss সঠিকভাবে পরিচালনা করি নি।

এবং একটি সর্বশেষ জিনিস যা আমরা বিচ্ছিন্নতার মধ্যে দেখতে পাচ্ছি না।

:1000000000100020150000001B0000001B00000075
:100010001B00000000F004F8FFE7FEE77047000057
:1000200080B500AF04480068401C04490860FFF731
:10003000F5FF002080BDC046040000200000002025
:08004000E0FFFF7F010000005A
:0400480078563412A0
:00000001FF

আমি 0x12345678 এর সাথে প্রি-ইন হয়ে এক্স পরিবর্তন করেছি। আমার লিঙ্কার স্ক্রিপ্ট (এটি gnu ld এর জন্য) বব জিনিসটিতে এই টেড রয়েছে। এটি লিঙ্কারে বলছে আমি চূড়ান্ত জায়গাটি টেড ঠিকানার জায়গায় থাকতে চাই, তবে এটি টেড ঠিকানার জায়গায় বাইনারি রেখে সঞ্চয় করব এবং কেউ আপনার জন্য এটি স্থানান্তরিত করবে। এবং আমরা দেখতে পেয়েছি যে ঘটেছে। এটি ইন্টেল হেক্স ফর্ম্যাট। এবং আমরা 0x12345678 দেখতে পাচ্ছি

:0400480078563412A0

বাইনারি ফ্ল্যাশ ঠিকানা স্পেসে হয়।

পাঠকরাও এটি দেখায়

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  EXIDX          0x010040 0x00000040 0x00000040 0x00008 0x00008 R   0x4
  LOAD           0x010000 0x00000000 0x00000000 0x00048 0x00048 R E 0x10000
  LOAD           0x020004 0x20000004 0x00000048 0x00004 0x00004 RW  0x10000
  LOAD           0x030000 0x20000000 0x20000000 0x00000 0x00004 RW  0x10000
  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RWE 0x10

LOAD লাইন যেখানে ভার্চুয়াল ঠিকানা 0x20000004 এবং দৈহিক 0x48


একেবারে শুরুতে আমার কাছে দুটি অস্পষ্ট ছবি রয়েছে:
ব্যবহারকারী 16307

১) "প্রাথমিক ব্যবহারের ক্ষেত্রে র‌্যাম / ফ্ল্যাশ এবং র‌্যামে ডেটা থাকতে হবে" " আপনি যখন "এখানে র্যামের ডেটা" বলবেন, আপনি কি এই প্রোগ্রামটির সন্ধানে ডেটা জেনারেট করেছেন বোঝাতে চাইছেন? বা আপনি কি প্রাথমিক তথ্য অন্তর্ভুক্ত করবেন? মানে আমরা যখন রমটিতে কোড আপলোড করব তখনই আমাদের কোডটিতে ইতিমধ্যে ডেটা শুরু করা আছে। উদাহরণস্বরূপ আমাদের আউডে যদি থাকে: int x = 1; int y = x +1; উপরের কোডে নির্দেশাবলী রয়েছে এবং প্রাথমিক তথ্য রয়েছে যা ১ (x = 1)। এই ডেটাটি কি র‌্যামে অনুলিপি করে বা কেবল রমে থাকে।
ব্যবহারকারী 16307

13
হাহ, আমি এখন স্ট্যাক এক্সচেঞ্জ উত্তরের চরিত্রের সীমাটি জানি!
old_timer

2
আপনার নতুন বইগুলিতে এই জাতীয় ধারণাটি ব্যাখ্যা করে একটি বই লিখতে হবে। "
গিথুবে আমার জিলিয়ন

1
আমি করেছি. এমন কিছু নয় যা দরকারী কিছু করে তবে তবুও এটি একটি মাইক্রোকন্ট্রোলারের কোডের একটি উদাহরণ। এবং আমি একটি গিথব লিঙ্ক রেখেছি যা থেকে আপনি ভাগ করে নেওয়া, ভাল, খারাপ, বা অন্য কোনও কিছু আপনি পেতে পারেন।
old_timer

8

এই উত্তরটি বুট প্রক্রিয়াটিতে আরও ফোকাস করতে চলেছে। প্রথমত, একটি সংশোধন - এমসিইউ (বা এর কমপক্ষে কিছু অংশ) ইতিমধ্যে শুরু হওয়ার পরে ফ্ল্যাশ করতে লেখেন। কিছু এমসিইউতে (সাধারণত আরও উন্নততর) সিপিইউ নিজেই সিরিয়াল বন্দরগুলি পরিচালনা করতে পারে এবং ফ্ল্যাশ রেজিস্টারগুলিতে লিখতে পারে। সুতরাং প্রোগ্রাম লেখা এবং সম্পাদন করা বিভিন্ন প্রক্রিয়া। আমি ধরে নেব যে প্রোগ্রামটি ইতিমধ্যে ফ্ল্যাশ লিখিত হয়েছে।

এখানে বেসিক বুট প্রক্রিয়া। আমি কিছু সাধারণ প্রকরণের নাম দেব, তবে বেশিরভাগ ক্ষেত্রেই আমি এই সহজ রাখছি।

  1. রিসেট: দুটি মূল ধরণ রয়েছে। প্রথমটি পাওয়ার-অন রিসেট, যা সরবরাহের ভোল্টেজগুলি বাড়ানোর সময় অভ্যন্তরীণভাবে উত্পন্ন হয়। দ্বিতীয়টি একটি বাহ্যিক পিন টগল। নির্বিশেষে, পুনরায় সেট এমসইউতে সমস্ত ফ্লিপ-ফ্লপকে পূর্বনির্ধারিত অবস্থায় নিয়ে যায়।

  2. অতিরিক্ত হার্ডওয়্যার সূচনা: সিপিইউ চালু হওয়ার আগে অতিরিক্ত সময় এবং / অথবা ঘড়ির চক্রের প্রয়োজন হতে পারে। উদাহরণস্বরূপ, আমি যে টিআই এমসিইউগুলিতে কাজ করি সেগুলিতে একটি অভ্যন্তরীণ কনফিগারেশন স্ক্যান চেইন রয়েছে যা লোড হয়।

  3. সিপিইউ বুট: সিপিইউ তার প্রথম নির্দেশটি একটি বিশেষ ঠিকানা থেকে রিসেট ভেক্টর নামে ডেকে আনে। এই ঠিকানাটি সিপিইউ নকশা করা হলে নির্ধারিত হয়। সেখান থেকে, এটি কেবলমাত্র সাধারণ প্রোগ্রাম কার্যকর করা।

    সিপিইউ বারবার তিনটি মূল ধাপ পুনরাবৃত্তি করে:

    • আনুন: প্রোগ্রামের কাউন্টারে (পিসি) রেজিষ্টারে সঞ্চিত ঠিকানা থেকে একটি নির্দেশ (8-, 16- বা 32-বিট মান) পড়ুন , তারপরে পিসি বৃদ্ধি করুন।
    • ডিকোড: বাইনারি নির্দেশকে সিপিইউর অভ্যন্তরীণ নিয়ন্ত্রণ সংকেতগুলির মানগুলির একটি সংকেতে রূপান্তর করুন।
    • সম্পাদন করুন: নির্দেশনাটি সম্পাদন করুন - দুটি নিবন্ধ যুক্ত করুন, মেমরি থেকে পড়ুন বা লিখুন, শাখা (পিসি পরিবর্তন করুন), বা যাই হোক না কেন।

    (এটি আসলে এর চেয়ে জটিল। সিপিইউ সাধারণত হয় পাইপলাইনযুক্ত হয় , যার মানে তারা একই সময়ে বিভিন্ন নির্দেশাবলী উপরোক্ত ধাপগুলি প্রতিটি কাজ করা যেতে পারে। উপরোক্ত ধাপগুলি প্রত্যেকটি একাধিক পাইপলাইন পর্যায়ে থাকতে পারে। তারপর সেখানে সমান্তরাল পাইপলাইনগুলি, শাখা ভবিষ্যদ্বাণী , এবং সমস্ত অভিনব কম্পিউটার আর্কিটেকচার স্টাফ যা সেই সমস্ত ইন্টেল সিপিইউগুলি ডিজাইন করতে বিলিয়ন ট্রানজিস্টর গ্রহণ করে)

    আপনি হয়ত ভাবছেন যে আনয়ন কীভাবে কাজ করে। সিপিইউতে ক বাস রয়েছে রয়েছে যেখানে ঠিকানা (আউট) এবং ডেটা (ইন / আউট) সংকেত রয়েছে। আনার জন্য, সিপিইউ তার ঠিকানা লাইনগুলি প্রোগ্রামের কাউন্টারে মান হিসাবে সেট করে, তারপরে বাসের উপর একটি ঘড়ি প্রেরণ করে। ঠিকানাটি একটি মেমোরি সক্ষম করতে ডিকোড করা হয়েছে। মেমরিটি ঘড়ি এবং ঠিকানা গ্রহণ করে এবং সেই ঠিকানায় ডেটা লাইনে মান রাখে। সিপিইউ এই মানটি গ্রহণ করে। তথ্য পঠন এবং লেখাগুলি একই রকম হয়, কেবল ঠিকানাটি নির্দেশনা থেকে আসে বা কোনও সাধারণ-উদ্দেশ্যে নিবন্ধের মান হয়, পিসি নয় not

    ভন নিউমান আর্কিটেকচার সহ সিপিইউতে একটি একক বাস রয়েছে যা নির্দেশাবলী এবং ডেটা উভয়ের জন্যই ব্যবহৃত হয়। হার্ভার্ড আর্কিটেকচার সহ সিপিইউ নির্দেশনার জন্য একটি বাস এবং ডেটার জন্য have প্রকৃত এমসিইউগুলিতে, এই দুটি বাসই একই স্মৃতির সাথে সংযুক্ত থাকতে পারে, তাই এটি প্রায়শই (তবে সর্বদা নয়) এমন কোনও বিষয় যা আপনাকে উদ্বিগ্ন হতে হবে না।

    বুট প্রক্রিয়া ফিরে। পুনরায় সেট করার পরে, পিসি রিসেট ভেক্টর নামে একটি প্রারম্ভিক মান দিয়ে লোড করা হয় এটি হার্ডওয়্যারটিতে তৈরি করা যেতে পারে, বা (এআরএম কর্টেক্স-এম সিপিইউগুলিতে) এটি স্বয়ংক্রিয়ভাবে মেমরির বাইরে পড়তে পারে। সিপিইউ রিসেট ভেক্টর থেকে নির্দেশিকাটি নিয়ে আসে এবং উপরের পদক্ষেপগুলির মধ্য দিয়ে লুপিং শুরু করে। এই মুহুর্তে, সিপিইউ স্বাভাবিকভাবে সম্পাদন করছে।

  4. বুট লোডার: প্রায়শই বেশিরভাগ নিম্ন-স্তরের সেটআপ থাকে যা বাকি এমসইউ চালিত করার জন্য করা দরকার। এটিতে এনালগ উপাদানগুলির জন্য র‌্যামগুলি সাফ করা এবং উত্পাদন ট্রিম সেটিংস লোড করার মতো জিনিস অন্তর্ভুক্ত থাকতে পারে। বাহ্যিক উত্স থেকে সিরিয়াল পোর্ট বা বাহ্যিক মেমরির মতো কোড লোড করার বিকল্পও থাকতে পারে। এমসিইউতে একটি বুট রম অন্তর্ভুক্ত থাকতে পারে যাতে এই কাজগুলি করার জন্য একটি ছোট প্রোগ্রাম থাকে। এই ক্ষেত্রে, সিপিইউ রিসেট ভেক্টর বুট রমের ঠিকানা স্পেসের দিকে নির্দেশ করে। এটি মূলত একটি সাধারণ কোড, এটি কেবল প্রস্তুতকারকের দ্বারা সরবরাহ করা হয় যাতে আপনার নিজের এটি লিখতে হবে না। :-) একটি পিসিতে, BIOS বুট রমের সমতুল্য।

  5. সি এনভায়রনমেন্ট সেটআপ: সি গ্লোবাল ভেরিয়েবলের জন্য স্ট্যাক (ফাংশন কলের সময় স্টোরেজ স্টেটের জন্য র‌্যাম এরিয়া) এবং ইনিশিয়ালাইজড মেমোরি অবস্থানের প্রত্যাশা করে । এগুলি হল। স্ট্যাক, .ডাটা এবং .bss বিভাগ যা দলেভ কথা বলছে। আরম্ভ করা গ্লোবাল ভেরিয়েবলগুলির এই প্রারম্ভিক মানগুলি ফ্ল্যাশ থেকে র‌্যামে অনুলিপি করা হয়েছে step একীকরণবিহীন গ্লোবাল ভেরিয়েবলগুলির র‍্যাম ঠিকানা রয়েছে যা একত্রে কাছাকাছি রয়েছে, সুতরাং মেমরির পুরো ব্লকটি খুব সহজেই শূন্যে আরম্ভ করা যায়। স্ট্যাকটি আরম্ভ করার দরকার নেই (যদিও এটি হতে পারে) - আপনাকে যা করতে হবে তা হল সিপিইউর স্ট্যাক পয়েন্টার রেজিস্ট্রার সেট করা যাতে এটি র‌্যামের একটি নির্ধারিত অঞ্চলে নির্দেশ করে।

  6. প্রধান ফাংশন : একবার সি পরিবেশ তৈরি হয়ে গেলে, সি লোডার মূল () ফাংশনটি কল করে। এখান থেকে আপনার অ্যাপ্লিকেশন কোডটি সাধারণত শুরু হয়। আপনি যদি চান তবে আপনি স্ট্যান্ডার্ড লাইব্রেরিটি ছেড়ে দিতে পারেন, সি এনভায়রনমেন্ট সেটআপটি এড়িয়ে যেতে পারেন এবং মেইন () এ কল করতে নিজের কোড লিখতে পারেন। কিছু এমসিইউ আপনাকে নিজের বুট লোডার লিখতে দেয় এবং তারপরে আপনি নিজেরাই নিম্ন-স্তরের সমস্ত সেটআপ করতে পারেন।

বিবিধ জিনিস: অনেকগুলি এমসিইউ আপনাকে আরও ভাল পারফরম্যান্সের জন্য র‌্যামের বাইরে কোড চালায়। এটি সাধারণত লিংক কনফিগারেশনে সেট আপ হয়। লিঙ্কার প্রতিটি ফাংশনে দুটি ঠিকানা বরাদ্দ করে - একটি লোড ঠিকানা , যা এখানে কোডটি প্রথমে সঞ্চিত হয় (সাধারণত ফ্ল্যাশ), এবং একটি রান ঠিকানা , যা ফাংশন (ফ্ল্যাশ বা র‌্যাম) চালানোর জন্য পিসিতে লোড করা ঠিকানা। র‌্যামের বাইরে কোড চালিয়ে যাওয়ার জন্য, আপনি সিপিইউটিকে তার লোড ঠিকানা থেকে ফাংশন কোডটি ফ্ল্যাশ করে র‌্যামের তার রান ঠিকানায় অনুলিপি করতে কোড লিখবেন, তারপরে রান ঠিকানায় ফাংশনটি কল করুন। লিঙ্কার এটির সাহায্যে গ্লোবাল ভেরিয়েবলগুলি সংজ্ঞায়িত করতে পারে। তবে এমসইউগুলিতে র‌্যামের বাইরে কোড কার্যকর করা alচ্ছিক। আপনি যদি সাধারণত উচ্চতর পারফরম্যান্সের প্রয়োজন হয় বা আপনি যদি ফ্ল্যাশটি আবার লিখতে চান তবে আপনি সাধারণত এটি করতে পারেন।


1

ভন নিউম্যান আর্কিটেকচারের জন্য আপনার সারাংশ প্রায় সঠিক । প্রাথমিক কোডটি সাধারণত বুটলোডারের মাধ্যমে র‌্যামে লোড করা হয়, তবে (সাধারণত) কোনও সফ্টওয়্যার বুটলোডার নয় যা শব্দটি সাধারণত বোঝায়। এটি সাধারণত 'সিলিকনে বেকড' আচরণ is এই আর্কিটেকচারে কোড এক্সিকিউশনটি প্রায়শই রম থেকে একটি ভবিষ্যদ্বাণীমূলক ক্যাশিং নির্দেশাবলী জড়িত থাকে যাতে প্রসেসর কোডটি কার্যকর করতে তার সময়কে সর্বাধিক করে তোলে এবং কোডটি র‍্যামে লোড হওয়ার জন্য অপেক্ষা না করে। আমি কোথাও পড়েছি যে এমএসপি 430 এই স্থাপত্যের উদাহরণ।

এ-তে হার্ভার্ড আর্কিটেকচার ডিভাইসে, নির্দেশাবলী সরাসরি রম থেকে কার্যকর করা হয় যখন ডেটা মেমোরি (র‌্যাম) পৃথক বাসের মাধ্যমে অ্যাক্সেস করা হয়। এই স্থাপত্যে, কোডটি সহজেই রিসেট ভেক্টর থেকে চালানো শুরু করে। PIC24 এবং dsPIC33 এই স্থাপত্যের উদাহরণ।

বিটগুলির প্রকৃত উল্টাপাল্টা যা এই প্রক্রিয়াগুলিকে বন্ধ করে দেয়, এটি ডিভাইস-থেকে-ডিভাইসে পরিবর্তিত হতে পারে এবং ডিবাগার, জেটিএইচ, মালিকানাধীন পদ্ধতি ইত্যাদি জড়িত থাকতে পারে


তবে আপনি কিছু পয়েন্ট দ্রুত এড়িয়ে যাচ্ছেন। এটি ধীর গতিতে নিতে দেয়। আসুন বলুন বাইনারি কোড "প্রথম" রমকে লেখা আছে। ঠিক আছে .. এর পরে আপনি লিখুন "ডেটা মেমরি অ্যাক্সেস করা হয়" .... তবে "র‌্যামে" ডেটা প্রথম থেকে কোথা থেকে আসে? এটি কি আবার রম থেকে আসে? এবং যদি তা হয় তবে বুট-লোডার কীভাবে জানতে পারে যে রমের শুরুতে রমের কোনও অংশটি লেখা হবে?
ব্যবহারকারী 16307

আপনি ঠিক বলেছেন, আমি প্রচুর পরিমাণে এড়িয়ে গেছি। অন্য ছেলেদের আরও ভাল উত্তর আছে। আমি খুশি যে আপনি যা খুঁজছিলেন তা পেয়েছেন।
সামান্য
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.