সি-তে স্টার্ট () ব্যবহার কী?


125

আমি আমার সহকর্মীর কাছ থেকে শিখেছি যে কোনও main()ফাংশন না লিখেই কোনও সি প্রোগ্রাম লিখতে এবং সম্পাদন করতে পারে। এটি এইভাবে করা যেতে পারে:

my_main.c

/* Compile this with gcc -nostartfiles */

#include <stdlib.h>

void _start() {
  int ret = my_main();
  exit(ret); 
}

int my_main() {
  puts("This is a program without a main() function!");
  return 0; 
}

এটি এই আদেশের সাথে সংকলন করুন:

gcc -o my_main my_main.c nostartfiles

এই আদেশ দিয়ে এটি চালান:

./my_main

এই ধরণের জিনিসটি কখন করা দরকার? এমন কোনও বাস্তব বিশ্বের দৃশ্যপট আছে যেখানে এটি কার্যকর হবে?


1
দূরবর্তীভাবে সম্পর্কিত: স্ট্যাকওভারফ্লো
মোহিত জৈন

7
ক্লাসিক নিবন্ধ যা প্রোগ্রামগুলি কীভাবে শুরু হয় তার কিছু অভ্যন্তরীণ কার্যকারিতা প্রদর্শন করে: লিনাক্সের জন্য সত্যই টেনেসি ইএলএফ এক্সিকিউটেবল তৈরির বিষয়ে একটি ঘূর্ণি টিউটোরিয়াল । এটি একটি ভাল পঠন যা এর সূক্ষ্ম বিন্দুগুলির _start()বাইরে এবং এর বাইরে অন্যান্য স্টাফ নিয়ে আলোচনা করে main()

1
সি ভাষা নিজেই _startবা অন্য কোনও প্রবেশ পয়েন্ট সম্পর্কে কিছুই বলে না main(এন্ট্রি পয়েন্টের নামটি फ्रीস্ট্যান্ডিং (এম্বেডেড) বাস্তবায়নের জন্য বাস্তবায়ন-সংজ্ঞায়িত)।
কিথ থম্পসন

উত্তর:


107

প্রতীকটি _startহল আপনার প্রোগ্রামের প্রবেশের স্থান point অর্থাৎ, সেই প্রতীকটির ঠিকানা হ'ল ঠিকানাটি প্রোগ্রামের শুরুতে লাফিয়ে। সাধারণত, নামের সাথে ফাংশনটি _startএমন একটি ফাইল দ্বারা সরবরাহ করা হয় crt0.oযার নাম সি রানটাইম পরিবেশের জন্য স্টার্টআপ কোড থাকে। এটি কিছু স্টাফ সেট আপ করে, আর্গুমেন্ট অ্যারেকে পপুলেট করে argv, সেখানে কত আর্গুমেন্ট রয়েছে তা গণনা করে এবং তারপরে কল করে mainmainরিটার্ন পরে exitবলা হয়।

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


2
আর একটি উদাহরণ লিনাক্সের গতিশীল লিংক / লোডার যার নিজস্ব _ স্টার্ট সংজ্ঞায়িত হয়েছে।
পিপি

2
@ ব্লুমুন তবে _startএটি অবজেক্ট ফাইল থেকেও আসে crt0.o
ফুজ

2
@ থমাস ম্যাথিউজ মানটি নির্দিষ্ট করে না _start; প্রকৃতপক্ষে, এটি নির্দিষ্ট করা হয় না যা আগে ঘটেছিল mainএকেবারে বলা হয়েছিল, এটি কেবল নির্দিষ্ট করার পরে যখন mainডাকা হয় তখন কী শর্ত পূরণ করতে হবে তা নির্দিষ্ট করে । এটি _startপুরানো দিনের পুরানো তারিখের পয়েন্টের জন্য আরও অধিবেশন ।
ফুজ

1
"গো প্রোগ্রামিং ল্যাঙ্গুয়েজের রেফারেন্স বাস্তবায়ন তাই করে কারণ তাদের একটি অ-মানক থ্রেডিং মডেল প্রয়োজন" crt0.o সি নির্দিষ্ট (crt-> সি রানটাইম)। এটি অন্য কোনও ভাষার জন্য ব্যবহার করা হবে বলে আশা করার কোনও কারণ নেই। এবং গো এর থ্রেডিং মডেলটি সম্পূর্ণ মান সম্মত
স্টিভ কক্স

8
@ স্টিভকক্স অনেকগুলি প্রোগ্রামিং ল্যাঙ্গুয়েজ সি রানটাইমের শীর্ষে নির্মিত কারণ ভাষাগুলিকে এভাবে প্রয়োগ করা সহজ। গো সাধারণ থ্রেডিং মডেল ব্যবহার করে না। তারা ছোট, গাদা-বরাদ্দ স্ট্যাক এবং তাদের নিজস্ব শিডিয়ুলার ব্যবহার করে। এটি অবশ্যই একটি আদর্শ থ্রেডিং মডেল নয়।
ফুজ

45

যদিও mainএকটি প্রোগ্রামারদের দৃষ্টিকোণ থেকে আপনার প্রোগ্রামের জন্য এন্ট্রি পয়েন্ট হয়, _startঅপারেটিং সিস্টেম দৃষ্টিকোণ (প্রথম নির্দেশ যে আপনার প্রোগ্রাম ওএস থেকে শুরু পর কার্যকর) থেকে স্বাভাবিক এন্ট্রি পয়েন্ট হয়

একটি সাধারণ সি এবং বিশেষত সি ++ প্রোগ্রামে ফাঁসির মূল প্রবেশের আগে প্রচুর কাজ করা হয়েছিল। বিশেষত গ্লোবাল ভেরিয়েবলের সূচনা করার মতো স্টাফ। এখানে আপনি যা শুরু করছেন তার মধ্যে _start()এবং main()প্রধানটি আবার বেরিয়ে আসার পরেও নীচের মন্তব্য দেখুন) এর ভাল ব্যাখ্যা পেতে পারেন ।
এর জন্য প্রয়োজনীয় কোডটি সাধারণত একটি স্টার্টআপ ফাইলটিতে সংকলক লেখকরা সরবরাহ করেন তবে পতাকাটির সাহায্যে –nostartfilesআপনি মূলত সংকলকটি বলে: "আমাকে স্ট্যান্ডার্ড স্টার্টআপ ফাইল দেওয়ার জন্য বিরক্ত করবেন না, ঠিক কী ঘটছে তার উপর আমাকে সম্পূর্ণ নিয়ন্ত্রণ দিন give শুরু "।

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


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

@ শায়রন: দুঃখিত, আমার পিসি সি ++ তে, বৈশ্বিক ভেরিয়েবলগুলি প্রায়শই একটি নির্মাণকারী দ্বারা শুরু করা হয় যা ভিতরে চালিত হয় _start()(বা আসলে এটির নামে পরিচিত অন্য কোনও ফাংশন) এবং অনেকগুলি বেয়ার-মেটাল-প্রোগ্রামে আপনি স্পষ্টত সমস্ত গ্লোবাল ডেটা ফ্ল্যাশ থেকে র্যামে অনুলিপি করেন প্রথমটি, যা এটিতে ঘটেছিল _start(), তবে এই প্রশ্নটি সি ++ বা বেয়ার-মেটাল কোড সম্পর্কে নয়।
মাইক এমবি

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

@zwol এটি কেবল আংশিকভাবে সঠিক। উদাহরণস্বরূপ, এই জাতীয় ফাংশন মেমরি বরাদ্দ করতে পারে। অভ্যন্তরীণ ডেটা স্ট্রাকচারগুলি mallocআরম্ভ না করা হলে মেমরি বরাদ্দ করা সমস্যাযুক্ত ।
ফুজ

1
@FUZxxl যে বলেন, আমি ASYNC-সংকেত-নিরাপদ ফাংশন লক্ষ্য করছে সংশোধন করার অনুমতি দেওয়া errno(যেমন readএবং writeASYNC-সংকেত-নিরাপদ ও সেট করতে পারেন errno) এবং বোধগম্যভাবেই ঠিক উপর নির্ভর করে একটি সমস্যা প্রতি থ্রেড হতে পারে errnoঅবস্থান বরাদ্দ করা হয় ।
zwol

2

প্রোগ্রাম শুরুর আগে কী ঘটেছিল তার একটি ভাল ওভারভিউ এখানেmain । বিশেষ করে, এটা দেখায় যে __startহয় প্রকৃত এন্ট্রি পয়েন্ট ওএস দৃষ্টিকোণ থেকে আপনার প্রোগ্রাম।

এটিই প্রথম ঠিকানা যা থেকে আপনার প্রোগ্রামে নির্দেশিকা পয়েন্টার গণনা শুরু করবে।

সেখানকার কোডটি কিছু সি রানটাইম লাইব্রেরি রুটিনকে কেবল কিছু বাড়ির রক্ষণাবেক্ষণের জন্য অনুরোধ করে, তারপরে আপনার কল করুন mainএবং তারপরে জিনিসগুলি নামিয়ে আনুন এবং যে exitকোনও প্রস্থান কোড mainফিরে আসবে তার সাথে কল করুন ।


একটি ছবি হাজার শব্দের সমান:

সি রানটাইম স্টার্টআপ ডায়াগ্রাম


পিএস: এই উত্তরটি অন্য একটি প্রশ্ন থেকে প্রতিস্থাপন করা হয়েছে যা এসও এই প্রশ্নের সদৃশ হিসাবে সহায়কভাবে বন্ধ করেছে has


দুর্দান্ত বিশ্লেষণ এবং সুন্দর চিত্র সংরক্ষণের জন্য ক্রস পোস্ট করা ।
ulidtko

1

এই ধরণের জিনিসটি কখন করা দরকার?

আপনি যখন নিজের প্রোগ্রামটির জন্য নিজের স্টার্টআপ কোডটি চান।

mainকোনও সি প্রোগ্রামের _startপ্রথম প্রবেশ নয়, পর্দার আড়ালে প্রথম প্রবেশ।

লিনাক্স উদাহরণ:

_start: # _start is the entry point known to the linker
    xor %ebp, %ebp            # effectively RBP := 0, mark the end of stack frames
    mov (%rsp), %edi          # get argc from the stack (implicitly zero-extended to 64-bit)
    lea 8(%rsp), %rsi         # take the address of argv from the stack
    lea 16(%rsp,%rdi,8), %rdx # take the address of envp from the stack
    xor %eax, %eax            # per ABI and compatibility with icc
    call main                 # %edi, %rsi, %rdx are the three args (of which first two are C standard) to main

    mov %eax, %edi    # transfer the return of main to the first argument of _exit
    xor %eax, %eax    # per ABI and compatibility with icc
    call _exit        # terminate the program

এমন কোনও বাস্তব বিশ্বের দৃশ্যপট আছে যেখানে এটি কার্যকর হবে?

আপনি যদি বলতে চান তবে আমাদের নিজস্বটি প্রয়োগ করুন _start:

হ্যাঁ, আমি বেশিরভাগ বাণিজ্যিক এমবেডেড সফ্টওয়্যার নিয়ে কাজ করেছি যার মধ্যে আমাদের _startআমাদের নির্দিষ্ট মেমরি এবং কর্মক্ষমতা প্রয়োজনীয়তার সাথে সম্পর্কিত নিজস্ব প্রয়োগ করতে হবে।

যদি আপনি বোঝাতে চান তবে mainফাংশনটি ফেলে দিন এবং এটিকে অন্য কোনওটিতে পরিবর্তন করুন:

না, আমি এটি করে কোনও লাভ দেখছি না।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.