Exercism-এর x86-64 ট্র্যাকটি অ্যাসেম্বলার হিসেবে NASM (The Netwide Assembler) ব্যবহার করে।
NASM-এ মন্তব্যের শুরুতে একটি সেমিকোলন (;) বসানো হয়।
মন্তব্য প্রোগ্রামের যেকোনো জায়গায় রাখা যায়, আর একটি ; চিহ্নের পরে যা-ই আসুক, অ্যাসেম্বলার সেটি উপেক্ষা করে।
NASM-এ equ ব্যবহার করে অ্যাসেম্বলার-টাইম কনস্ট্যান্ট ডিফাইন করা যায়।
যেমন, এটি UNIVERSE নামের একটি কনস্ট্যান্ট ডিফাইন করে, যার মান 42:
UNIVERSE equ 42
কনস্ট্যান্ট ডিফাইন করার সময়ই একবার এর মান নির্ধারিত হয়, আর পরে এটি পুনরায় ডিফাইন করা যায় না।
অ্যাসেম্বলিতে ভ্যারিয়েবলের বদলে মান সংরক্ষণ করতে আমরা সাধারণত রেজিস্টার ব্যবহার করি। CPU রেজিস্টার হলো কম্পিউটারের প্রসেসরের ভেতরে থাকা এক টুকরো দ্রুতগতির মেমোরি। বেশিরভাগ গণনাই CPU-র রেজিস্টারে সম্পন্ন হয়।
কিছু রেজিস্টার নানা রকম গণনায় ব্যবহৃত হয়, এদের বলা হয় জেনারেল পারপাস রেজিস্টার (GPRs)। আবার কিছু রেজিস্টারের বিশেষ বা নির্দিষ্ট কাজ রয়েছে।
x86-64-এ ষোলটি ৬৪-বিট জেনারেল পারপাস রেজিস্টার (GPRs) আছে, যেগুলোকে ৩২-বিট, ১৬-বিট বা ৮-বিট হিসেবেও অ্যাক্সেস করা যায়।
GPR-গুলো নিচে বর্ণনা করা হয়েছে, যেখানে rn-এর n ৮ থেকে ১৫ পর্যন্ত হয়: r8, r9, r10, r11, r12, r13, r14 এবং r15।
| 64-bit | 32-bit | 16-bit | 8-bit |
|---|---|---|---|
| rax | eax | ax | ah/al |
| rbx | ebx | bx | bh/bl |
| rcx | ecx | cx | ch/cl |
| rdx | edx | dx | dh/dl |
| rsi | esi | si | sil |
| rdi | edi | di | dil |
| rbp | ebp | bp | bpl |
| rsp | esp | sp | spl |
| rn | rnd | rnw | rnb |
৬৪ বিটের কম ব্যবহার করলে, সাধারণত রেজিস্টারের নিচের অংশ থেকে বিটগুলো অ্যাক্সেস করা হয়।
এই নিয়মের ব্যতিক্রম হলো ah, bh, ch এবং dh, যেগুলো রেজিস্টারের ১৬-বিট অংশের উপরের ৮ বিট অ্যাক্সেস করে।
rax রেজিস্টারের বিটগুলো কীভাবে অ্যাক্সেস করা হয় তার একটি চিত্র:
+--------+---------------------------------------+
| 64-bit | rax |
+--------+-------------------+-------------------+
| 32-bit | | eax |
+--------+-------------------+---------+---------+
| 16-bit | | ax |
+--------+-----------------------------+----+----+
| 8-bit | | ah | al |
+--------+-----------------------------+----+----+
এই রেজিস্টারগুলোর মধ্যে কিছু ফাংশন কলের আগে-পরে সংরক্ষণ করতে হয়: rbp, rsp, rbx, r12, r13, r14 এবং r15।
এগুলো সংরক্ষণ না করলে এরর হতে পারে, কিংবা আচরণ অনির্ধারিত হয়ে যেতে পারে।
বাকিগুলো সংরক্ষণ করার দরকার নেই এবং স্বাধীনভাবে ব্যবহার করা যায়: rax, rcx, rdx, rdi, rsi, r8, r9, r10 এবং r11।
সিলেবাসে পরে আপনি শিখবেন কীভাবে রেজিস্টার সংরক্ষণ করতে হয়।
আপাতত শুধু দ্বিতীয় ধরনের রেজিস্টারগুলো ব্যবহার করুন: rax, rcx, rdx, rdi, rsi, r8, r9, r10 এবং r11।
নির্দেশনা হলো এমন কিছু গণনা, যা একটি CPU সম্পাদন করতে পারে। এগুলোর সাধারণ রূপটি হলো:
name destination, source
অর্থাৎ, নির্দেশনার নামটি প্রথমে বসে, তারপর অন্তত একটি হোয়াইটস্পেস, এরপর ডেস্টিনেশন অপারেন্ড, একটি কমা (,), এবং শেষে সোর্স অপারেন্ড।
সাধারণত নির্দেশনাটি সোর্স অপারেন্ড পরিবর্তন করে না, শুধু ডেস্টিনেশন অপারেন্ডই পরিবর্তিত হয়।
অন্যথায় বলা না থাকলে দুই অপারেন্ডেরই একই সাইজ হতে হবে। যেমন, সোর্স অপারেন্ডের ১৬ বিট থাকলে ডেস্টিনেশন অপারেন্ডেও ১৬ বিট থাকতে হবে।
যেমন, একটি রেজিস্টারে একটি মান রাখতে আমরা mov নির্দেশনা ব্যবহার করতে পারি:
mov rax, rdx ; rax = rdx
; mov is the name, rax is the destination operand and rdx is the source operand
উপরের স্নিপেটটি সোর্স অপারেন্ড rdx-এর ৬৪ বিটের পুরো কনটেন্ট ডেস্টিনেশন অপারেন্ড rax-এর ৬৪ বিটে কপি করে।
বেশিরভাগ নির্দেশনায় সোর্স অপারেন্ড হিসেবে ধ্রুবক ইন্টিজার সংখ্যা ব্যবহার করা সম্ভব (তবে ডেস্টিনেশন অপারেন্ড হিসেবে নয়):
mov rcx, 42 ; rcx = 42
; rcx is the destination operand and 42 is the source operand
মনে রাখবেন, কোনো ৩২-বিট রেজিস্টারে লিখলে উপরের বিটগুলোও মুছে যায়, তাই mov eax, 42 আর mov rax, 42 একই কাজ করে।
১৬-বিট ও ৮-বিট রেজিস্টারের ক্ষেত্রে এটি সত্য নয়।
যোগ, বিয়োগ ও গুণের মতো গাণিতিক কাজে আমরা add, sub এবং imul নির্দেশনা ব্যবহার করতে পারি:
add rax, rsi ; rax = rax + rsi
imul rax, rdi ; rax = rax * rdi
sub rax, r8 ; rax = rax - r8
নির্দেশনাগুলো ফাংশনে সাজানো হয়। সব ফাংশনই সোর্স ফাইলের section .text অংশে রাখা হয়।
একটি ফাংশন ডিক্লারেশনে থাকে:
:।ret।এই ট্র্যাকটি System V AMD64 ABI কলিং কনভেনশন ব্যবহার করে, এবং প্রথম ছয়টি ইন্টিজার আর্গুমেন্ট রেজিস্টারে ফাংশনে পাঠানো হয়।
এগুলো এই ক্রমে পাঠানো হয়: rdi, rsi, rdx, rcx, r8 এবং r9।
ফাংশন থেকে ইন্টিজার মান rax রেজিস্টারে রিটার্ন করা হয়।
একটি ফাংশন কল করতে আমরা call নির্দেশনা ব্যবহার করি।
একই সোর্স ফাইলের যেকোনো জায়গা থেকেই একটি ফাংশন কল করা যায়।
একটি ফাংশনকে অন্য সোর্স ফাইল থেকে দৃশ্যমান করতে global ডিরেক্টিভটি ব্যবহার করতে হয়।
যেমন, এটি sum নামের একটি ফাংশন ডিক্লেয়ার করে:
section .text ; functions are placed here
global sum ; sum is visible to other source files
sum:
; first argument is passed in rdi
; second argument is passed in rsi
; return value is placed in rax
mov rax, rdi ; rax is now equal to rdi
add rax, rsi ; rax = rax + rsi
ret ; function return
আর এটি আর্গুমেন্ট ৩ ও ৫ দিয়ে আমাদের sum ফাংশনটি কল করে:
mov rdi, 3 ; First argument in rdi
mov rsi, 5 ; Second argument in rsi
call sum
; The rax register now contains the value 8 (3 + 5), after sum returns
এই অনুশীলনীতে আপনি আপনার প্রিয় রান্নার বই থেকে একটি দুর্দান্ত লাসাগনা রান্না করতে সাহায্য করার জন্য কিছু কোড লিখবেন।
আপনার চারটি কাজ আছে, সবগুলোই লাসাগনা রান্না করতে লাগা সময়ের সাথে সম্পর্কিত।
এই কনসেপ্টে উল্লেখিত নির্দেশনাগুলো এই:
| নির্দেশ | বর্ণনা |
|---|---|
| mov a, b | b থেকে a-তে কনটেন্ট কপি করে |
| add a, b | a = a + b |
| sub a, b | a = a - b |
| imul a, b | a = a * b |
| call a | a ফাংশনটি কল করে |
| ret | একটি ফাংশন থেকে রিটার্ন করে |
expected_minutes_in_oven ফাংশনটি ডিফাইন করুন, যা কোনো প্যারামিটার নেয় না এবং রিটার্ন করে লাসাগনাটি কত মিনিট ওভেনে থাকা উচিত।
রান্নার বই অনুযায়ী, মিনিটে প্রত্যাশিত ওভেন সময় হলো 40:
expected_minutes_in_oven();
// => 40
remaining_minutes_in_oven ফাংশনটি ডিফাইন করুন, যা প্যারামিটার হিসেবে নেয় লাসাগনাটি ইতিমধ্যে কত মিনিট ওভেনে রয়েছে, এবং আগের কাজের মিনিটে প্রত্যাশিত ওভেন সময়ের ভিত্তিতে রিটার্ন করে লাসাগনাটিকে আর কত মিনিট ওভেনে থাকতে হবে।
remaining_minutes_in_oven(30);
// => 10
preparation_time_in_minutes ফাংশনটি ডিফাইন করুন, যা প্যারামিটার হিসেবে নেয় আপনি লাসাগনায় কত স্তর যোগ করেছেন, এবং রিটার্ন করে লাসাগনা প্রস্তুত করতে আপনি কত মিনিট ব্যয় করেছেন, ধরে নিয়ে যে প্রতিটি স্তর প্রস্তুত করতে আপনার 2 মিনিট লাগে।
preparation_time_in_minutes(2);
// => 4
elapsed_time_in_minutes ফাংশনটি ডিফাইন করুন, যা দুটি প্যারামিটার নেয়, এই ক্রমে:
ফাংশনটি রিটার্ন করবে লাসাগনা রান্না করতে আপনি কত মিনিট কাজ করেছেন। এটি হলো মিনিটে প্রস্তুতির সময় এবং এই মুহূর্তে লাসাগনাটি ওভেনে যত মিনিট কাটিয়েছে তার যোগফল।
elapsed_time_in_minutes(3, 20);
// => 26
Exercism-এ সাইন আপ করুন, x86-64 Assembly ট্র্যাকের 22টি কনসেপ্ট130টি অনুশীলনী আর সত্যিকারের মানুষের মেন্টরিং দিয়ে শিখুন ও দক্ষ হয়ে উঠুন, সম্পূর্ণ বিনামূল্যে।