linux - X86-64 লিনাক্সে 32-বিট পরম ঠিকানাগুলির আর অনুমতি নেই?



gcc linker-errors (1)

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

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

ELF শেয়ার করা অবজেক্টে 32-বিট পরম স্থানান্তরের অনুমতি নেই; এটি তাদের কম 2GiB এর বাইরে লোড হওয়া থেকে বিরত করবে (সাইন-এক্সটেন্ডেড 32-বিট ঠিকানাগুলির জন্য)। -৪-বিটের পরম ঠিকানাগুলির অনুমতি রয়েছে তবে সাধারণভাবে আপনি কেবলমাত্র জাম্প টেবিল বা অন্যান্য স্থিতিশীল ডেটাগুলির জন্য নির্দেশাবলীর অংশ হিসাবে তা চান না। 1

ত্রুটি বার্তার recompile with -fPIC অংশের recompile with -fPIC হস্ত লিখিত asm এর জন্য বোগাস; এটি gcc -c সাথে সংকলন করা লোকদের ক্ষেত্রে এবং তারপরে gcc -shared -o foo.so *.o সাথে লিঙ্ক দেওয়ার চেষ্টা করার ক্ষেত্রে, যেখানে -fPIE ডিফল্ট নয় -fPIE ত্রুটি বার্তাটি সম্ভবত পরিবর্তন করা উচিত কারণ হাতের লিখিত asm লিঙ্ক করার সময় অনেক লোক এই ত্রুটির মধ্যে চলে।

কীভাবে আরআইপি-আপেক্ষিক ঠিকানা ব্যবহার করবেন: মূল কথা

সরল ক্ষেত্রে যেখানে কোনও খারাপ দিক নেই সেখানে সর্বদা আরআইপি-আপেক্ষিক ঠিকানা ব্যবহার করুন। নীচের পাদটীকা 1 এবং সিনট্যাক্সের জন্য এই উত্তরটি দেখুন । কেবলমাত্র 32-বিট পরম ঠিকানা ব্যবহার করার বিষয়ে বিবেচনা করুন যখন এটি ক্ষতির পরিবর্তে কোড-আকারের জন্য আসলে সহায়ক helpful যেমন আপনার ফাইলের শীর্ষে NASM default rel

এটিএন্ডটি .intel_syntax noprefix foo(%rip) বা জিএএস। .intel_syntax noprefix [rip + foo] .intel_syntax noprefix [rip + foo]

32-বিট পরম অ্যাড্রেসিংয়ের কাজটি করতে পিআইই মোডটি অক্ষম করুন

gcc -fno-pie -no-pie পুরানো আচরণে ওভাররাইড করতে gcc -fno-pie -no-pie ব্যবহার করুন। -fno-pie লিঙ্কার বিকল্প, -fno-pie হ'ল কোড-জেন বিকল্প । কেবলমাত্র -fno-pie , mov eax, offset .LC0 মতো কোড তৈরি করবে যা এখনও সক্রিয় -pie - -pie সাথে লিঙ্ক করে না।

( clang -fno-pie -nopie ডিফল্টরূপে পিআইই সক্ষম থাকতে পারে: clang -fno-pie -nopie ব্যবহার করুন clang -fno-pie -nopie জুলাই 2017 প্যাচ -no-pie -nopie সহ -nopie জন্য -nopie জন্য একটি উপনাম তৈরি -nopie , তবে ক্ল্যাং ৪.০.১ নেই)। )

I৪-বিট (গৌণ) বা 32-বিট কোড (প্রধান) এর জন্য পিআইই এর পারফরম্যান্স ব্যয়

কেবলমাত্র -no-pie সহ, (তবে এখনও- -fpie ) সংকলক-উত্পাদিত কোড (সি বা সি ++ উত্স থেকে) প্রয়োজনের তুলনায় কিছুটা ধীর এবং বৃহত্তর হবে, তবে এখনও এমন অবস্থান-নির্ভর এক্সিকিউটেবলের সাথে যুক্ত হবে যা থেকে কোনও উপকার হবে না ASLR। "পারফরম্যান্সের জন্য খুব বেশি পিআইই খারাপ)" স্পেক সিপিইউ ২০০200-এ x86-64 এর জন্য গড়ে 3% হ্রাসের প্রতিবেদন করে (আমার কাছে কাগজের কোনও অনুলিপি নেই যাতে আইডিকে কী হার্ডওয়্যার ছিল: /)) তবে 32-বিট কোডে, গড় মন্দা 10%, সবচেয়ে খারাপ 25% (স্পেক সিপিইউ 2006-তে)।

পিআইই এক্সিকিউটেবলের জন্য জরিমানা বেশিরভাগ ক্ষেত্রে স্ট্যাটিক অ্যারেগুলি সূচীকরণের মতো স্টাফের জন্য, যেমন আগ্নের প্রশ্নটিতে বর্ণনা করেছেন, যেখানে স্থির ঠিকানাটি 32-বিট তাত্ক্ষণিক হিসাবে বা [disp32 + index*4] সম্বোধনের মোডের অংশ হিসাবে নির্দেশাবলী এবং রেজিস্টারগুলি সংরক্ষণ করে বনাম একটি নিবন্ধ সম্পর্কিত একটি ঠিকানা পেতে একটি RIP- সম্পর্কিত এলইএ। এছাড়াও 5-বাইট mov r32, imm32 7-বাইট lea r64, [rel symbol] mov r32, imm32 পরিবর্তে lea r64, [rel symbol] একটি রেজিস্টারে স্থির ঠিকানা পাওয়ার জন্য কোনও ফাংশনে স্ট্রিং আক্ষরিক বা অন্যান্য স্ট্যাটিক ডেটার ঠিকানা পাস করার জন্য দুর্দান্ত।

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

সুতরাং -fPIE -fPIC বিট কোডের জন্য -fPIC তুলনায় খুব কম খারাপ, তবে এখনও 32-বিটের জন্য খারাপ কারণ -fPIC আপেক্ষিক ঠিকানা উপলব্ধ নয় গডবোল্ট সংকলক এক্সপ্লোরার এর কয়েকটি উদাহরণ দেখুন। গড়ে, -fPIE -বিট কোডে খুব ছোট পারফরম্যান্স / কোড-সাইজ ডাউনসাইড করে। নির্দিষ্ট লুপের জন্য সবচেয়ে খারাপ পরিস্থিতি কেবলমাত্র কয়েক% হতে পারে। তবে 32-বিট পিআইই আরও খারাপ হতে পারে।

এই লিঙ্ক-কোড জেন বিকল্পগুলির .S কেবল লিঙ্ক করার সময়, বা এস .S হওয়ার সময় কোনও .S hand gcc -fno-pie -no-pie -O3 main.c nasm_output.o এমন একটি মামলা যেখানে আপনি উভয় বিকল্প চান।

আপনার জিসিসি কনফিগারেশন চেক করা হচ্ছে

আপনার জিসিসি যদি এভাবে কনফিগার করা থাকে তবে gcc -v |& grep -o -e '[^ ]*pie' মুদ্রণ --enable-default-pie 2015 সালের গোড়ার দিকে এই কনফিগার বিকল্পটির জন্য সমর্থন জিসিসিতে যুক্ত করা হয়েছিল। উবুন্টু এটি 16.10-এ এবং ডিবিয়ান প্রায় একই সময়ে 6.2.0-7 (কার্নেল বিল্ড ত্রুটির দিকে পরিচালিত করে: https://lkml.org/lkml/2016/10/21/904 )।

সম্পর্কিত: পিআইই পরিবর্তিত ডিফল্ট দ্বারা প্রভাবিত হওয়ায় সংকুচিত x86 কার্নেলগুলি তৈরি করুন

কেন লিনাক্স এক্সিকিউটেবল কোড সেগমেন্টের ঠিকানাটি এলোমেলো করে না? এটি পূর্ববর্তী কেন আগে ডিফল্ট ছিল না, বা বোর্ড জুড়ে সক্রিয় হওয়ার আগে কেবল পুরানো উবুন্টুতে কয়েকটি প্যাকেজগুলির জন্য সক্ষম হয়েছিল সে সম্পর্কে এটি একটি পুরানো প্রশ্ন।

মনে রাখবেন যে ld নিজেই এর ডিফল্ট পরিবর্তন করে না । এটি এখনও স্বাভাবিকভাবে কাজ করে (অন্তত আর্ক লিনাক্সে বাইনুটিস ২.২৮) সহ। পরিবর্তনটি হ'ল আপনি যদি স্পষ্টভাবে -no-pie -static বা -static -no-pie ব্যবহার না করেন, তবে -pie লিংকার বিকল্প হিসাবে পাস- -pie ডিফল্ট হয় -pie

একটি এনএএসএম উত্স ফাইলে, আমি একটি a32 mov eax, [abs buf] ঠিকানা পেতে a32 mov eax, [abs buf] ব্যবহার a32 mov eax, [abs buf] । (আমি যদি নিরঙ্কুশ ঠিকানাগুলি এনকোড করার 6-বাইট উপায়ে (ঠিকানা-আকার + মুভ ইক্স, এমওফস: 67 a1 40 f1 60 00 ) এর ইনটেল সিপিইউগুলিতে একটি এলসিপি স্টল রেখেছি তা পরীক্ষা করে দেখছিলাম) এটি রয়েছে))

nasm -felf64 -Worphan-labels -g -Fdwarf testloop.asm &&
ld -o testloop testloop.o              # works: static executable

gcc -v -nostdlib testloop.o            # doesn't work
...
..../collect2  ... -pie ...
/usr/bin/ld: testloop.o: relocation R_X86_64_32 against `.bss' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Nonrepresentable section on output
collect2: error: ld returned 1 exit status

gcc -v -no-pie -nostdlib testloop.o    # works
gcc -v -static -nostdlib testloop.o    # also works: -static implies -no-pie

সম্পর্কিত: বিল্ডিং স্ট্যাটিক / গতিশীল এক্সিকিউটেবলগুলি _start সাথে / ছাড়াই, _start বা _start সংজ্ঞায়িত করে

বিদ্যমান এক্সিকিউটেবল PIE কিনা তা পরীক্ষা করা হচ্ছে

file এবং readelf বলেছেন যে পিআইইগুলি "ভাগ করা অবজেক্টস", ইএলএফ এক্সিকিউটেবল নয়। স্ট্যাটিক এক্সিকিউটেবলগুলি পিআইই হতে পারে না।

$ gcc -fno-pie  -no-pie -O3 hello.c
$ file a.out
a.out: ELF 64-bit LSB executable, ...

$ gcc -O3 hello.c
$ file a.out
a.out: ELF 64-bit LSB shared object, ...

 ## Or with a more recent version of file:
a.out: ELF 64-bit LSB pie executable, ...

এটিতে এখানেও জিজ্ঞাসা করা হয়েছিল: কোনও লিনাক্স বাইনারি অবস্থান স্বতন্ত্র কোড হিসাবে সংকলিত হয়েছিল কিনা তা কীভাবে পরীক্ষা করবেন?

আধা সম্পর্কিত (তবে সত্যিই নয়): সাম্প্রতিক আরেকটি gcc -fno-plt বৈশিষ্ট্য হ'ল gcc -fno-plt । অবশেষে ভাগ করা লাইব্রেরিতে কলগুলি কেবলমাত্র call [rip + [email protected]] কল করা যেতে পারে (এটিএন্ডটি call *[email protected](%rip) ) call *[email protected](%rip) , কোনও পিএলটি ট্রামপোলিন ছাড়াই।

ডিস্ট্রোজ আশা করি শীঘ্রই এটি সক্ষম করা শুরু করবে, কারণ এটি লেখার যোগ্য + কার্যকরকরণযোগ্য মেমরি পৃষ্ঠাগুলির প্রয়োজনও এড়িয়ে চলে ids এটি এমন প্রোগ্রামগুলির জন্য একটি তাত্পর্যপূর্ণ গতিবেগ যা প্রচুর শেয়ার্ড-লাইব্রেরি কল করে, যেমন x86-64 clang -O2 -g সংকলন ট্রাম্প 3 ডি প্যাচ লেখক যে কোনও হার্ডওয়্যার দ্বারা পরীক্ষা করা হয়েছে তার উপর 41.6s থেকে 36.8s পর্যন্ত চলে। (শেয়ার লাইব্রেরি কলগুলির জন্য ঝনঝনাই সবচেয়ে খারাপ পরিস্থিতি হতে পারে।)

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

এটি ভাগ করা লাইব্রেরি পিআইসি কোডে বাহ্যিক ভেরিয়েবলের জন্য জিওটি ওভারহেড সরিয়ে দেয় না, যদিও। (উপরের গডবোল্ট লিঙ্কটি দেখুন)।

পাদটীকা ঘ

লিনাক্স ইএলএফ ভাগ করা অবজেক্টগুলিতে 64৪-বিট পরম ঠিকানাগুলি অনুমোদিত, পাঠ্য স্থানান্তরের সাথে বিভিন্ন ঠিকানায় (এএসএলআর এবং ভাগ করা লাইব্রেরি) লোড করার অনুমতি দেয়। এটি আপনাকে section .rodata জাম্প টেবিল রাখতে অনুমতি দেয় section .rodata , বা static const int *foo = &bar; section .rodata static const int *foo = &bar; একটি রানটাইম আরম্ভকারী ছাড়া।

সুতরাং mov rdi, qword msg কাজ করে (10-বাইট mov r64, imm64 , ওরফে এটি অ্যান্ড টি সিনট্যাক্স movabs জন্য NASM / YASM সিনট্যাক্স, একমাত্র নির্দেশ যা movabs -বিট অবিলম্বে ব্যবহার করতে পারে)। তবে এটি lea rdi, [rel msg] চেয়ে বড় এবং সাধারণত ধীর lea rdi, [rel msg] , আপনি যদি -pie অক্ষম না করার সিদ্ধান্ত নেন তবে আপনার ব্যবহার করা উচিত। অ্যাডনার ফগের মাইক্রোয়ার্ক পিডিএফ অনুসারে একটি immediate৪-বিট তাত্ক্ষণিকভাবে স্যান্ডিব্রিজ-পরিবার সিপিইউতে ইউওপ ক্যাশে থেকে আনা ধীর। (হ্যাঁ, একই ব্যক্তি যিনি এই প্রশ্নটি করেছিলেন। :)

আপনি প্রতিটি [rel symbol] অ্যাড্রেসিং মোডে এটি নির্দিষ্ট করার পরিবর্তে NASM এর default rel ব্যবহার করতে পারেন। আরও দেখুন ম্যাচ-ও 64-বিট ফর্ম্যাট 32-বিট পরম ঠিকানাগুলিকে সমর্থন করে না। 32-বিট পরম সম্বোধন এড়িয়ে যাওয়ার আরও কিছু বিবরণের জন্য NASM অ্যারে অ্যাক্সেস করছে । ওএস এক্স মোটেও 32-বিট ঠিকানা ব্যবহার করতে পারে না, তাই আরআইপি-আপেক্ষিক ঠিকানাটিও সেখানে সবচেয়ে ভাল উপায়।

অবস্থান-নির্ভর কোডে ( -no-pie ), আপনি mov edi, msg ব্যবহার করতে হবে mov edi, msg যখন আপনি কোনও নিবন্ধে ঠিকানা চান; 5-বাইট mov r32, imm32 আর mov r32, imm32 আরআইপি-আপেক্ষিক এলইএর চেয়েও ছোট এবং আরও কার্যকর mov r32, imm32 পোর্টগুলি এটি চালাতে পারে।

ডিফল্টরূপে 64 বিট লিনাক্স ছোট মেমরি মডেল ব্যবহার করে, যা সমস্ত কোড এবং স্থিতিশীল ডেটা 2 জিবি ঠিকানা সীমাতে নীচে রাখে। এটি নিশ্চিত করে যে আপনি 32-বিট পরম ঠিকানা ব্যবহার করতে পারেন। জিসিসির পুরানো সংস্করণগুলি স্থির অ্যারেগুলির জন্য 32-বিট পরম ঠিকানা ব্যবহার করে যাতে আপেক্ষিক ঠিকানা গণনার জন্য অতিরিক্ত নির্দেশ সংরক্ষণ করা যায়। তবে এটি আর কাজ করে না। আমি যদি সমাবেশে 32-বিটের নিখুঁত ঠিকানা করার চেষ্টা করি তবে আমি লিঙ্কারের ত্রুটিটি পেয়েছি: "` .ডাটা'র বিপরীতে স্থানান্তর R_X86_64_32S একটি ভাগ করা অবজেক্ট তৈরি করার সময় ব্যবহার করা যাবে না; -fPIC এর সাথে পুনরায় সংযোগ করুন "। এই ত্রুটি বার্তাটি অবশ্যই বিভ্রান্তিমূলক, কারণ আমি কোনও ভাগ করা অবজেক্ট তৈরি করছি না এবং -fPIC সাহায্য করবে না। আমি এখন পর্যন্ত যা জানতে পেরেছি তা হ'ল: জিসিসি সংস্করণ 4.8.5 স্ট্যাটিক অ্যারেগুলির জন্য 32-বিট পরম ঠিকানা ব্যবহার করে, জিসিসি সংস্করণ 6.3.0 দেয় না। সংস্করণ 5 সম্ভবত হয় না। বাইনুটিলেস ২.২৪ এর লিঙ্কারটি 32-বিট পরম ঠিকানাগুলিতে অনুমতি দেয়, বিপরীতে 2.28 দেয় না।

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

এখন আমি জিজ্ঞাসা করতে চাই: কখন এই পরিবর্তনটি করা হয়েছিল? এটি কোথাও নথিভুক্ত করা হয়? এবং এমন কোনও লিঙ্কার বিকল্প রয়েছে যা এটি 32-বিট পরম ঠিকানাগুলি গ্রহণ করে?