GCC -fPIC বিকল্প


437

আমি কোড জেনারেশন কনভেনশনগুলির জন্য জিসিসির বিকল্পগুলি সম্পর্কে পড়েছি , তবে বুঝতে পারি না যে "জেনারেট পজিশন-ইন্ডিপেন্ডেন্ট কোড (পিআইসি)" কী করে। এর অর্থ কী তা বোঝাতে দয়া করে একটি উদাহরণ দিন।


25
ঝাঁকুনি -fPIC ব্যবহার করে।
গেছে

উত্তর:


526

পজিশন ইন্ডিপেন্ডেন্ট কোডের অর্থ হ'ল উত্পন্ন মেশিন কোডটি কাজ করার জন্য কোনও নির্দিষ্ট ঠিকানায় অবস্থিত হওয়ার উপর নির্ভর করে না।

যেমন জাম্পগুলি পরম হওয়ার চেয়ে আপেক্ষিক হিসাবে উত্পন্ন হত।

সিউডো-সমাবেশ:

PIC: কোডটি 100 বা 1000 এর ঠিকানায় ছিল কিনা এটি কাজ করবে

100: COMPARE REG1, REG2
101: JUMP_IF_EQUAL CURRENT+10
...
111: NOP

নন-পিক: কোডটি 100 এর ঠিকানায় থাকলে এটি কাজ করবে

100: COMPARE REG1, REG2
101: JUMP_IF_EQUAL 111
...
111: NOP

সম্পাদনা: মন্তব্য প্রতিক্রিয়া।

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


36
এই উদাহরণটি স্পষ্ট, তবে ব্যবহারকারী হিসাবে যদি আমি বিকল্পটি না দিয়ে ভাগ করে নেওয়া ল্যাব্রারি (.so) ফাইল তৈরি করি তবে তার পার্থক্য কী হবে? এমন কি কিছু ঘটনা রয়েছে যা -fPIC ব্যতীত আমার লিবটি অবৈধ হবে?
নেরেক

16
হ্যাঁ, একটি ভাগ করা লাইব্রেরি তৈরি করা যা PIC নয় ত্রুটি হতে পারে।
জন জুইনক

92
আরও সুনির্দিষ্টভাবে বলতে গেলে, ভাগ করা লাইব্রেরিটি প্রক্রিয়াগুলির মধ্যে ভাগ হওয়ার কথা, তবে উভয় ক্ষেত্রে একই ঠিকানায় গ্রন্থাগারটি লোড করা সর্বদা সম্ভব নাও হতে পারে। কোডটি যদি অবস্থানটি স্বতন্ত্র না থাকে তবে প্রতিটি প্রক্রিয়াটির নিজস্ব অনুলিপি প্রয়োজন।
সাইমন রিখটার

19
@ নেরেক: যদি কোনও প্রক্রিয়া একই ভার্চুয়াল ঠিকানায় একাধিক ভাগ ভাগ করা লাইব্রেরি লোড করতে চায় তবে ত্রুটি ঘটে। যেহেতু গ্রন্থাগারগুলি ভবিষ্যদ্বাণী করতে পারে না যে অন্যান্য গ্রন্থাগারগুলি লোড করা যায়, তাই এই সমস্যাটি traditionalতিহ্যবাহী ভাগ করা লাইব্রেরি ধারণার সাথে অনিবার্য। ভার্চুয়াল ঠিকানার স্থান এখানে সহায়তা করে না।
ফিলিপ

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

61

ইতিমধ্যে যা বলা হয়েছে তা সহজ পদ্ধতিতে ব্যাখ্যা করার চেষ্টা করব।

যখনই কোনও ভাগ করা lib লোড হয়, তখন লোডারটি (ওএসের কোড যা আপনার দ্বারা চালিত কোনও প্রোগ্রাম লোড করে) কোডটিতে কিছু ঠিকানা পরিবর্তন করে যেখানে অবজেক্টটি লোড হয়েছিল on

উপরের উদাহরণে, নন-পিআইসি কোডে "111" লোডার দ্বারা প্রথমবার এটি লোড করা হয়েছিল।

ভাগ না করা অবজেক্টের জন্য, আপনি এটি এর মতো হতে চাইতে পারেন কারণ সংকলক সেই কোডটিতে কিছু অপ্টিমাইজেশন করতে পারে।

ভাগ করা অবজেক্টের জন্য, অন্য কোনও প্রক্রিয়া যদি সেই কোডটির সাথে "লিঙ্ক" করতে চায় তবে তাকে অবশ্যই এটি একই ভার্চুয়াল ঠিকানায় পড়তে হবে বা "111" কোনও অর্থ দেবে না। তবে সেই ভার্চুয়াল-স্পেসটি ইতিমধ্যে দ্বিতীয় প্রক্রিয়াতে ব্যবহৃত হতে পারে।


Whenever a shared lib is loaded, the loader changes some addresses in the code depending on where the object was loaded to.আমি মনে করি যে -ফপিক এবং সংস্থার কারণে -fpic কেন সংঘটিত হয়েছে তা সঠিক নয় অর্থাত্ পারফরম্যান্সের কারণে বা আপনার যদি এমন একটি লোডার রয়েছে যা স্থানান্তরিত করতে সক্ষম হয় না বা আপনাকে বিভিন্ন স্থানে একাধিক অনুলিপি বা আরও অনেক কারণে প্রয়োজন হয়।
রোবসন

সর্বদা -ফিক ব্যবহার করবেন না কেন?
জে

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

45

ভাগ করা লাইব্রেরিতে অন্তর্নির্মিত কোডটি সাধারণত অবস্থান-স্বতন্ত্র কোড হওয়া উচিত, যাতে ভাগ করা লাইব্রেরি সহজেই মেমরির কোনও ঠিকানায় (কম-বেশি) লোড করা যায়। -fPICবিকল্প নিশ্চিত করে যে জিসিসি যেমন কোড উৎপন্ন হয়।


একটি ভাগ করা লাইব্রেরিটি -fPICপতাকা না রেখে মেমরির কোনও ঠিকানায় লোড করা হবে না কেন ? এটি কি প্রোগ্রামের সাথে যুক্ত নয়? যখন প্রোগ্রামটি চলছে, অপারেটিং সিস্টেম এটিকে মেমোরিতে আপলোড করে। আমি কিছু অনুপস্থিত করছি?
টনি ট্যানুস

1
হয় -fPICপতাকা, ব্যবহৃত এই liberal এর সংক্ষিপ্ত রূপ কোন লোড করা যাবে তা নিশ্চিত করার জন্য ভার্চুয়াল অ্যাড্রেস প্রক্রিয়া হয় যে লিঙ্ক আছে? দ্বিগুণ মন্তব্যের জন্য দুঃখিত 5 মিনিট অতিবাহিত পূর্বের কোনওটি সম্পাদনা করতে পারে না।
টনি ট্যানুস

1
ভাগ করা লাইব্রেরি তৈরি করা (এটি তৈরি করা libwotnot.so) এবং এর সাথে লিঙ্ক করার মধ্যে পার্থক্য করুন ( -lwotnot)। লিঙ্ক করার সময়, আপনার সম্পর্কে ঝগড়া করার দরকার নেই -fPIC। এটি এমন ক্ষেত্রে ব্যবহৃত হত যে ভাগ করা লাইব্রেরিটি তৈরি করার সময়, আপনাকে অবশ্যই নিশ্চিত করতে হবে যে -fPICসমস্ত অবজেক্ট ফাইলগুলি ভাগ করে নেওয়া লাইব্রেরিতে তৈরি করা যেতে পারে। বিধিগুলি পরিবর্তিত হতে পারে কারণ আজকাল পিক কোডগুলি ডিফল্টরূপে সংকলকগণ তৈরি করে। সুতরাং, 20 বছর আগে যা গুরুত্বপূর্ণ ছিল এবং 7 বছর আগে এটি গুরুত্বপূর্ণ ছিল আজকের দিনগুলিতে কম গুরুত্বপূর্ণ, আমি বিশ্বাস করি। O / s কার্নেলের বাইরে ঠিকানাগুলি 'সর্বদা' ভার্চুয়াল ঠিকানাগুলি।
জোনাথন লেফলার

সুতরাং আগে আপনি যোগ করতে হবে -fPIC। এই পতাকাটি পাস না করে।। নির্মাণের সময় উত্পন্ন কোডটি ব্যবহৃত হতে পারে এমন নির্দিষ্ট ভার্চুয়াল ঠিকানাগুলিতে লোড করা দরকার?
টনি ট্যাননস

1
হ্যাঁ, কারণ আপনি যদি পিআইসি পতাকা ব্যবহার না করেন, কোডটি নির্ভরযোগ্যভাবে স্থানান্তরযোগ্য ছিল না। কোডটি পিক না হলে (বা স্থান অন্তত, এতটা কঠিন যে এগুলি কার্যকরভাবে অসম্ভব) যদি এএসএলআর (অ্যাড্রেস স্পেস লেআউট র্যান্ডমাইজেশন) এর মতো জিনিসগুলি সম্ভব হয় না।
জোনাথন লেফলার

21

আরও যুক্ত করা হচ্ছে ...

প্রতিটি প্রক্রিয়াতে একই ভার্চুয়াল ঠিকানার স্থান থাকে (যদি লিনাক্স ওএসে একটি পতাকা ব্যবহার করে ভার্চুয়াল ঠিকানার র্যান্ডমাইজেশন বন্ধ করা হয়) (আরও তথ্যের জন্য কেবলমাত্র নিজের জন্য ঠিকানা স্থানের বিন্যাসটি অক্ষম করুন এবং পুনরায় সক্ষম করুন )

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

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

সুতরাং একটি প্রক্রিয়া তার নিজস্ব ভার্চুয়াল স্পেসে 0x45678910 হিসাবে একই সূচনা ঠিকানা দিতে পারে এবং একই সময়ে অন্যান্য প্রক্রিয়া 0x12131415 এর সূচনা ঠিকানা দিতে পারে এবং যদি তারা আপেক্ষিক ঠিকানা ব্যবহার না করে তবে। কিছুতেই কাজ করবে না।

সুতরাং তাদের সর্বদা আপেক্ষিক ঠিকানার মোড ব্যবহার করতে হবে এবং তাই এফপিক বিকল্পটি।


1
ভার্চুয়াল অ্যাডারের ব্যাখ্যার জন্য ধন্যবাদ।
হট.পেক্সএল

2
এটি কীভাবে ব্যাখ্যা করতে পারে যে এটি স্ট্যাটিক লাইব্রেরিতে কীভাবে সমস্যা নয়, কেন আপনাকে স্ট্যাটিক লাইব্রেরিতে -fPIC ব্যবহার করতে হবে না? আমি বুঝতে পারি যে লিঙ্কিংটি সংকলন সময়ে করা হয় (বা আসলে আসার পরে), তবে আপনার যদি অবস্থান নির্ভর কোড সহ 2 টি স্ট্যাটিক লাইব্রেরি থাকে তবে সেগুলি কীভাবে যুক্ত হবে?
মাইকেল পি

3
@ মিশেলপ অবজেক্ট ফাইলের অবস্থানের উপর নির্ভরশীল লেবেলের একটি টেবিল রয়েছে এবং যখন নির্দিষ্ট ওজেক্ট ফাইলটি সংযুক্ত করা হয় তখন সমস্ত লেবেল সেই অনুযায়ী আপডেট করা হয়। ভাগ করা লাইব্রেরিতে এটি করা যাবে না।
স্লাভা

16

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


এই সমস্যাটি মোকাবেলার জন্য দুটি ব্যবহৃত পদ্ধতি রয়েছে:

1.Relocation। কোডের সমস্ত পয়েন্টার এবং ঠিকানাগুলি আসল লোড ঠিকানাটি ফিট করার জন্য, প্রয়োজনে সংশোধিত হয়। রিলোকেশন লিঙ্কার এবং লোডার দ্বারা সম্পন্ন হয়।

2. অবস্থান-স্বাধীন কোড। কোডে সমস্ত ঠিকানা বর্তমান অবস্থানের তুলনায়। ইউনিক্সের মতো সিস্টেমে ভাগ করা অবজেক্টগুলি ডিফল্টরূপে অবস্থান-স্বতন্ত্র কোড ব্যবহার করে। প্রোগ্রামটি যদি দীর্ঘকাল ধরে চালিত হয় তবে বিশেষত 32-বিট মোডে স্থান পরিবর্তন করার চেয়ে কম দক্ষ।


" অবস্থান-স্বতন্ত্র কোড " নামটি নিম্নলিখিতটি বোঝায়:

  • কোড বিভাগে এমন কোনও নিখুঁত ঠিকানা নেই যা স্থানান্তরের প্রয়োজন, তবে কেবল স্ব স্ব সম্পর্কিত ঠিকানা। অতএব, কোড বিভাগটি একটি স্বেচ্ছাসেবী মেমরি ঠিকানায় লোড করা যায় এবং একাধিক প্রক্রিয়ার মধ্যে ভাগ করা যায়।

  • ডেটা বিভাগটি একাধিক প্রক্রিয়ার মধ্যে ভাগ করা হয় না কারণ এটি প্রায়শই লেখার উপযোগী ডেটা থাকে। সুতরাং, ডেটা বিভাগে পয়েন্টার বা ঠিকানা থাকতে পারে যাতে স্থানান্তর প্রয়োজন।

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


এই তথাকথিত প্রতীক ইন্টারপজিশন স্থির গ্রন্থাগারগুলির আচরণ নকল করার উদ্দেশ্যে তৈরি করা হয়েছে।

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

পিএস যেখানে ডায়নামিক লিঙ্কিং এড়ানো যায় না, সেখানে অবস্থান-স্বতন্ত্র কোডের সময়সীমীকরণ বৈশিষ্ট্যগুলি এড়ানোর বিভিন্ন উপায় রয়েছে।

আপনি এই নিবন্ধটি থেকে আরও পড়তে পারেন: http://www.agner.org/optimize/optimizing_cpp.pdf


9

ইতিমধ্যে পোস্ট করা উত্তরের একটি সামান্য সংযোজন: অবস্থানের স্বাধীন হতে সংকলিত অবজেক্ট ফাইলগুলি স্থানান্তরযোগ্য; এগুলিতে স্থানান্তর টেবিল এন্ট্রি রয়েছে।

এই এন্ট্রিগুলি ভার্চুয়াল অ্যাড্রেস স্পেসের প্রকৃত লোড ঠিকানার জন্য সামঞ্জস্য করতে লোডারকে (কোডের একটি বিট যা কোনও প্রোগ্রামকে মেমোরিতে লোড করে) পরম ঠিকানাগুলি পুনরায় লেখার অনুমতি দেয়।

অপারেটিং সিস্টেম সেই একই অংশীদারি অবজেক্ট লাইব্রেরির সাথে লিঙ্কযুক্ত সমস্ত প্রোগ্রামের সাথে মেমরিতে লোড করা "ভাগ করা অবজেক্ট লাইব্রেরি" এর একটি কপি ভাগ করার চেষ্টা করবে।

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

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

যেহেতু মূল প্রোগ্রামের মূল অংশ থেকে এই পাঠাগারগুলিতে কলগুলি স্থানান্তরযোগ্য করে তোলা হবে, তাই এটি একটি ভাগ করা লাইব্রেরি অনুলিপি করার সম্ভাবনা খুব কম করে তোলে।

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