MIPS बुला सम्मेलन a3
और के माध्यम से रजिस्टर a0
में होने की पहले चार फ़ंक्शन पैरामीटर की आवश्यकता है बाकी, अगर स्टैक पर अधिक हैं। इसके अलावा, रजिस्टरों में पारित होने के बावजूद, पहले चार पैरामीटर के लिए स्टैक पर चार स्लॉट आवंटित करने के लिए फ़ंक्शन कॉलर की भी आवश्यकता होती है।
तो, यदि आप पैरामीटर पांच (और आगे पैरामीटर) तक पहुंचना चाहते हैं, तो आपको sp
का उपयोग करने की आवश्यकता है। यदि फ़ंक्शन बदले में अन्य फ़ंक्शंस कॉल करता है और कॉल के बाद इसके पैरामीटर का उपयोग करता है, तो उसे खोने/ओवरराइट करने से बचने के लिए स्टैक पर उन चार स्लॉट में a0
a3
स्टोर करना होगा। फिर, आप इन रजिस्टरों को स्टैक पर लिखने के लिए sp
का उपयोग करें।
यदि आपके फ़ंक्शन में स्थानीय चर हैं और वे सभी रजिस्टरों में नहीं रख सकते हैं (जैसे a0
a3
के माध्यम से जब यह अन्य कार्यों को कॉल करता है), तो उन लोगों के लिए ऑन-स्टैक स्पेस का उपयोग करना होगा स्थानीय चर, जो फिर से sp
के उपयोग की आवश्यकता है।
उदाहरण के लिए, अगर आप इस था:
int tst5(int x1, int x2, int x3, int x4, int x5)
{
return x1 + x2 + x3 + x4 + x5;
}
अपने disassembly की तरह कुछ होगा:
tst5:
lw $2,16($sp) # r2 = x5; 4 slots are skipped
addu $4,$4,$5 # x1 += x2
addu $4,$4,$6 # x1 += x3
addu $4,$4,$7 # x1 += x4
j $31 # return
addu $2,$4,$2 # r2 += x1
देखें, sp
x5
उपयोग करने के लिए प्रयोग किया जाता है।
और फिर आप इस तरह कोड कुछ है अगर:
int binary(int a, int b)
{
return a + b;
}
void stk(void)
{
binary(binary(binary(1, 2), binary(3, 4)), binary(binary(5, 6), binary(7, 8)));
}
यह है कि क्या यह संकलन के बाद disassembly में दिखाई देता है:
binary:
j $31 # return
addu $2,$4,$5 # r2 = a + b
stk:
subu $sp,$sp,32 # allocate space for local vars & 4 slots
li $4,0x00000001 # 1
li $5,0x00000002 # 2
sw $31,24($sp) # store return address on stack
sw $17,20($sp) # preserve r17 on stack
jal binary # call binary(1,2)
sw $16,16($sp) # preserve r16 on stack
li $4,0x00000003 # 3
li $5,0x00000004 # 4
jal binary # call binary(3,4)
move $16,$2 # r16 = binary(1,2)
move $4,$16 # r4 = binary(1,2)
jal binary # call binary(binary(1,2), binary(3,4))
move $5,$2 # r5 = binary(3,4)
li $4,0x00000005 # 5
li $5,0x00000006 # 6
jal binary # call binary(5,6)
move $17,$2 # r17 = binary(binary(1,2), binary(3,4))
li $4,0x00000007 # 7
li $5,0x00000008 # 8
jal binary # call binary(7,8)
move $16,$2 # r16 = binary(5,6)
move $4,$16 # r4 = binary(5,6)
jal binary # call binary(binary(5,6), binary(7,8))
move $5,$2 # r5 = binary(7,8)
move $4,$17 # r4 = binary(binary(1,2), binary(3,4))
jal binary # call binary(binary(binary(1,2), binary(3,4)), binary(binary(5,6), binary(7,8)))
move $5,$2 # r5 = binary(binary(5,6), binary(7,8))
lw $31,24($sp) # restore return address from stack
lw $17,20($sp) # restore r17 from stack
lw $16,16($sp) # restore r16 from stack
addu $sp,$sp,32 # remove local vars and 4 slots
j $31 # return
nop
मुझे आशा है कि मैं गलतियों के बिना कोड एनोटेट गए हैं।
तो, ध्यान दें कि कंपाइलर फ़ंक्शन में r16
और r17
का उपयोग करना चुनता है लेकिन उन्हें स्टैक पर संरक्षित करता है। चूंकि फ़ंक्शन किसी अन्य को कॉल करता है, इसलिए उसे इसे r31
में रखने के बजाय स्टैक पर अपना रिटर्न पता सुरक्षित रखना होगा।
पीएस याद रखें कि एमआईपीएस पर सभी शाखा/कूद निर्देश वास्तव में तुरंत एक नए स्थान पर नियंत्रण स्थानांतरित करने से पहले तुरंत निम्नलिखित निर्देश निष्पादित करते हैं। यह भ्रमित हो सकता है।
आपको पते के लिए हस्ताक्षरित ऐड/सब का उपयोग करना चाहिए, या यदि ओवरफ्लो है (0x7FFFFFFF और 0x80000000 के बीच की सीमा पार कर रहा है) तो आप अपवाद/जाल को जोखिम दे रहे हैं। –
अभ्यास में हां, लेकिन परीक्षण के प्रयोजनों के लिए मुझे नहीं लगता कि उसे हमें उस सूक्ष्मता को समझने की आवश्यकता है। –