আমার জন্য, এটি কেবল মজাদার এমওভিয়ের মতো মনে হচ্ছে। এর উদ্দেশ্য কী এবং আমি কখন এটি ব্যবহার করব?
আমার জন্য, এটি কেবল মজাদার এমওভিয়ের মতো মনে হচ্ছে। এর উদ্দেশ্য কী এবং আমি কখন এটি ব্যবহার করব?
উত্তর:
যেমনটি অন্যরা উল্লেখ করেছে, এলইএ (লোড কার্যকর ঠিকানা) প্রায়শই নির্দিষ্ট গণনা করতে একটি "কৌশল" হিসাবে ব্যবহৃত হয়, তবে এটি এর প্রাথমিক উদ্দেশ্য নয়। X86 নির্দেশিকা সেটটি পাস্কাল এবং সি এর মতো উচ্চ-স্তরের ভাষার জন্য ডিজাইন করা হয়েছিল, যেখানে অ্যারেগুলি - বিশেষত ইনট বা ছোট স্ট্রাকের অ্যারেগুলি সাধারণ। উদাহরণস্বরূপ, একটি কাঠামো (x, y) স্থানাঙ্কগুলি বিবেচনা করুন:
struct Point
{
int xcoord;
int ycoord;
};
এখন একটি বিবৃতি কল্পনা করুন:
int y = points[i].ycoord;
যেখানে points[]
একটি অ্যারে হয় Point
। অ্যারের বেস ধরে নেওয়া যাক আগে থেকেই EBX
, এবং পরিবর্তনশীল i
রয়েছে EAX
, এবং xcoord
এবং ycoord
প্রতিটি 32 বিট (তাই হয় ycoord
struct অনেক অফসেট 4 বাইট এ করা হয়), এই বিবৃতি কম্পাইল করা যেতে পারে:
MOV EDX, [EBX + 8*EAX + 4] ; right side is "effective address"
যা অবতরণ করবে y
মধ্যে EDX
। 8 এর স্কেল ফ্যাক্টর কারণ প্রতিটি Point
আকার 8 বাইট হয়। এখন "ঠিকানা" অপারেটরের সাথে ব্যবহৃত একই অভিব্যক্তিটি বিবেচনা করুন এবং:
int *p = &points[i].ycoord;
এই ক্ষেত্রে, আপনি এর মান চান না ycoord
, তবে এটির ঠিকানা। যে যেখানে আছে LEA
(লোড কার্যকর ঠিকানা) আসে। একটি পরিবর্তে MOV
, কম্পাইলার তৈরি করতে পারেন
LEA ESI, [EBX + 8*EAX + 4]
যা ঠিকানা লোড করবে ESI
।
mov
নির্দেশিকাটি বাড়ানো এবং বন্ধনীগুলি ছেড়ে দেওয়া কি ক্লিনার না হত ? MOV EDX, EBX + 8*EAX + 4
MOV
একটি পরোক্ষ উত্সের মতো, এটি কেবল ইন্ডিয়ারেশন দেয় এবং না করেই MOV
। এটি আসলে গণনা করা ঠিকানা থেকে পড়ে না , কেবল এটি গণনা করে।
আবরাশের রচনা "জেন অফ জেন" থেকে :
LEA
, একমাত্র নির্দেশ যা মেমরি সম্বোধনের গণনা সম্পাদন করে তবে মেমরিটিকে আসলে সম্বোধন করে না।LEA
একটি স্ট্যান্ডার্ড মেমরি অ্যাড্রেসিং অপারেন্ড গ্রহণ করে, তবে নির্দিষ্ট রেজিস্টারে গণিত মেমরি অফসেট সংরক্ষণ করা ছাড়া আর কিছুই করে না, যা কোনও সাধারণ উদ্দেশ্য নিবন্ধ হতে পারে।আমাদের কী দেয়? দুটি জিনিস যা সরবরাহ
ADD
করে না:
- দুটি বা তিনটি অপারেন্ডের সাথে সংযোজন করার ক্ষমতা এবং
- যে কোনও রেজিস্টারে ফলাফল সংরক্ষণের ক্ষমতা ; শুধুমাত্র উত্স অপারেশন এক।
এবং LEA
পতাকাগুলি পরিবর্তন করে না।
উদাহরণ
LEA EAX, [ EAX + EBX + 1234567 ]
গণনা করে EAX + EBX + 1234567
(এটি তিনটি অপারেশন)LEA EAX, [ EBX + ECX ]
EBX + ECX
ফলাফলের সাথে ওভাররাইড না করে গণনা করে।LEA EAX, [ EBX + N * EBX ]
(এন 1,2,4,8 হতে পারে)।অন্যান্য usecase লুপ মধ্যে কুশলী হল: মধ্যে পার্থক্য LEA EAX, [ EAX + 1 ]
এবং INC EAX
যে আধুনিক পরিবর্তন হয় EFLAGS
কিন্তু সাবেক না; এই CMP
রাষ্ট্র সংরক্ষণ করে ।
LEA EAX, [ EAX + EBX + 1234567 ]
সমষ্টি হিসাব করে EAX
, EBX
এবং 1234567
(যে তিন operands এর)। LEA EAX, [ EBX + ECX ]
হিসাব EBX + ECX
ছাড়া ফলাফল নিয়ে পারেন অগ্রাহ্য। তৃতীয় জিনিসটি LEA
(ফ্র্যাঙ্ক দ্বারা তালিকাভুক্ত নয়) এর জন্য ব্যবহৃত হয় হ'ল ধ্রুবক দ্বারা দ্বিগুণ (দুটি, তিন, পাঁচ বা নয় দ্বারা), যদি আপনি এটি ব্যবহার করেন LEA EAX, [ EBX + N * EBX ]
( N
1,2,4,8 হতে পারে) like অন্যান্য usecase লুপ মধ্যে কুশলী হল: মধ্যে পার্থক্য LEA EAX, [ EAX + 1 ]
এবং INC EAX
যে আধুনিক পরিবর্তন হয় EFLAGS
কিন্তু সাবেক না; এই CMP
রাষ্ট্র সংরক্ষণ করে
LEA
ব্যবহার করতে পারে তা স্পষ্ট করে তোলে ... (দেখুন "এলইএ (কার্যকর ঠিকানা লোড করুন) উপরের আইজে কেনেডি-র জনপ্রিয় উত্তরে" নির্দিষ্ট গণনা করতে "কৌশল হিসাবে ব্যবহৃত হয়)
LEA
নির্দেশের আরেকটি গুরুত্বপূর্ণ বৈশিষ্ট্য হ'ল এটি শর্তের কোডগুলিতে যেমন পরিবর্তন করে না CF
এবং যেমন ZF
পাটিগণিত নির্দেশাবলীর দ্বারা ঠিকানাটি গণনা করার সময় ADD
বা MUL
করে। এই বৈশিষ্ট্যটি নির্দেশাবলীর মধ্যে নির্ভরতার মাত্রা হ্রাস করে এবং এইভাবে সংকলক বা হার্ডওয়্যার সিডিউলারের দ্বারা আরও অনুকূলকরণের সুযোগ করে দেয়।
lea
কখনও কখনও সংকলক (বা মানব কোডার) কোনও পতাকা ফলাফলকে ক্লোবার্ব না করে গণিত করতে দরকারী। তবে এর lea
চেয়ে দ্রুত নয় add
। বেশিরভাগ x86 নির্দেশাবলী পতাকা লিখেছে। উচ্চ-কার্যকারিতা x86 বাস্তবায়নগুলিকে EFLAGS এর নাম পরিবর্তন করতে হবে বা অন্যথায় স্বাভাবিক কোডটি দ্রুত চালানোর জন্য লেখার পরে লেখার ঝুঁকি এড়াতে হবে, সুতরাং পতাকা লেখাগুলি এড়ানো নির্দেশাবলী সেই কারণে ভাল নয়। ( আংশিক ফ্ল্যাগ স্টাফগুলি বিষয়গুলি তৈরি করতে পারে, আইএনসি নির্দেশনা বনাম এডিডি 1 দেখুন: এতে কী আসে যায়? )
সমস্ত ব্যাখ্যা থাকা সত্ত্বেও এলইএ একটি পাটিগণিত অপারেশন:
LEA Rt, [Rs1+a*Rs2+b] => Rt = Rs1 + a*Rs2 + b
শিফট + অ্যাড অপারেশনের জন্য এটির নাম চূড়ান্তভাবে বোকা। এর কারণটি ইতিমধ্যে শীর্ষ রেটে দেওয়া উত্তরগুলিতে ব্যাখ্যা করা হয়েছিল (যেমন এটি সরাসরি উচ্চ স্তরের মেমরি রেফারেন্সগুলি ম্যাপ করার জন্য তৈরি করা হয়েছিল)।
LEA
করে সাধারণ পূর্ণসংখ্যার এএলইউতে বেছে নিয়েছে । "স্টাফ কোথায় চলছে" তা খুঁজে পেতে
LEA
আপনাকে এমন ঠিকানা দেয় যা স্মৃতি সম্পর্কিত কোনও অ্যাড্রেসিং মোড থেকে উদ্ভূত হয়। এটি কোনও শিফট এবং অ্যাড অপারেশন নয়।
এলইএ নির্দেশনা সম্পর্কে সম্ভবত অন্য একটি জিনিস। 3, 5 বা 9 দ্বারা দ্রুত গুণনের নিবন্ধগুলির জন্য আপনি এলইএ ব্যবহার করতে পারেন।
LEA EAX, [EAX * 2 + EAX] ;EAX = EAX * 3
LEA EAX, [EAX * 4 + EAX] ;EAX = EAX * 5
LEA EAX, [EAX * 8 + EAX] ;EAX = EAX * 9
LEA EAX, [EAX*3]
?
shl
রেজিস্টারগুলি 2,4,8,16 দ্বারা গুণনের জন্য বাম দিকের শিফ্টের মতো নির্দেশ ব্যবহার করতে পারেন ... এটি দ্রুত এবং খাটো। তবে 2 এর শক্তির বিভিন্ন সংখ্যার সাথে সংখ্যাবৃদ্ধির জন্য আমরা সাধারণত mul
নির্দেশাবলী ব্যবহার করি যা আরও বেশি ভ্রান্ত ও ধীর।
lea eax,[eax*3]
সমতুল্য অনুবাদ করবে lea eax,[eax+eax*2]
।
lea
"লোড কার্যকর ঠিকানা" এর একটি সংক্ষেপণ। এটি উত্স অপারেন্ড দ্বারা গন্তব্য অপারেন্ডে অবস্থানের রেফারেন্সের ঠিকানাটি লোড করে। উদাহরণস্বরূপ, আপনি এটি ব্যবহার করতে পারেন:
lea ebx, [ebx+eax*8]
একক নির্দেশ দিয়ে ebx
পয়েন্টার eax
আইটেমগুলি আরও সরানো (64৪-বিট / উপাদান অ্যারেতে)। মূলত, আপনি পয়েন্টারগুলিকে দক্ষতার সাথে পরিচালনা করতে x86 আর্কিটেকচার দ্বারা সমর্থিত জটিল ঠিকানা মোডগুলি থেকে উপকৃত হন benefit
আপনি এটিকে ব্যবহার LEA
করার সবচেয়ে বড় কারণ MOV
হ'ল যদি আপনি ঠিকানাটি গণনা করতে ব্যবহার করা নিবন্ধগুলিতে পাটিগণিত সম্পাদন করতে হয়। কার্যকরভাবে, আপনি কার্যকরভাবে "ফ্রি" এর জন্য একাধিক নিবন্ধগুলিতে পয়েন্টার গাণিতিকের পরিমাণটি সম্পাদন করতে পারেন।
এটি সম্পর্কে আসলেই বিভ্রান্তিকর বিষয়টি হ'ল আপনি সাধারণত একটি LEA
ঠিক তেমন একটি লেখেন MOV
তবে আপনি আসলে স্মৃতিটিকে অবনমিত করছেন না। অন্য কথায়:
MOV EAX, [ESP+4]
এটি কোন ESP+4
বিষয়গুলিতে পয়েন্ট দেয় সেগুলির বিষয়বস্তু সরানো হবে EAX
।
LEA EAX, [EBX*8]
এটি কার্যকর ঠিকানাটি EBX * 8
EAX এ স্থানান্তরিত করবে, সেই জায়গাতে পাওয়া যায় না। আপনি দেখতে পাচ্ছেন, এছাড়াও, দুটি (স্কেলিং) এর গুণাবলী দ্বারা গুণিত করা সম্ভব যখন ক MOV
যোগ / বিয়োগের মধ্যে সীমাবদ্ধ।
LEA
।
8086 এর একটি বৃহত্তর নির্দেশিকা রয়েছে যা একটি রেজিস্টার অপারেন্ড এবং একটি কার্যকর ঠিকানা গ্রহণ করে, সেই কার্যকর ঠিকানার অফসেট অংশ গণনা করার জন্য কিছু গণনা সম্পাদন করে এবং নিবন্ধক এবং গণনা করা ঠিকানার দ্বারা উল্লেখ করা মেমরির সাথে জড়িত কিছু অপারেশন সম্পাদন করে। প্রকৃত স্মৃতি ক্রিয়াকলাপটি বাদ দেওয়া ছাড়া সেই পরিবারের যে কোনও একটি নির্দেশ উপরোক্তরূপে আচরণ করা মোটামুটি সহজ ছিল। এটি, নির্দেশাবলী:
mov ax,[bx+si+5]
lea ax,[bx+si+5]
প্রায় একইভাবে অভ্যন্তরীণভাবে প্রয়োগ করা হয়েছিল। পার্থক্যটি একটি এড়ানো পদক্ষেপ। উভয় নির্দেশাবলী এমন কিছু কাজ করে:
temp = fetched immediate operand (5)
temp += bx
temp += si
address_out = temp (skipped for LEA)
trigger 16-bit read (skipped for LEA)
temp = data_in (skipped for LEA)
ax = temp
কেন ইন্টেল এই নির্দেশকে অন্তর্ভুক্ত করার জন্য মূল্যবান বলে মনে করেছিল, আমি ঠিক নিশ্চিত নই, তবে বাস্তবায়নে সস্তা যে সত্য ছিল এটি একটি বড় কারণ হতে পারে। আরেকটি কারণ হ'ল ইন্টেলের এসেম্বলারের প্রতীকগুলি বিপি রেজিস্টারের সাথে সম্পর্কিত হতে পারে। যদি fnord
কোনও বিপি-আপেক্ষিক প্রতীক হিসাবে চিহ্নিত করা হয় (যেমন বিপি + 8), কেউ বলতে পারেন:
mov ax,fnord ; Equivalent to "mov ax,[BP+8]"
কেউ যদি কোনও বিপি-আপেক্ষিক ঠিকানায় ডেটা সঞ্চয় করতে স্টসওয়ের মতো কিছু ব্যবহার করতে চান, বলতে সক্ষম হচ্ছেন
mov ax,0 ; Data to store
mov cx,16 ; Number of words
lea di,fnord
rep movs fnord ; Address is ignored EXCEPT to note that it's an SS-relative word ptr
এর চেয়ে সুবিধাজনক ছিল:
mov ax,0 ; Data to store
mov cx,16 ; Number of words
mov di,bp
add di,offset fnord (i.e. 8)
rep movs fnord ; Address is ignored EXCEPT to note that it's an SS-relative word ptr
নোট করুন যে বিশ্বকে "অফসেট" ভুলে যাওয়া অবস্থানের বিষয়বস্তু [বিপি + 8] এর পরিবর্তে ডিআইতে যোগ করা হবে 8 উফ।
উল্লিখিত বিদ্যমান উত্তরের হিসাবে, LEA
স্মৃতি অ্যাক্সেস না করে পাটিগণিতকে সম্বোধন করার মেমরি সম্পাদন করার সুবিধা রয়েছে, অ্যাডিশনের সাধারণ ফর্মের পরিবর্তে পাটিগণিত ফলাফলকে আলাদা রেজিস্টারে সংরক্ষণ করা saving আসল অন্তর্নিহিত পারফরম্যান্স সুবিধাটি হ'ল আধুনিক প্রসেসরের কার্যকরী ঠিকানা উত্পাদনের জন্য পৃথক এলইএএএএলএ ইউনিট এবং বন্দর রয়েছে ( LEA
এবং অন্যান্য মেমরি রেফারেন্স ঠিকানা সহ ), এর অর্থ এটিএলইউতে পাটিগণিত অপারেশন LEA
এবং অন্যান্য স্বাভাবিক গাণিতিক অপারেশন একের মধ্যে সমান্তরালে করা যেতে পারে মূল.
এলইএ ইউনিট সম্পর্কে কিছু বিশদ জানতে হ্যাসওয়েল আর্কিটেকচারের এই নিবন্ধটি দেখুন: http://www.realworldtech.com/haswell-cpu/4/
অন্য গুরুত্বপূর্ণ বিষয় যা অন্য উত্তরে উল্লেখ করা হয়নি তা LEA REG, [MemoryAddress]
হ'ল পিআইসি (অবস্থান স্বতন্ত্র কোড) যা এই নির্দেশিকায় পিসির আপেক্ষিক ঠিকানা এনকোড করেMemoryAddress
। এটি আলাদা MOV REG, MemoryAddress
যা থেকে আপেক্ষিক ভার্চুয়াল ঠিকানা এনকোড করে এবং আধুনিক অপারেটিং সিস্টেমগুলিতে স্থান পরিবর্তন / প্যাচিংয়ের প্রয়োজন (যেমন ASLR সাধারণ বৈশিষ্ট্য)। সুতরাং LEA
যেমন নন পিআইসিকে পিআইসিতে রূপান্তর করতে ব্যবহার করা যেতে পারে।
lea
একই সংখ্যক ALU গুলির মধ্যে এক বা একাধিকের উপর চালিত করে যা অন্যান্য গাণিতিক নির্দেশাবলী কার্যকর করে (তবে সাধারণত অন্যান্য গাণিতিকের তুলনায় এর চেয়ে কম)) উদাহরণস্বরূপ, উল্লিখিত হাসওয়েল সিপিইউ চারটি বিভিন্ন এএলইউতে কার্যকর add
বা sub
বা অন্যান্য বেশ কয়েকটি বেসিক পাটিগণিত অপারেশন করতে পারে, তবে কেবলমাত্র একটি (জটিল ) বা দুটি (সাধারণ ) দিয়ে কার্যকর করতে পারে । আরও গুরুত্বপূর্ণ বিষয়, এই দুটি-সক্ষম যোগ্য এএলইউ হ'ল চারটির মধ্যে দুটি যা অন্য নির্দেশাবলী কার্যকর করতে পারে, তাই দাবি হিসাবে কোনও সমান্তরালতার সুবিধা নেই। lea
lea
lea
lea
এলইএর নির্দেশাবলী সিপিইউ দ্বারা কার্যকর ঠিকানার সময় গ্রহণের গণনা এড়াতে ব্যবহার করা যেতে পারে। যদি কোনও ঠিকানা বারবার ব্যবহার করা হয় তবে প্রতিবার কার্যকর ঠিকানাটি ব্যবহার করার পরিবর্তে এটি রেজিস্টারে সংরক্ষণ করা আরও কার্যকর।
[esi]
বলার চেয়ে কমই সস্তা [esi + 4200]
এবং এটির তুলনায় খুব কমই সস্তা [esi + ecx*8 + 4200]
।
[esi]
তুলনায় সস্তা নয় [esi + ecx*8 + 4200]
। তবে তুলনা কেন বিরক্ত করবেন? তারা সমতুল্য নয়। আপনি যদি পূর্বেরটিকে একই হিসাবে মেমরির অবস্থানটি একই হিসাবে চিহ্নিত করতে চান তবে আপনাকে অতিরিক্ত নির্দেশাবলীর দরকার: আপনি 8 দ্বারা গুণিত esi
মানটি যুক্ত করতে হবে ecx
h আহা, গুণ আপনার সিপিইউ ফ্ল্যাগগুলি আঁকতে চলেছে! তারপরে আপনাকে 4200 টি যুক্ত করতে হবে These
[esi + 4200]
নির্দেশের অনুক্রমে বারবার মতো কিছু ব্যবহার করতে চলেছেন তবে প্রথমে কার্যকর ঠিকানাটি একটি রেজিস্টারে লোড করা এবং এটি ব্যবহার করা ভাল। উদাহরণস্বরূপ, লেখার পরিবর্তে add eax, [esi + 4200]; add ebx, [esi + 4200]; add ecx, [esi + 4200]
আপনার পছন্দ করা উচিত lea edi, [esi + 4200]; add eax, [edi]; add ebx, [edi]; add ecx, [edi]
, যা খুব কমই দ্রুত হয়। অন্তত এই উত্তরটির সরল ব্যাখ্যা interpretation
[esi]
এবং [esi + 4200]
(বা [esi + ecx*8 + 4200]
এটি হ'ল ওপি প্রস্তাবিত সরলকরণ) (আমি বুঝতে পারছি): একই জটিল ঠিকানা সহ এন নির্দেশাবলী সরল (একটি রেজি) সম্বোধন, আরও একটি lea
, সহ এন নির্দেশিকায় রূপান্তরিত হয় , জটিল ঠিকানা হ'ল "সময় সাপেক্ষ"। বাস্তবে, এটি আধুনিক x86 এর চেয়েও ধীরে ধীরে, তবে কেবলমাত্র
lea
যাতে এটি সেই ক্ষেত্রে চাপ বাড়ে। সাধারণভাবে, মধ্যস্থতাকারীদের সংরক্ষণ করা নিবন্ধকের চাপের কারণ, এটির সমাধান নয় - তবে আমি মনে করি বেশিরভাগ পরিস্থিতিতে এটি ধোয়া। @ কাজ
এলইএ (লোড ইফেক্টিভ অ্যাড্রেস) নির্দেশিকা ঠিকানা প্রাপ্তির একটি উপায় যা ইন্টেল প্রসেসরের কোনও মেমরি অ্যাড্রেসিং মোড থেকে উদ্ভূত হয়।
এটি বলতে গেলে, আমাদের যদি কোনও ডেটা স্থানান্তর থাকে তবে:
MOV EAX, <MEM-OPERAND>
এটি লক্ষ্য রেজিস্টারে মনোনীত মেমরি অবস্থানের সামগ্রীগুলি সরিয়ে দেয়।
যদি আমরা MOV
বাই দ্বারা প্রতিস্থাপন করি LEA
, তবে মেমরির অবস্থানের ঠিকানা ঠিক ঠিক একই পদ্ধতিতে <MEM-OPERAND>
সম্বোধন অভিব্যক্তি দ্বারা গণনা করা হয় । তবে মেমরির অবস্থানের বিষয়বস্তুগুলির পরিবর্তে আমরা লোকেশনটি গন্তব্যে নিয়ে যাই।
LEA
নির্দিষ্ট গাণিতিক নির্দেশ নয়; এটি কোনও প্রসেসরের মেমোরি অ্যাড্রেসিং মোডগুলির মধ্য থেকে উত্পন্ন কার্যকর ঠিকানাটিকে বাধা দেওয়ার একটি উপায়।
উদাহরণস্বরূপ, আমরা LEA
কেবল একটি সাধারণ সরাসরি ঠিকানা ব্যবহার করতে পারি । কোনও গাণিতিক জড়িত না:
MOV EAX, GLOBALVAR ; fetch the value of GLOBALVAR into EAX
LEA EAX, GLOBALVAR ; fetch the address of GLOBALVAR into EAX.
এটি বৈধ; আমরা এটি লিনাক্স প্রম্পটে পরীক্ষা করতে পারি:
$ as
LEA 0, %eax
$ objdump -d a.out
a.out: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <.text>:
0: 8d 04 25 00 00 00 00 lea 0x0,%eax
এখানে, কোনও আকারযুক্ত মান যোগ করা যায় না, এবং কোনও অফসেট হয় না। জিরো EAX এ সরানো হয়েছে। আমরা তাত্ক্ষণিক অপরেন্ডের সাথে এমওভি ব্যবহার করে তা করতে পারি।
এই কারণেই এমন লোকেরা যারা মনে করেন বন্ধনীগুলি ভিতরে LEA
অতিমাত্রায় ব্যবহার করা হয় তারা মারাত্মকভাবে ভুল হয়; বন্ধনী নেইLEA
সিনট্যাক্স নয় তবে অ্যাড্রেসিং মোডের অংশ।
এলইএ হার্ডওয়্যার স্তরে আসল। উত্পন্ন নির্দেশটি প্রকৃত ঠিকানা মোডটিকে এনকোড করে এবং প্রসেসর এটিকে ঠিকানার গণনার পয়েন্ট পর্যন্ত বহন করে। তারপরে এটি ঠিকানাটি কোনও মেমরি রেফারেন্স তৈরির পরিবর্তে গন্তব্যে নিয়ে যায়। (যেহেতু অন্য কোনও নির্দেশে ঠিকানা মোডের ঠিকানা গণনার সিপিইউ ফ্ল্যাগগুলির কোনও প্রভাব নেই,LEA
কোনও প্রভাব নেই))
ঠিকানা শূন্য থেকে মান লোড করার সাথে বিপরীতে:
$ as
movl 0, %eax
$ objdump -d a.out | grep mov
0: 8b 04 25 00 00 00 00 mov 0x0,%eax
এটি একটি খুব অনুরূপ এনকোডিং, দেখুন? শুধু এর 8d
মধ্যে LEA
পরিবর্তিত হয়েছে8b
।
অবশ্যই, এই LEA
এনকোডিংটি তাত্ক্ষণিক শূন্যে সরানোর চেয়ে দীর্ঘ EAX
:
$ as
movl $0, %eax
$ objdump -d a.out | grep mov
0: b8 00 00 00 00 mov $0x0,%eax
LEA
এই সম্ভাবনাটি বাদ দেওয়ার কোনও কারণ নেই যদিও কেবল একটি সংক্ষিপ্ত বিকল্প রয়েছে; এটি কেবল উপলভ্য মোডের সাথে একটি orthogonal উপায়ে সংযুক্ত।
এখানে একটি উদাহরণ।
// compute parity of permutation from lexicographic index
int parity (int p)
{
assert (p >= 0);
int r = p, k = 1, d = 2;
while (p >= k) {
p /= d;
d += (k << 2) + 6; // only one lea instruction
k += 2;
r ^= p;
}
return r & 1;
}
সংকলক বিকল্প হিসাবে -O (অনুকূলিতকরণ) সহ, জিসিসি নির্দেশিত কোড লাইনের জন্য লি নির্দেশিকা সন্ধান করবে।
দেখে মনে হচ্ছে যে প্রচুর উত্তর ইতিমধ্যে সম্পূর্ণ, আমি একই রকম এক্সপ্রেশন ফর্ম্যাট থাকাকালীন কীভাবে লি এবং সরানো নির্দেশাবলী আলাদাভাবে কাজ করে তা দেখানোর জন্য আমি আরও একটি উদাহরণ কোড যুক্ত করতে চাই।
একটি দীর্ঘ গল্প সংক্ষিপ্ত করতে, লি নির্দেশিকা এবং মুভি নির্দেশাবলী উভয় নির্দেশকের src অপারেন্ডটি বন্ধনী বন্ধনীর সাথে ব্যবহার করা যেতে পারে। যখন তারা () দিয়ে সংযুক্ত থাকে , তখন () তে প্রকাশটি একইভাবে গণনা করা হয়; যাইহোক, দুটি নির্দেশাবলী src অপারেন্ডে গণনা করা মানটিকে অন্যভাবে ব্যাখ্যা করবে।
অভিব্যক্তিটি লি বা মুভের সাথে ব্যবহার করা হোক না কেন, এসআরসি মানটি নীচের হিসাবে গণনা করা হবে।
ডি (আরবি, রি, এস) => (রেগ [আরবি] + এস * রেজি [রি] + ডি)
যাইহোক, যখন এটি মুভ নির্দেশের সাথে ব্যবহার করা হয়, এটি উপরের অভিব্যক্তি দ্বারা উত্পন্ন ঠিকানা দ্বারা চিহ্নিত মানটি অ্যাক্সেস করার চেষ্টা করে এবং এটি গন্তব্যে সংরক্ষণ করে।
এর বিপরীতে, যখন লি নির্দেশিকাটি উপরের এক্সপ্রেশন দিয়ে কার্যকর করা হয়, তখন এটি উত্পন্ন মানটিকে গন্তব্য হিসাবে লোড করে।
নীচের কোডটি একই পরামিতি সহ লি নির্দেশিকা এবং মুভি নির্দেশকে কার্যকর করে। তবে, পার্থক্যটি ধরতে, আমি মুভের নির্দেশের ফলস্বরূপ কোনও ভুল ঠিকানা অ্যাক্সেস করার কারণে সেগমেন্টেশন ত্রুটিটি ধরতে একটি ব্যবহারকারী-স্তরের সিগন্যাল হ্যান্ডলার যুক্ত করেছি।
উদাহরণ কোড
#define _GNU_SOURCE 1 /* To pick up REG_RIP */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <signal.h>
uint32_t
register_handler (uint32_t event, void (*handler)(int, siginfo_t*, void*))
{
uint32_t ret = 0;
struct sigaction act;
memset(&act, 0, sizeof(act));
act.sa_sigaction = handler;
act.sa_flags = SA_SIGINFO;
ret = sigaction(event, &act, NULL);
return ret;
}
void
segfault_handler (int signum, siginfo_t *info, void *priv)
{
ucontext_t *context = (ucontext_t *)(priv);
uint64_t rip = (uint64_t)(context->uc_mcontext.gregs[REG_RIP]);
uint64_t faulty_addr = (uint64_t)(info->si_addr);
printf("inst at 0x%lx tries to access memory at %ld, but failed\n",
rip,faulty_addr);
exit(1);
}
int
main(void)
{
int result_of_lea = 0;
register_handler(SIGSEGV, segfault_handler);
//initialize registers %eax = 1, %ebx = 2
// the compiler will emit something like
// mov $1, %eax
// mov $2, %ebx
// because of the input operands
asm("lea 4(%%rbx, %%rax, 8), %%edx \t\n"
:"=d" (result_of_lea) // output in EDX
: "a"(1), "b"(2) // inputs in EAX and EBX
: // no clobbers
);
//lea 4(rbx, rax, 8),%edx == lea (rbx + 8*rax + 4),%edx == lea(14),%edx
printf("Result of lea instruction: %d\n", result_of_lea);
asm volatile ("mov 4(%%rbx, %%rax, 8), %%edx"
:
: "a"(1), "b"(2)
: "edx" // if it didn't segfault, it would write EDX
);
}
ফাঁসির ফলাফল
Result of lea instruction: 14
inst at 0x4007b5 tries to access memory at 14, but failed
=d
সংকলকটি বলতে ব্যবহার করতে পারেন ফলাফলটি EDX এ রয়েছে, একটি সংরক্ষণ করা mov
। আপনি আউটপুটটিতে একটি প্রাথমিক ক্লোবারের ঘোষণাও রেখে গেছেন। এটি আপনি যা প্রদর্শনের চেষ্টা করছেন তা প্রমাণ করে, তবে ইনলাইন asm এর একটি বিভ্রান্তিকর খারাপ উদাহরণ যা অন্য প্রসঙ্গে ব্যবহৃত হলে ভেঙে যাবে। স্ট্যাক ওভারফ্লো উত্তরের জন্য এটি একটি খারাপ জিনিস।
%%
বর্ধিত asm এ সমস্ত নিবন্ধের নাম লিখতে না চান তবে ইনপুট সীমাবদ্ধতাগুলি ব্যবহার করুন। মত asm("lea 4(%%ebx, %%eax, 8), %%edx" : "=d"(result_of_lea) : "a"(1), "b"(2));
। সংকলক আরআইজি রেজিস্টার দেওয়ার অর্থ হল আপনার ক্লোবারগুলি ঘোষণা করতে হবে না। আপনি মুভি-তাত্ক্ষণিকভাবে পুরো রেজিস্টারটিকে ওভাররাইট করার আগে আপনি জোর-শূন্যের মাধ্যমে জিনিসগুলিকে অতিরিক্ত জটিল করে তুলছেন।
mov 4(%ebx, %eax, 8), %edx
এটি অবৈধ? যাইহোক, হ্যাঁ, কারণ আপনার কাছে 64৪-বিট মান রয়েছে এমন সংকলকটি mov
লিখতে লিখতে হবে তা বোঝা যায় "a"(1ULL)
এবং এটি পুরো রেজিস্টারটি পূরণ করার জন্য এটি নিশ্চিত করা দরকার make অনুশীলনে এটি এখনও ব্যবহার করবে mov $1, %eax
, কারণ EAX লিখতে শূন্য প্রসারিত হয় RAX- এ, যদি না আপনার চারপাশের কোডের একটি উদ্ভট পরিস্থিতি থাকে যেখানে কম্পাইলার জানত যে RAX = 0xff00000001
বা অন্য কিছু। এর জন্য lea
, আপনি এখনও 32-বিট অপারেন্ড-আকার ব্যবহার করছেন, সুতরাং ইনপুট রেজিস্টারগুলিতে যে কোনও বিপুল উচ্চ বিট 32-বিটের ফলাফলের উপর কোনও প্রভাব ফেলবে না।
এলইএ: কেবল একটি "পাটিগণিত" নির্দেশ ..
এমওভি অপারেন্ডগুলির মধ্যে ডেটা স্থানান্তর করে তবে লিটা কেবল গণনা করছে
mov eax, offset GLOBALVAR
পরিবর্তে ব্যবহার করুন। আপনি এলইএ ব্যবহার করতে পারেন তবে এটি কোডের চেয়ে কিছুটা বড় আকারের mov r32, imm32
এবং কম বন্দরগুলিতে চালিত হয় কারণ এটি এখনও ঠিকানা-গণনা প্রক্রিয়াতে চলে । lea reg, symbol
যখন আপনি পিআইসি এবং / অথবা কম 32 বিটের বাইরে ঠিকানা প্রয়োজন তখন কেবল একটি আরআইপি-সম্পর্কিত আত্মীয় এলইএর জন্য 64৪-বিটের ক্ষেত্রে কার্যকর। 32 বা 16-বিট কোডে শূন্য সুবিধা রয়েছে। এলইএ একটি পাটিগণিত নির্দেশ যা সিপিইউর ডিকোড / কম্পিউটিং অ্যাড্রেসিং মোডের ক্ষমতা প্রকাশ করে।
imul eax, edx, 1
গণনা করা হয় না: এটি কেবল ইডেক্সকে ইমেক্স করে অনুলিপি করে। তবে আসলে এটি 3 টি চক্রের বিলম্বের সাথে গুণকের মাধ্যমে আপনার ডেটা চালায়। অথবা এটি rorx eax, edx, 0
কেবল অনুলিপিগুলি (শূন্যের সাথে ঘোরান)।
সমস্ত সাধারণ "গণনা" নির্দেশাবলী যেমন গুণন যোগ করা, একচেটিয়া বা শূন্য, চিহ্ন হিসাবে স্থিতির পতাকা সেট করে set আপনি যদি কোনও জটিল ঠিকানা ব্যবহার করেন, AX xor:= mem[0x333 +BX + 8*CX]
তবে জোর ক্রিয়াকলাপ অনুযায়ী পতাকাগুলি সেট করা হবে।
এখন আপনি ঠিকানাটি একাধিকবার ব্যবহার করতে চাইতে পারেন। নিবন্ধে এই জাতীয় ঠিকানা লোড করা কখনই স্থিতি পতাকা সেট করার উদ্দেশ্যে নয় এবং ভাগ্যক্রমে এটি হয় না। "লোড কার্যকর ঠিকানা" বাক্যাংশ প্রোগ্রামারকে সে সম্পর্কে সচেতন করে তোলে। অদ্ভুত প্রকাশটি এখান থেকেই আসে।
এটা স্পষ্ট যে প্রসেসর একবার তার বিষয়বস্তু প্রক্রিয়াজাত করার জন্য জটিল ঠিকানাটি ব্যবহার করতে সক্ষম হয়, এটি অন্যান্য উদ্দেশ্যে এটি গণনা করতে সক্ষম হয়। প্রকৃতপক্ষে এটি x <- 3*x+1
একটি নির্দেশে একটি রূপান্তর সম্পাদন করতে ব্যবহৃত হতে পারে । এটি অ্যাসেম্বলি প্রোগ্রামিংয়ের একটি সাধারণ নিয়ম: নির্দেশাবলী ব্যবহার করুন তবে এটি আপনার নৌকাকে দোলায়।
নির্দেশের দ্বারা সজ্জিত বিশেষ রূপান্তরটি আপনার পক্ষে কার্যকর কিনা তা কেবলমাত্র গণনা করা।
শেষের সারি
MOV, X| T| AX'| R| BX|
এবং
LEA, AX'| [BX]
এএক্স- তে একই প্রভাব রয়েছে তবে স্থিতির পতাকাগুলিতে নয়। (এটি সিয়াসডিস স্বরলিপি।)
call lbl
lbl: pop rax
প্রযুক্তিগতভাবে "কাজ করা" এর মতো মূল্য অর্জনের উপায় হিসাবে আমি ব্যক্তিগতভাবে সেই পরামর্শটি rip
দেব না, তবে আপনি শাখার ভবিষ্যদ্বাণীটি অত্যন্ত অসন্তুষ্ট করবেন make আপনি চাইছেন সেই নির্দেশাবলীটি ব্যবহার করুন তবে আপনি কোনও কৌশলপূর্ণ কিছু করলে অবাক হবেন না এবং এর
যদি ইতিমধ্যে কেউ উল্লেখ করে থাকে তবে আমাকে ক্ষমা করুন, তবে x86 এর দিনগুলিতে যখন মেমরি বিভাজন এখনও প্রাসঙ্গিক ছিল, আপনি এই দুটি নির্দেশাবলীর থেকে একই ফলাফল পেতে পারেন না:
LEA AX, DS:[0x1234]
এবং
LEA AX, CS:[0x1234]
seg:off
জুটির "অফসেট" অংশ । এলইএ সেগমেন্ট বেস দ্বারা প্রভাবিত হয় না; এই নির্দেশাবলী উভয়ই (অকার্যকরভাবে) 0x1234
এক্স এ দেওয়া হবে। দুর্ভাগ্যক্রমে দুর্ভাগ্যক্রমে কোনও রেজিস্টার বা রেজিস্টার-জুটিতে পূর্ণ রৈখিক ঠিকানা (কার্যকর + বিভাগ অংশ) গণনা করার সহজ উপায় নেই।