ट्रैक
/
Lean
Lean
/
अभ्यास
/
असेंबल कीजिए
असेंबल कीजिए

असेंबल कीजिए

कठिन

निर्देश

इस अभ्यास में आप एक छोटी भाषा का सिंटैक्स और निष्पादन मॉडल तय करेंगे, जो 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 में संग्रहीत की जाती है।

Note

रजिस्टर के नाम में छोटे और बड़े अक्षरों से कोई फर्क नहीं पड़ता। इसका मतलब है कि rax, RAX और rAx तीनों एक ही रजिस्टर को दिखाते हैं।

असेंबली कोड

असेंबली कोड की हर लाइन दो तरह की हो सकती है:

  • लेबल प्रोग्राम की कुछ खास जगहों को चिह्नित करते हैं, ताकि कुछ निर्देश उन जगहों का इस्तेमाल कर सकें।
  • निर्देश उन कामों को दिखाते हैं जो प्रोग्राम चलाता है।

जब तक कोई निर्देश इसे बदल न दे, प्रोग्राम का निष्पादन एक ही क्रम में आगे बढ़ता रहता है। इसका मतलब है कि एक लाइन पूरी तरह चल जाने के बाद ही उसके बाद वाली लाइन चलती है।

लेबल

लेबल का सिंटैक्स ऐसा है:

<label>:

लेबल किसी रजिस्टर की वैल्यू नहीं बदलते और प्रोग्राम पर कोई और असर भी नहीं डालते। वे सिर्फ कोड की कुछ खास जगहों को चिह्नित करते हैं, ताकि निर्देश उन जगहों का इस्तेमाल कर सकें।

Note

लेबल में छोटे और बड़े अक्षरों का फर्क मायने रखता है। इसका मतलब है कि 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 जंप करता है अगर आंतरिक स्थिति बड़ा हो
Note

निर्देशों के ऑपकोड में, चाहे वे दो ऑपरेंड वाले हों या एक ऑपरेंड वाले, छोटे और बड़े अक्षरों से कोई फर्क नहीं पड़ता। इसका मतलब है कि add, ADD और aDd तीनों एक ही निर्देश को दिखाते हैं।

GitHub के ज़रिए संपादित करें यह लिंक एक नई विंडो या टैब में खुलता है
Lean Exercism

असेंबल कीजिए शुरू करने के लिए तैयार हैं?

Exercism पर साइन अप कीजिए और Lean को 100 अभ्यास तथा असली इंसानों से मिलने वाली मेंटरिंग के साथ सीखिए और उसमें महारत हासिल कीजिए, वह भी बिल्कुल मुफ्त।