x86-64 মেশিন কোড, 30 বাইট
31 C0 99 8B 4C B7 FC F6 C1 01 74 04 01 CA EB 02 01 C8 FF CE 75 ED 29 D0 99 31 D0 29 D0 C3
উপরের কোডটি এমন একটি ফাংশন সংজ্ঞায়িত করে যা পূর্ণসংখ্যার অঙ্কের তালিকা / অ্যারে গ্রহণ করে এবং তার সমান সংখ্যার যোগফল এবং তার বিজোড় অঙ্কগুলির যোগফলের মধ্যে পরম পার্থক্য প্রদান করে।
সি হিসাবে , সমাবেশ ভাষা প্রথম শ্রেণীর ধরণের হিসাবে তালিকাগুলি বা অ্যারেগুলি প্রয়োগ করে না, বরং তাদেরকে পয়েন্টার এবং দৈর্ঘ্যের সংমিশ্রণ হিসাবে উপস্থাপন করে। অতএব, আমি এই ফাংশনটি দুটি পরামিতি গ্রহণ করার ব্যবস্থা করেছি: প্রথমটি হ'ল অঙ্কের তালিকার শুরুর দিকে একটি পয়েন্টার এবং দ্বিতীয়টি হল পূর্ণসংখ্যা যা তালিকার মোট দৈর্ঘ্য নির্দিষ্ট করে (সংখ্যার এক নম্বর, এক সূচকযুক্ত) ।
ফাংশনটি সিস্টেম ভি এএমডি .৪ কলিং কনভেনশনকে সম্মতি জানায় যা জ্ঞানু / ইউএনআইএক্স সিস্টেমের উপর প্রমিত। বিশেষত, প্রথম প্যারামিটার (তালিকার শুরুতে পয়েন্টার) পাস করা হয়েছে RDI
(এটি যেমন 64৪-বিট কোড, এটি একটি -৪-বিট পয়েন্টার) এবং দ্বিতীয় পরামিতি (তালিকার দৈর্ঘ্য) এখানে পাস করা হয় ESI
( এটি কেবলমাত্র একটি 32-বিট মান, কারণ এটি খেলতে পর্যাপ্ত সংখ্যাগুলির চেয়ে বেশি এবং স্বাভাবিকভাবেই এটি শূন্য নয় বলে ধরে নেওয়া হয়)। ফলাফলটি EAX
রেজিস্টারে ফিরে আসে ।
এটি যদি আরও পরিষ্কার হয় তবে এটি সি প্রোটোটাইপ (এবং আপনি এটি সি থেকে ফাংশনটি কল করতে ব্যবহার করতে পারেন):
int OddsAndEvens(int *ptrDigits, int length);
অবহেলিত সমাবেশ মেমোনমিক্স:
; parameter 1 (RDI) == pointer to list of integer digits
; parameter 2 (ESI) == number of integer digits in list (assumes non-zero, of course)
OddsAndEvens:
xor eax, eax ; EAX = 0 (accumulator for evens)
cdq ; EDX = 0 (accumulator for odds)
.IterateDigits:
mov ecx, [rdi+rsi*4-4] ; load next digit from list
test cl, 1 ; test last bit to see if even or odd
jz .IsEven ; jump if last bit == 0 (even)
.IsOdd: ; fall through if last bit != 0 (odd)
add edx, ecx ; add value to odds accumulator
jmp .Continue ; keep looping
.IsEven:
add eax, ecx ; add value to evens accumulator
.Continue: ; fall through
dec esi ; decrement count of digits in list
jnz .IterateDigits ; keep looping as long as there are digits left
sub eax, edx ; subtract odds accumulator from evens accumulator
; abs
cdq ; sign-extend EAX into EDX
xor eax, edx ; XOR sign bit in with the number
sub eax, edx ; subtract sign bit
ret ; return with final result in EAX
এখানে কোডের একটি সংক্ষিপ্ত পদচারণা:
- প্রথমত, আমরা নিবন্ধগুলি শূন্য করি
EAX
এবং EDX
এটি সমান এবং বিজোড় অঙ্কগুলির যোগফল যোগ করতে ব্যবহৃত হবে। EAX
রেজিস্টার দ্বারা পরিষ্কার করা হয় XOR
নিজেই (2 বাইটস) সঙ্গে এটি ing, এবং তারপর EDX
রেজিস্টার সাইন-ব্যাপ্ত তা EAX (দ্বারা পরিষ্কার করা হয় CDQ
, 1 বাইট)।
তারপরে, আমরা লুপটিতে যাই যা অ্যারেতে সমস্ত সংখ্যার মধ্য দিয়ে পুনরাবৃত্তি করে। এটি একটি অঙ্ক পুনরুদ্ধার করে, এটি সমান বা বিজোড় কিনা তা পরীক্ষা করে (সর্বনিম্ন-তাত্পর্যপূর্ণ বিটটি পরীক্ষা করে, যা মানটি যদি সমান হয় তবে 1 হয় বা এটি বিজোড় হলে 1 হয়) এবং তারপরে লাফ দেয় বা পড়ে যায়, যোগ করে যোগ করে উপযুক্ত সঞ্চয়ের মান। লুপের নীচে, আমরা অঙ্কের কাউন্টারটি হ্রাস করব ( ESI
) এবং যতক্ষণ না এটি শূন্যহীন হয় ততক্ষণ লুপিং চালিয়ে যাব (যেমন, তালিকায় আরও অঙ্কগুলি পুনরুদ্ধার করার জন্য যতক্ষণ থাকবে)।
এখানে মুশকিল জিনিস হ'ল প্রাথমিক এমওভি নির্দেশনা, যা x86-এ সম্ভব সবচেয়ে জটিল সম্বোধন মোড ব্যবহার করে। * এটি RDI
বেস নিবন্ধ হিসাবে (তালিকার শুরুতে নির্দেশক), স্কেলগুলি RSI
(দৈর্ঘ্যের কাউন্টার, যা সূচক হিসাবে কাজ করে) 4 দ্বারা (একটি পূর্ণসংখ্যার আকার, বাইটে) যোগ করে এবং এটি বেসকে যুক্ত করে, এবং তারপরে মোট থেকে ৪ টি বিয়োগ করে (কারণ দৈর্ঘ্যের কাউন্টারটি এক-ভিত্তিক এবং আমাদের অফসেটটি শূন্য-ভিত্তিক হওয়া দরকার)। এটি অ্যারেতে অঙ্কের ঠিকানা দেয় যা পরে ECX
রেজিস্টারে লোড হয় ।
লুপটি শেষ হওয়ার পরে, আমরা সন্ধ্যা ( EAX -= EDX
) থেকে প্রতিকূলের বিয়োগফলটি করি ।
পরিশেষে, আমরা একটি সাধারণ কৌশল ব্যবহার করে পরম মানটি গণনা করি most একই abs
ফাংশনের জন্য বেশিরভাগ সি সংকলক দ্বারা ব্যবহৃত । এই কৌশলটি এখানে কীভাবে কাজ করে সে সম্পর্কে আমি বিশদে যাব না; ইঙ্গিতগুলির জন্য কোড মন্তব্যগুলি দেখুন বা একটি ওয়েব অনুসন্ধান করুন।
__ * কোডিংটি
সহজ সম্বোধনের মোডগুলি ব্যবহার করার জন্য পুনরায় লেখা যেতে পারে, তবে এটি কোনও ছোট হয় না। আমি একটি বিকল্প বাস্তবায়ন নিয়ে আসতে সক্ষম হয়েছি RDI
যা লুপের মাধ্যমে প্রতিবার এটি 8 টি দ্বারা নিখুঁত হয় এবং বাড়িয়ে দেয় তবে আপনাকে এখনও কাউন্টারটি কমিয়ে আনতে হয় ESI
, এটি একই 30 বাইট হিসাবে পরিণত হয়েছিল। প্রাথমিকভাবে যা আমাকে আশা দিয়েছিল তা add eax, DWORD PTR [rdi]
হ'ল এটি কেবল 2 বাইট, দুটি নিবন্ধিত মান যুক্ত করার মতো। এই বাস্তবায়নটি এখানে, যদি কেউ আমাকে কিছুটা প্রচেষ্টা চালিয়ে যায় :-)
OddsAndEvens_Alt:
31 C0 xor eax, eax
99 cdq
.IterateDigits:
F6 07 01 test BYTE PTR [rdi], 1
74 04 je .IsEven
.IsOdd:
03 17 add edx, DWORD PTR [rdi]
EB 02 jmp .Continue
.IsEven:
03 07 add eax, DWORD PTR [rdi]
.Continue:
48 83 C7 08 add rdi, 8
FF CE dec esi
75 ED jne .IterateDigits
29 D0 sub eax, edx
99 cdq
31 D0 xor eax, edx
29 D0 sub eax, edx
C3 ret