লিঙ্কাররা কী করবে?


127

আমি সবসময় ভাবতাম। আমি জানি যে সংকলকগণ আপনার লেখার কোডটিকে বাইনারিগুলিতে রূপান্তর করে তবে লিঙ্কাররা কী করে? তারা সবসময় আমার কাছে রহস্য হয়ে আছে।

'লিঙ্কিং' কী তা আমি প্রায় বুঝতে পারি understand এটি তখনই যখন বাইনারিটিতে লাইব্রেরি এবং ফ্রেমওয়ার্কের উল্লেখ যুক্ত হয়। আমি এর বাইরে কিছুই বুঝতে পারছি না। আমার জন্য এটি "স্রেফ কাজ করে"। আমি গতিশীল সংযোগের বুনিয়াদি বুঝতে পারি তবে খুব গভীর কিছু না।

কেউ কি শর্তাবলী ব্যাখ্যা করতে পারে?

উত্তর:


160

লিঙ্কারগুলি বোঝার জন্য, আপনি যখন কোনও উত্স ফাইলকে (যেমন সি বা সি ++ ফাইল হিসাবে) এক্সিকিউটেবল ফাইলে রূপান্তর করেন তখন একটি হুডের নীচে কী ঘটে তা বুঝতে সহায়তা করে (এক্সিকিউটেবল ফাইল এমন একটি ফাইল যা আপনার মেশিনে এক্সিকিউট হতে পারে বা অন্য কারও মেশিন একই মেশিনের আর্কিটেকচার চালাচ্ছে)।

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

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

printf("Hello Kristina!\n");

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

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

আশা করি এটি বুঝতে আপনাকে সহায়তা করবে!


9
দুর্দান্ত উত্তর। অতিরিক্তভাবে বেশিরভাগ আধুনিক লিঙ্কারগুলি টেম্পলেট ইনস্ট্যান্টেশনের মতো অপ্রয়োজনীয় কোড সরিয়ে ফেলবে।
এডওয়ার্ড স্ট্রেঞ্জ

1
এই পার্থক্যগুলির কিছু অতিক্রম করার জন্য এটি কি উপযুক্ত জায়গা?
জন পি

2
হাই, ধরুন আমার ফাইলটি অন্য কোনও ফাইলের রেফারেন্স দেয় না। ধরুন আমি কেবল দুটি ভেরিয়েবল ঘোষণা করি এবং প্রারম্ভিক করি। এই উত্স ফাইলটি কি লিঙ্কারে যাবে?
মঙ্গেশ খেরেদেকার

3
@ মঙ্গেশখেরেদেকার - হ্যাঁ, এটি সর্বদা একটি লিঙ্কারের মধ্য দিয়ে যায়। লিঙ্কারটি কোনও বাহ্যিক গ্রন্থাগারগুলিতে লিঙ্ক নাও করতে পারে, তবে লিঙ্কিং পর্বটি এখনও কার্যকর হতে পারে উত্পাদন করার জন্য।
আইসমানিন্ড

78

ঠিকানা স্থানান্তর ন্যূনতম উদাহরণ

ঠিকানা স্থানান্তর লিঙ্কিংয়ের অন্যতম গুরুত্বপূর্ণ কাজ।

সুতরাং আসুন এটি কীভাবে একটি ন্যূনতম উদাহরণ দিয়ে কাজ করে তা একবার দেখুন।

0) ভূমিকা

সংক্ষিপ্তসার: স্থানান্তর .textঅনুবাদ করতে অবজেক্ট ফাইলগুলির বিভাগটি সম্পাদনা করে :

  • অবজেক্ট ফাইল ঠিকানা
  • এক্সিকিউটেবলের চূড়ান্ত ঠিকানায়

এটি অবশ্যই লিঙ্কারের মাধ্যমেই করা উচিত কারণ সংকলকটি একবারে কেবল একটি ইনপুট ফাইল দেখে, তবে কীভাবে তা স্থির করতে আমাদের অবশ্যই একবারে সমস্ত অবজেক্ট ফাইল সম্পর্কে জানতে হবে:

  • ঘোষিত অপরিজ্ঞাত ফাংশনগুলির মতো অপরিবর্তিত প্রতীকগুলি সমাধান করুন
  • একাধিক .textএবং .dataএকাধিক অবজেক্ট ফাইলের বিভাগ সংঘর্ষ না

পূর্বশর্ত: এর ন্যূনতম বোঝাপড়া:

  • x86-64 বা আইএ -32 সমাবেশ
  • একটি ELF ফাইলের বৈশ্বিক কাঠামো। আমি এটির জন্য একটি টিউটোরিয়াল তৈরি করেছি

সি বা সি ++ এর সাথে লিঙ্কিংয়ের কোনও সম্পর্ক নেই: সংকলকগণ কেবলমাত্র বস্তু ফাইলগুলি তৈরি করে rate লিঙ্কারটি তখন কোন ভাষা তাদের সংকলন করে না জেনে এগুলি ইনপুট হিসাবে নেয়। এটি ফোর্টরানও হতে পারে।

সুতরাং ভূত্বক হ্রাস করতে, আসুন একটি এনএএসএম x86-64 ইএলএফ লিনাক্স হ্যালো ওয়ার্ল্ড অধ্যয়ন করি:

section .data
    hello_world db "Hello world!", 10
section .text
    global _start
    _start:

        ; sys_write
        mov rax, 1
        mov rdi, 1
        mov rsi, hello_world
        mov rdx, 13
        syscall

        ; sys_exit
        mov rax, 60
        mov rdi, 0
        syscall

সংকলিত এবং একত্রিত:

nasm -o hello_world.o hello_world.asm
ld -o hello_world.out hello_world.o

NASM 2.10.09 সহ।

1)। টেক্সট .o

প্রথমে আমরা .textঅবজেক্ট ফাইলটির বিভাগটি বিশিষ্ট :

objdump -d hello_world.o

যা দেয়:

0000000000000000 <_start>:
   0:   b8 01 00 00 00          mov    $0x1,%eax
   5:   bf 01 00 00 00          mov    $0x1,%edi
   a:   48 be 00 00 00 00 00    movabs $0x0,%rsi
  11:   00 00 00
  14:   ba 0d 00 00 00          mov    $0xd,%edx
  19:   0f 05                   syscall
  1b:   b8 3c 00 00 00          mov    $0x3c,%eax
  20:   bf 00 00 00 00          mov    $0x0,%edi
  25:   0f 05                   syscall

গুরুত্বপূর্ণ লাইনগুলি হ'ল:

   a:   48 be 00 00 00 00 00    movabs $0x0,%rsi
  11:   00 00 00

যা হ্যালো ওয়ার্ল্ড স্ট্রিংয়ের ঠিকানাটি rsiরেজিস্টারে সরিয়ে নেওয়া উচিত, যা রাইটিং সিস্টেম কলটিতে পাস করা হয়।

কিন্তু অপেক্ষা করো! "Hello world!"প্রোগ্রামটি লোড হওয়ার পরে সংকলকটি কীভাবে সম্ভবত জানতে পারে যে মেমরির কোথায় শেষ হবে?

ভাল, এটি সম্ভব নয়, বিশেষত আমরা .oএকাধিক .dataবিভাগের সাথে একগুচ্ছ ফাইল সংযুক্ত করি ।

কেবল লিঙ্কারই এটি করতে পারে যেহেতু কেবলমাত্র তার কাছে এই সমস্ত বস্তুর ফাইল থাকবে।

তাই সংকলক ঠিক:

  • 0x0সংকলিত আউটপুটে একটি স্থানধারক মান রাখে
  • কীভাবে ভাল ঠিকানাগুলির সাথে সংকলিত কোডটি সংশোধন করতে হয় তার লিঙ্কারে কিছু অতিরিক্ত তথ্য দেয়

এই "অতিরিক্ত তথ্য" .rela.textঅবজেক্ট ফাইলের বিভাগে রয়েছে

2) .rela.text

.rela.text "টেক্সট বিভাগের স্থানান্তর" এর জন্য দাঁড়িয়েছে।

রিলোকেশন শব্দটি ব্যবহার করা হয়েছে কারণ লিঙ্কারটিকে বস্তুটি থেকে এক্সিকিউটেবলের মধ্যে ঠিকানাটি স্থানান্তর করতে হবে।

আমরা এর .rela.textসাথে বিভাগটি বিচ্ছিন্ন করতে পারি :

readelf -r hello_world.o

যেটা বহন করে;

Relocation section '.rela.text' at offset 0x340 contains 1 entries:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
00000000000c  000200000001 R_X86_64_64       0000000000000000 .data + 0

এই বিভাগটির ফর্ম্যাটটি এখানে নথিবদ্ধ করা হয়েছে: http://www.sco.com/developers/gabi/2003-12-17/ch4.reloc.html

প্রতিটি এন্ট্রি লিঙ্কারকে এমন একটি ঠিকানা সম্পর্কে জানায় যা স্থানান্তরিত করতে হবে, এখানে স্ট্রিংয়ের জন্য আমাদের কেবল একটি আছে।

কিছুটা সরলকরণ, এই নির্দিষ্ট লাইনের জন্য আমাদের নিম্নোক্ত তথ্য রয়েছে:

  • Offset = C: .textএই এন্ট্রিটি পরিবর্তিত হওয়ার প্রথম বাইটটি কী ।

    আমরা যদি পচা পাঠ্যটির দিকে ফিরে তাকাই, এটি ঠিক সমালোচনার ভিতরে রয়েছে movabs $0x0,%rsiএবং যারা x86-64 নির্দেশনা এনকোডিং জানেন তারা লক্ষ্য করবেন যে এটি নির্দেশের -৪-বিট ঠিকানা অংশটি এনকোড করেছে।

  • Name = .data: ঠিকানাটি .dataবিভাগে নির্দেশ করে

  • Type = R_X86_64_64, যা ঠিকানাটি অনুবাদ করতে ঠিক কী গণনা করতে হবে তা নির্দিষ্ট করে।

    এই ক্ষেত্রটি আসলে প্রসেসর নির্ভর, এবং এইভাবে এটিএমডি 64 সিস্টেম ভি এবিআই এক্সটেনশন বিভাগ 4.4 "রিলোকেশন" এ নথিভুক্ত ।

    এই দস্তাবেজটি বলে যে R_X86_64_64:

    • Field = word64: 8 বাইট, এইভাবে 00 00 00 00 00 00 00 00ঠিকানা0xC

    • Calculation = S + A

      • Sহয় মান ঠিকানায় স্থানান্তর করা হচ্ছে, এইভাবে00 00 00 00 00 00 00 00
      • A0এখানে সংযোজন । এটি স্থানান্তরের প্রবেশের ক্ষেত্র।

      সুতরাং S + A == 0এবং আমরা .dataবিভাগটির প্রথম ঠিকানায় স্থান পরিবর্তন করব ।

3)। টেক্সট .আউট

এখন আসুন ldআমাদের জন্য নির্বাহযোগ্য এক্সিকিউটেবলের পাঠ্য অঞ্চলটি দেখুন :

objdump -d hello_world.out

দেয়:

00000000004000b0 <_start>:
  4000b0:   b8 01 00 00 00          mov    $0x1,%eax
  4000b5:   bf 01 00 00 00          mov    $0x1,%edi
  4000ba:   48 be d8 00 60 00 00    movabs $0x6000d8,%rsi
  4000c1:   00 00 00
  4000c4:   ba 0d 00 00 00          mov    $0xd,%edx
  4000c9:   0f 05                   syscall
  4000cb:   b8 3c 00 00 00          mov    $0x3c,%eax
  4000d0:   bf 00 00 00 00          mov    $0x0,%edi
  4000d5:   0f 05                   syscall

সুতরাং কেবলমাত্র যা বস্তুর ফাইল থেকে পরিবর্তিত হয়েছিল তা হ'ল সমালোচনামূলক লাইন:

  4000ba:   48 be d8 00 60 00 00    movabs $0x6000d8,%rsi
  4000c1:   00 00 00

যা এখন ঠিকানাটা পয়েন্ট 0x6000d8( d8 00 60 00 00 00 00 00অল্প endian মধ্যে) পরিবর্তে 0x0

এই hello_worldস্ট্রিং জন্য সঠিক অবস্থান ?

সিদ্ধান্ত নেওয়ার জন্য আমাদের প্রোগ্রামের শিরোনামগুলি পরীক্ষা করতে হবে, যা প্রতিটি বিভাগটি কোথায় লোড করতে হবে লিনাক্সকে বলে।

আমরা তাদের সাথে পৃথক করা:

readelf -l hello_world.out

যা দেয়:

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  LOAD           0x0000000000000000 0x0000000000400000 0x0000000000400000
                 0x00000000000000d7 0x00000000000000d7  R E    200000
  LOAD           0x00000000000000d8 0x00000000006000d8 0x00000000006000d8
                 0x000000000000000d 0x000000000000000d  RW     200000

 Section to Segment mapping:
  Segment Sections...
   00     .text
   01     .data

এটি আমাদের জানায় যে .dataবিভাগটি, যা দ্বিতীয়টি, VirtAddr= থেকে শুরু হয় 0x06000d8

এবং ডেটা বিভাগে কেবলমাত্র আমাদের হ্যালো ওয়ার্ল্ড স্ট্রিং।

বোনাস স্তর


1
বাবু তুমি দুর্দান্ত। 'একটি ইএলএফ ফাইলের বৈশ্বিক কাঠামো' টিউটোরিয়ালটির লিঙ্কটি নষ্ট হয়ে গেছে।
আদম জহরান

1
@ অ্যাডামজাহরান ধন্যবাদ! বোকা গিটহাব পৃষ্ঠাগুলি ইউআরএল যা স্ল্যাশগুলির সাথে লেনদেন করতে পারে না!
সিরো সান্তিলি 郝海东 冠状 病 六四 事件 法轮功

15

'সি' এর মতো ভাষায়, কোডের পৃথক মডিউলগুলি traditionতিহ্যগতভাবে অবজেক্ট কোডের ব্লবগুলিতে পৃথকভাবে সংকলিত হয়, যা মডিউলের বাইরে থাকা সমস্ত রেফারেন্স (যেমন গ্রন্থাগার বা অন্যান্য মডিউলগুলিতে) এর বাইরে অন্য সকল ক্ষেত্রে কার্যকর করতে প্রস্তুত exec এখনও সমাধান করা হয়নি (যেমন তারা ফাঁকা, কারও সাথে আসা এবং সমস্ত সংযোগগুলি মুলতুবি করা)।

লিঙ্কারটি যা করে তা হ'ল সমস্ত মডিউলগুলি একসাথে দেখতে, প্রতিটি মডিউলের বাইরে থেকে কী সংযোগ স্থাপন করা দরকার তা দেখুন এবং এটি রফতানি করছে এমন সমস্ত বিষয় দেখুন। এরপরে এটি স্থির করে এবং এটি একটি চূড়ান্ত নির্বাহযোগ্য উত্পাদন করে, যা পরে চালানো যেতে পারে।

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


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

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

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

10

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

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

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

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