लागू alloca
वास्तव में को कंपाइलर सहायता की आवश्यकता होती है। यहां कुछ लोग यह कह रहे हैं कि यह आसान है:
sub esp, <size>
जो दुर्भाग्य से तस्वीर का केवल आधा है। हां, जो "ढेर पर जगह आवंटित करेगा" लेकिन कुछ मिलचास हैं।
अगर संकलक कोड जो अन्य चर के बजाय esp
को सापेक्ष संदर्भ उत्सर्जित था ebp
(विशिष्ट अगर आप कोई फ्रेम सूचक के साथ संकलन)। फिर उन संदर्भों को समायोजित करने की आवश्यकता है। फ्रेम पॉइंटर्स के साथ भी, कंपाइलर्स कभी-कभी ऐसा करते हैं।
अधिक महत्वपूर्ण रूप से, परिभाषा के अनुसार, alloca
के साथ आवंटित स्थान कार्य समाप्त होने पर "मुक्त" होना चाहिए।
बड़ा एक बिंदु # 2 है। क्योंकि आप को को संकलित करने के लिए कोड को उत्सर्जित करने के लिए <size>
esp
को फ़ंक्शन के प्रत्येक निकास बिंदु पर जोड़ने के लिए संकलक की आवश्यकता है।
सबसे अधिक संभावना यह है कि संकलक कुछ अंतर्निहित प्रदान करता है जो लाइब्रेरी लेखकों को आवश्यक सहायता के लिए कंपाइलर से पूछने की अनुमति देता है।
संपादित करें:
वास्तव में, glibc (libc की जीएनयू के कार्यान्वयन) में। alloca
के कार्यान्वयन बस यह है:
#ifdef __GNUC__
# define __alloca(size) __builtin_alloca (size)
#endif /* GCC. */
संपादित करें:
इस बारे में सोच के बाद, कम से कम मेरा मानना है कि को संकलक के लिए किया जाएगा की आवश्यकता होगी हमेशा किसी में एक फ्रेम सूचक का उपयोग फ़ंक्शन ऑप्टिमाइज़ेशन सेटिंग्स के बावजूद alloca
का उपयोग करता है। यह सभी स्थानीय लोगों को ebp
के माध्यम से सुरक्षित रूप से संदर्भित करने की अनुमति देगा और फ्रेम क्लीनर को फ्रेम सूचक को esp
पर पुनर्स्थापित करके संभाला जाएगा।
संपादित करें:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define __alloca(p, N) \
do { \
__asm__ __volatile__(\
"sub %1, %%esp \n" \
"mov %%esp, %0 \n" \
: "=m"(p) \
: "i"(N) \
: "esp"); \
} while(0)
int func() {
char *p;
__alloca(p, 100);
memset(p, 0, 100);
strcpy(p, "hello world\n");
printf("%s\n", p);
}
int main() {
func();
}
जो दुर्भाग्य से सही ढंग से काम नहीं करता है:
तो मैं इस तरह चीजों के साथ कुछ प्रयोग किया था। जीसीसी द्वारा असेंबली आउटपुट का विश्लेषण करने के बाद। ऐसा प्रतीत होता है कि अनुकूलन रास्ते में आते हैं। समस्या यह प्रतीत होती है कि चूंकि संकलक का अनुकूलक पूरी तरह से मेरी इनलाइन असेंबली से अनजान है, इसलिए इसमें अप्रत्याशित क्रम में चीजों को करने की आदत है और अभी भीesp
के माध्यम से चीजों का संदर्भ देने की आदत है।
8048454: push ebp
8048455: mov ebp,esp
8048457: sub esp,0x28
804845a: sub esp,0x64 ; <- this and the line below are our "alloc"
804845d: mov DWORD PTR [ebp-0x4],esp
8048460: mov eax,DWORD PTR [ebp-0x4]
8048463: mov DWORD PTR [esp+0x8],0x64 ; <- whoops! compiler still referencing via esp
804846b: mov DWORD PTR [esp+0x4],0x0 ; <- whoops! compiler still referencing via esp
8048473: mov DWORD PTR [esp],eax ; <- whoops! compiler still referencing via esp
8048476: call 8048338 <[email protected]>
804847b: mov eax,DWORD PTR [ebp-0x4]
804847e: mov DWORD PTR [esp+0x8],0xd ; <- whoops! compiler still referencing via esp
8048486: mov DWORD PTR [esp+0x4],0x80485a8 ; <- whoops! compiler still referencing via esp
804848e: mov DWORD PTR [esp],eax ; <- whoops! compiler still referencing via esp
8048491: call 8048358 <[email protected]>
8048496: mov eax,DWORD PTR [ebp-0x4]
8048499: mov DWORD PTR [esp],eax ; <- whoops! compiler still referencing via esp
804849c: call 8048368 <[email protected]>
80484a1: leave
80484a2: ret
आप देख सकते हैं, यह इतना आसान नहीं है:
यहाँ परिणामी एएसएम है। दुर्भाग्यवश, मैं अपने मूल दावे से खड़ा हूं कि आपको कंपाइलर सहायता की आवश्यकता है।
मुझे लगता है कि आप ठीक हैं; ईएसपी एक्सेस फ़ंक्शन कॉल से पहले तर्क लिख रहे हैं, और ईएसपी-रिश्तेदार सही है। आप '-फनो-संचय-आउटगोइंग-एर्ग' का प्रयास कर सकते हैं या जो कुछ भी और संबंधित तर्क हैं, वे स्टैक के नीचे संशोधित करने के लिए एमओवी का उपयोग करने के बजाय बस पुश का उपयोग करने के लिए जीसीसी प्राप्त करना चाहते हैं। –
लेकिन वास्तव में, संकलक के पीछे एलोका को कार्यान्वित करने की कोशिश कर रहा है यह एक * भयानक * विचार है, जैसा कि आप इस उत्कृष्ट उत्तर के शुरुआती हिस्से में इंगित करते हैं। गलत होने के लिए कई तरीके हैं, और ऐसा करने का कोई कारण नहीं है। अगर लोग एएसएम लिखना चाहते हैं और अपना खुद का ढेर आवंटन करना चाहते हैं, तो सी ++ में इनलाइन-एएसएम का दुरुपयोग करने के बजाय बस शुद्ध एएसएम में लिखें। –
@ पीटरकॉर्डस सच है कि अधिकांश ईएसपी संदर्भ कार्य तर्क हैं, लेकिन क्योंकि यह "आवंटित" ** से पहले ** आवंटित करने की कोशिश की गई है, तो ये चाल उपयोगकर्ता की "आवंटित स्थान" पर टंपल हो जाएंगी। अगर मैं उस जगह का उपयोग करना चाहता हूं तो कौन टूटा हुआ है। उचित धक्का देने वालों को बदलने से उनमें से अधिकांश ठीक हो जाएंगे। इसके अलावा अंतिम esp संदर्भ स्थानीय चर में परिणाम संग्रहीत कर रहा है, और एक बार फिर "सरणी" पर ट्रामल हो जाएगा। यह बहुत जल्दी बुरी तरह से चला जाता है। –