इस अभ्यास में आप एक छोटी भाषा का सिंटैक्स और निष्पादन मॉडल तय करेंगे, जो x86-64 असेंबली भाषा से प्रेरित है।
इसका उद्देश्य यह स्पष्ट करना है कि सीमित वातावरण में कोड कैसे लिखा जाता है, कैसे पार्स किया जाता है और कैसे चलाया जाता है।
आपका असेंबली कोड एक खास कंस्ट्रक्ट के अंदर लिखा जाएगा:
let program := assemble!(
-- assembly code here
)
इस कंस्ट्रक्ट से एक प्रोग्राम बनना चाहिए, जो उस फंक्शन की तरह काम करता है जो असेंबली कोड चलाता है और एक वैल्यू लौटाता है।
इसके बाद इस प्रोग्राम को नीचे दिए सिंटैक्स से कॉल किया जाता है, जहाँ a, b, c आदि आर्गुमेंट हैं:
let result := program(a, b, c, ...)
सभी आर्गुमेंट और रिटर्न वैल्यू 64-बिट चिह्नित पूर्णांक होते हैं। अधिकतम 6 आर्गुमेंट की अनुमति है।
रिटर्न वैल्यू और सभी आर्गुमेंट रजिस्टर में भेजे जाते हैं। आपकी भाषा में इन रजिस्टर का समर्थन होना चाहिए:
| रजिस्टर | भूमिका |
|---|---|
rdi |
पहला आर्गुमेंट |
rsi |
दूसरा आर्गुमेंट |
rdx |
तीसरा आर्गुमेंट |
rcx |
चौथा आर्गुमेंट |
r8 |
पाँचवाँ आर्गुमेंट |
r9 |
छठा आर्गुमेंट |
rax |
रिटर्न वैल्यू |
शुरू में हर रजिस्टर की वैल्यू 0 होती है, सिवाय उन रजिस्टर के जो फंक्शन को आर्गुमेंट भेजने के काम आते हैं।
उदाहरण के लिए, नीचे दिए गए प्रोग्राम में सभी रजिस्टर की वैल्यू 0 है। अपवाद हैं rdi, जिसमें शुरू में 10 रखा जाता है, और rsi, जिसमें शुरू में -20:
program(10, -20)
प्रोग्राम की रिटर्न वैल्यू हमेशा rax में संग्रहीत की जाती है।
रजिस्टर के नाम में छोटे और बड़े अक्षरों से कोई फर्क नहीं पड़ता।
इसका मतलब है कि rax, RAX और rAx तीनों एक ही रजिस्टर को दिखाते हैं।
असेंबली कोड की हर लाइन दो तरह की हो सकती है:
जब तक कोई निर्देश इसे बदल न दे, प्रोग्राम का निष्पादन एक ही क्रम में आगे बढ़ता रहता है। इसका मतलब है कि एक लाइन पूरी तरह चल जाने के बाद ही उसके बाद वाली लाइन चलती है।
लेबल का सिंटैक्स ऐसा है:
<label>:
लेबल किसी रजिस्टर की वैल्यू नहीं बदलते और प्रोग्राम पर कोई और असर भी नहीं डालते। वे सिर्फ कोड की कुछ खास जगहों को चिह्नित करते हैं, ताकि निर्देश उन जगहों का इस्तेमाल कर सकें।
लेबल में छोटे और बड़े अक्षरों का फर्क मायने रखता है।
इसका मतलब है कि Start, start और sTart तीनों अलग-अलग लेबल हैं।
ज़्यादातर निर्देशों का सिंटैक्स ऐसा होता है:
<opcode> <destination>, <source>
opcode बताता है कि कौन-सा काम किया जा रहा है, और इसके लिए वह destination और source ऑपरेंड की वैल्यू इस्तेमाल करता है।
काम का नतीजा destination ऑपरेंड में रखा जाता है।
उदाहरण के लिए, add निर्देश destination और source ऑपरेंड की वैल्यू जोड़ता है और यह नतीजा destination ऑपरेंड में रख देता है।
destination ऑपरेंड हमेशा एक रजिस्टर होता है, जबकि source ऑपरेंड कोई रजिस्टर या लिटरल संख्या हो सकता है।
आपके प्रोग्राम को इन निर्देशों का समर्थन करना चाहिए:
| ऑपकोड | किया जाने वाला काम |
|---|---|
mov |
destination := source |
add |
destination := destination + source |
sub |
destination := destination - source |
mul |
destination := destination * source |
div |
destination := destination / source |
xor |
destination := destination ^^^ source |
and |
destination := destination &&& source |
or |
destination := destination ||| source |
shl |
destination := destination <<< source |
shr |
destination := destination >>> source |
इनके अलावा, आपके प्रोग्राम को दो ऑपरेंड वाले cmp निर्देश का समर्थन भी करना चाहिए।
यह निर्देश किसी रजिस्टर को नहीं बदलता। इसके बजाय यह destination और source ऑपरेंड की तुलना करता है और प्रोग्राम की आंतरिक स्थिति को तीन में से एक विकल्प पर सेट कर देता है:
destination > source
destination == source
destination < source
आंतरिक रूप से इस स्थिति का हिसाब आप कैसे रखते हैं, यह आप पर है।
कुछ निर्देश प्रोग्राम के क्रम को बदल देते हैं और निष्पादन को कोड के किसी दूसरी जगह पर पहुँचा देते हैं। इन्हें जंप निर्देश कहा जाता है।
इन सभी में सिर्फ एक ऑपरेंड लगता है, जो एक लेबल होता है और यह बताता है कि जंप कहाँ जाएगा, यानी कोड के उस बिंदु तक जहाँ से निष्पादन आगे बढ़ेगा:
<opcode> <label>
jmp निर्देश हमेशा लक्ष्य लेबल तक जंप करता है।
बाकी जंप निर्देश सिर्फ तभी जंप करते हैं जब प्रोग्राम की आंतरिक स्थिति किसी खास वैल्यू पर सेट हो।
इसका मतलब है कि इनसे पहले आम तौर पर एक cmp निर्देश आता है।
आपके प्रोग्राम को इन जंप निर्देशों का समर्थन करना चाहिए:
| निर्देश | किया जाने वाला काम |
|---|---|
jmp |
बिना शर्त जंप। जंप हमेशा किया जाता है |
je |
जंप करता है अगर आंतरिक स्थिति बराबर हो |
jl |
जंप करता है अगर आंतरिक स्थिति छोटा हो |
jg |
जंप करता है अगर आंतरिक स्थिति बड़ा हो |
निर्देशों के ऑपकोड में, चाहे वे दो ऑपरेंड वाले हों या एक ऑपरेंड वाले, छोटे और बड़े अक्षरों से कोई फर्क नहीं पड़ता।
इसका मतलब है कि add, ADD और aDd तीनों एक ही निर्देश को दिखाते हैं।
Exercism पर साइन अप कीजिए और Lean को 100 अभ्यास तथा असली इंसानों से मिलने वाली मेंटरिंग के साथ सीखिए और उसमें महारत हासिल कीजिए, वह भी बिल्कुल मुफ्त।