EBP फ्रेम पॉइंटर रजिस्टर का उद्देश्य क्या है?


95

मैं असेंबली लैंग्वेज में एक शुरुआत कर रहा हूं और देखा है कि कंपाइलरों द्वारा उत्सर्जित x86 कोड आमतौर पर फ्रेम पॉइंटर को रिलीज / अनुकूलित मोड में भी इधर-उधर रखता है जब वह EBPरजिस्टर को किसी और चीज के लिए इस्तेमाल कर सकता है।

मैं समझता हूं कि फ्रेम पॉइंटर क्यों डिबग करने के लिए कोड को आसान बना सकता है, और यदि alloca()किसी फ़ंक्शन के भीतर कहा जाता है, तो यह आवश्यक हो सकता है । हालांकि, x86 में बहुत कम रजिस्टर हैं और उनमें से दो का उपयोग स्टैक फ्रेम के स्थान को धारण करने के लिए किया जाता है, जब कोई पर्याप्त होगा बस मुझे इससे कोई मतलब नहीं है। अनुकूलित / रिलीज़ बिल्ड में भी फ्रेम पॉइंटर को खराब विचार क्यों माना जाता है?


19
अगर आपको लगता है कि x86 के पास बहुत कम रजिस्टर हैं, तो आपको 6502 :) की जाँच करनी चाहिए :)
सेदात कोपनोग्लू


1
C99 VLA भी इससे लाभान्वित हो सकता है।
सिरो सेंटिल्ली 郝海东 i iro i 法轮功 '


1
क्या फ्रेम पॉइंटर स्टैक पॉइंटर को निरर्थक नहीं बनाता है? । टीएल; डीआर: 1. गैर-तुच्छ स्टैक संरेखण 2. स्टैक आवंटन ( alloca) 3. रनटाइम कार्यान्वयन में आसानी: हैंडलिंग, सैंडबॉक्स, जीसी
अलेक्जेंडर

जवाबों:


102

फ़्रेम पॉइंटर एक संदर्भ सूचक है जो डिबगर को यह जानने की अनुमति देता है कि स्थानीय चर या तर्क एक एकल निरंतर ऑफसेट के साथ कहां है। हालांकि निष्पादन के दौरान ईएसपी का मूल्य बदल जाता है, ईबीपी समान ऑफसेट पर समान चर तक पहुंचना संभव बनाता है (जैसे कि पहला पैरामीटर हमेशा ईबीपी + 8 पर होगा, जबकि ईएसपी ऑफसेट महत्वपूर्ण रूप से बदल सकते हैं क्योंकि आप धक्का दे रहे हैं। / पॉपिंग चीजें)

कंपाइलर फ्रेम पॉइंटर को क्यों नहीं फेंकते हैं? क्योंकि फ़्रेम पॉइंटर के साथ, डिबगर यह पता लगा सकता है कि स्थानीय चर और तर्क प्रतीक तालिका का उपयोग कर रहे हैं क्योंकि वे EBP के लिए एक निरंतर ऑफसेट होने की गारंटी है। अन्यथा यह पता लगाने का कोई आसान तरीका नहीं है कि स्थानीय चर कोड में किसी भी बिंदु पर है।

जैसा कि ग्रेग ने उल्लेख किया है, यह डीबगर के लिए स्टैक अनइंडिंग में भी मदद करता है क्योंकि ईबीपी स्टैक फ्रेम की एक रिवर्स लिंक्ड सूची प्रदान करता है इसलिए डिबगर को फ़ंक्शन के स्टैक फ्रेम (स्थानीय चर + तर्क) के आकार का पता लगाने देता है।

अधिकांश कंपाइलर फ़्रेम पॉइंटर्स को छोड़ देने का विकल्प प्रदान करते हैं, हालांकि यह डीबगिंग को वास्तव में कठिन बनाता है। रिलीज़ कोड में भी उस विकल्प का विश्व स्तर पर उपयोग नहीं किया जाना चाहिए। आपको नहीं पता कि आपको किसी उपयोगकर्ता की क्रैश को कब डिबग करना होगा।


10
संकलक शायद जानता है कि यह ईएसपी को क्या करता है। अन्य बिंदु वैध हैं, हालांकि, +1
erikkallen

8
आधुनिक डिबगर्स, संकलित कोड में भी स्टैक बैकट्रैक कर सकते हैं -fomit-frame-pointer। हाल ही की gcc में वह सेटिंग डिफ़ॉल्ट है।
पीटर कॉर्ड्स

2
@SedatKapanoglu: एक डेटा अनुभाग आवश्यक जानकारी रिकॉर्ड करता है: yosefk.com/blog/…
पीटर कॉर्ड्स

3
@SedatKapanoglu: इस .eh_frame_hdrअनुभाग का उपयोग रनटाइम अपवादों के लिए भी किया जाता है। आपको objdump -hलिनक्स सिस्टम पर अधिकांश बायनेरिज़ में यह (साथ ) मिलेगा , यह लगभग 16k है /bin/bash, बनाम GN2 के लिए /bin/true572B, के लिए 108k ffmpeg। इसे जनरेट करने में अक्षम करने के लिए एक जीसीसी विकल्प है, लेकिन यह एक "सामान्य" डेटा अनुभाग है, न कि डिबग सेक्शन जो stripडिफ़ॉल्ट रूप से हटाता है। अन्यथा आप एक लाइब्रेरी फ़ंक्शन के माध्यम से बैकट्रेस नहीं कर सकते हैं जिसमें डीबग प्रतीक नहीं थे। यह खंड उसके push/mov/popनिर्देशों की तुलना में बड़ा हो सकता है, लेकिन इसके पास शून्य रनटाइम लागत (जैसे यूओपी कैश) है।
पीटर कॉर्ड्स

3
"जैसे कि पहला पैरामीटर हमेशा EBP-4 में रहेगा" के बारे में: EBP + 8 (x86 पर) पर पहला पैरामीटर नहीं है?

31

बस पहले से ही अच्छे उत्तरों के लिए मेरे दो सेंट जोड़ रहा हूं।

स्टैक फ्रेम की एक श्रृंखला के लिए यह एक अच्छी भाषा वास्तुकला का हिस्सा है। बीपी वर्तमान फ्रेम को इंगित करता है, जहां सबरूटीन-स्थानीय चर संग्रहीत किए जाते हैं। (स्थानीय लोग नकारात्मक स्थिति में हैं, और तर्क सकारात्मक स्थिति में हैं।)

यह विचार कि यह पूरी तरह से अच्छे रजिस्टर को ऑप्टिमाइज़ेशन में इस्तेमाल होने से रोक रहा है, यह सवाल उठाता है: कब और कहाँ ऑप्टिमाइज़ेशन वास्तव में सार्थक है?

अनुकूलन केवल तंग छोरों में केवल सार्थक है कि 1) फ़ंक्शन को कॉल न करें, 2) जहां प्रोग्राम काउंटर अपने समय का एक महत्वपूर्ण अंश खर्च करता है, और 3) कोड में कंपाइलर वास्तव में कभी भी (यानी गैर-लाइब्रेरी फ़ंक्शन) देखेंगे। यह आमतौर पर समग्र कोड का एक बहुत छोटा अंश होता है, विशेषकर बड़ी प्रणालियों में।

चक्र से छुटकारा पाने के लिए अन्य कोड को घुमाया और निचोड़ा जा सकता है, और यह केवल मायने नहीं रखेगा, क्योंकि प्रोग्राम काउंटर व्यावहारिक रूप से कभी नहीं होता है।

मुझे पता है कि आपने यह नहीं पूछा, लेकिन मेरे अनुभव में, 99% प्रदर्शन समस्याओं का कंपाइलर ऑप्टिमाइज़ेशन के साथ कुछ भी नहीं है। ओवर-डिज़ाइन के साथ उनके पास सब कुछ है।


धन्यवाद @ माइक, मुझे आपका उत्तर बहुत मददगार लगा।
साठफुटेरसूड 15

2
फ़्रेम पॉइंटर के साथ दूर करने से आपको प्रत्येक फ़ंक्शन कॉल के लिए कुछ निर्देशों की बचत होती है, जो अपने आप में एक छोटा अनुकूलन है। BTW, "बेग द क्वेश्चन" का आपका उपयोग गलत है; आपका मतलब है "सवाल उठाता है"।
अगुरार

@ सुदूर: अचल। धन्यवाद। मैं अपने आप को एक व्याकरण से थोड़ा
परेशान

3
@ उद्घोषक भाषा विकसित होती है: "भीख माँगती है" का अर्थ अब "प्रश्न उठाता है" है। पुराने उपयोग के लिए एक प्रिस्क्रिप्वीविस्ट नाइटपिकर होने के नाते कुछ भी नहीं जोड़ता है।
user3364825

9

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

कंपाइलर अपवाद हैंडलिंग के दौरान स्टैक अनइंडिंग के साथ ईबीपी रजिस्टर को बनाए रखने के लिए भी चुन सकते हैं, लेकिन फिर से यह सटीक कंपाइलर कार्यान्वयन पर निर्भर करता है।


-fomit-frame-pointerअनुकूलन सक्षम होने पर अधिकांश कंपाइलर डिफ़ॉल्ट होते हैं । (जब एबीआई इसकी अनुमति देता है)। 32-बिट विंडोज को टारगेट करते हुए भी GCC, clang, ICC और MSVC सभी इसे IIRC करते हैं। हाँ, इस पर मेरा जवाब है कि स्टैक पर मापदंडों का पता लगाने के लिए एस्प रजिस्टर की तुलना में ईबीपी का उपयोग करना बेहतर क्यों है? दिखाता है कि 32-बिट विंडोज भी फ्रेम पॉइंटर को छोड़ सकता है। 32-बिट x86 लिनक्स निश्चित रूप से कर सकता है और करता है। और निश्चित रूप से 64-बिट एबीआई ने प्रारंभ से फ्रेम-पॉइंटर चूक की अनुमति दी है।
पीटर कॉर्ड्स

4

हालांकि, x86 में बहुत कम रजिस्टर हैं

यह केवल इस अर्थ में सही है कि opcodes केवल 8 रजिस्टरों को संबोधित कर सकता है। प्रोसेसर के पास वास्तव में इससे कई अधिक रजिस्टर होंगे और उस सीमा के आसपास पाने के लिए रजिस्टर का नाम बदलने, पाइपलाइनिंग, सट्टा निष्पादन, और अन्य प्रोसेसर buzzwords का उपयोग करें। विकिपीडिया का एक अच्छा परिचयात्मक पैराग्राफ है जैसे कि x86 प्रोसेसर रजिस्टर सीमा को पार करने के लिए क्या कर सकता है: http://en.wikipedia.org/wiki/X86#Current_implementations


1
मूल प्रश्न उत्पन्न कोड के बारे में है, जो कड़ाई से opcodes द्वारा संदर्भित रजिस्टरों तक सीमित है।
डैरन

1
हां, लेकिन यही कारण है कि अनुकूलित बिल्ड में फ्रेम पॉइंटर को बनाना आजकल उतना महत्वपूर्ण नहीं है।
माइकल

1
रजिस्टर नामकरण वास्तव में उपलब्ध रजिस्टर की एक बड़ी संख्या होने के रूप में काफी एक ही बात नहीं है। अभी भी बहुत सारी स्थितियाँ हैं जहाँ नाम बदलने में मदद नहीं मिलेगी, लेकिन अधिक "नियमित" रजिस्टर होंगे।
जालपा

1

स्टैक फ्रेम का उपयोग करना किसी भी हार्डवेयर में अविश्वसनीय रूप से सस्ता हो गया है, यहां तक ​​कि आधुनिक रूप से भी। यदि आपके पास सस्ते स्टैक फ्रेम हैं तो रजिस्टर के एक जोड़े को सहेजना उतना महत्वपूर्ण नहीं है। मुझे यकीन है कि तेज स्टैक फ्रेम बनाम अधिक रजिस्टर एक इंजीनियरिंग ट्रेड-ऑफ था, और फास्ट स्टैक फ्रेम जीता।

आप कितना शुद्ध रजिस्टर बचा रहे हैं? यह इसके लायक है?


अधिक रजिस्टर निर्देश एन्कोडिंग द्वारा सीमित है। x86-64 REX उपसर्ग बाइट में बिट्स का उपयोग करता है जो src और डेस्ट रजिस्टरों के लिए 3 से 4 बिट्स के निर्देशों के रजिस्टर-निर्दिष्ट हिस्से का विस्तार करता है। यदि कमरा था, तो x86-64 शायद 32 वास्तुशिल्प रजिस्टरों में चला गया होगा, हालांकि संदर्भ स्विचेस में से कई को सहेजना / बहाल करना शुरू होता है। 15 7 से एक बड़ा कदम है, लेकिन 31 ज्यादातर मामलों में बहुत छोटा सुधार है। (सामान्य उद्देश्य के रूप में स्टैक पॉइंटर की गिनती नहीं करना।) स्टैक / पॉप फास्ट बनाना केवल स्टैक फ्रेम से अधिक के लिए महान है। यह # regs के साथ एक व्यापार नहीं है, हालांकि।
पीटर कॉर्ड्स
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.