ঠিকানা স্থানান্তর ন্যূনতম উদাহরণ
ঠিকানা স্থানান্তর লিঙ্কিংয়ের অন্যতম গুরুত্বপূর্ণ কাজ।
সুতরাং আসুন এটি কীভাবে একটি ন্যূনতম উদাহরণ দিয়ে কাজ করে তা একবার দেখুন।
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
A
0
এখানে সংযোজন । এটি স্থানান্তরের প্রবেশের ক্ষেত্র।
সুতরাং 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
।
এবং ডেটা বিভাগে কেবলমাত্র আমাদের হ্যালো ওয়ার্ল্ড স্ট্রিং।
বোনাস স্তর