2011-09-23 23 views
39

का स्पष्टीकरण मुझे जीसीसी द्वारा उत्पन्न असेंबली में .cfi_def_cfa_offset निर्देशों के साथ उपयोग किए गए मानों के लिए स्पष्टीकरण चाहिए। मुझे पता है कि .cfi निर्देश कॉल फ्रेम में शामिल हैं और अवांछित ढेर हैं, लेकिन मुझे एक और विस्तृत स्पष्टीकरण चाहिए कि क्यों, उदाहरण के लिए, निम्नलिखित सी प्रोग्राम को संकलित करने में जीसीसी द्वारा प्रदत्त असेंबली में मान 16 और 8 का उपयोग किया जाता है मेरी 64-बिट उबंटू मशीन पर।जीएएस: .cfi_def_cfa_offset

सी कार्यक्रम: gcc -S -O3 test.c:

#include <stdio.h> 

int main(int argc, char** argv) 
{ 
     printf("%d", 0); 
     return 0; 
} 

मैं इस प्रकार स्रोत फ़ाइल test.c पर जीसीसी लागू। मुझे पता है कि -O3 गैर मानक अनुकूलन को सक्षम बनाता है, लेकिन मैं पैदाित्व के लिए उत्पन्न असेंबली के आकार को सीमित करना चाहता था।

उत्पन्न विधानसभा:

 .file "test.c" 
     .section  .rodata.str1.1,"aMS",@progbits,1 
.LC0: 
     .string "%d" 
     .text 
     .p2align 4,,15 
.globl main 
     .type main, @function 
main: 
.LFB22: 
     .cfi_startproc 
     subq $8, %rsp 
     .cfi_def_cfa_offset 16 
     xorl %edx, %edx 
     movl $.LC0, %esi 
     movl $1, %edi 
     xorl %eax, %eax 
     call __printf_chk 
     xorl %eax, %eax 
     addq $8, %rsp 
     .cfi_def_cfa_offset 8 
     ret 
      .cfi_endproc 
.LFE22: 
     .size main, .-main 
     .ident "GCC: (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2" 
     .section  .note.GNU-stack,"",@progbits 

मान 16 और 8 उत्पन्न विधानसभा में .cfi_def_cfa_offset निर्देशों के लिए इस्तेमाल क्यों कर रहे हैं? साथ ही, स्थानीय फ़ंक्शन के लिए उपयोग की जाने वाली संख्या 22 क्यों शुरू होती है और अंतिम लेबल काम करती है?

उत्तर

61

DWARF spec के रूप में खंड 6.4 में कहते हैं:

[...] कॉल फ्रेम ढेर पर कोई पता द्वारा की पहचान है। हम इस पते को कैननिकल फ्रेम पता या सीएफए के रूप में देखते हैं। आम तौर पर, सीएफए को पिछले फ्रेम में कॉल साइट पर स्टैक पॉइंटर का मान माना जाता है (जो वर्तमान फ्रेम में प्रवेश पर इसके मूल्य से भिन्न हो सकता है)।

main() (libc सी क्रम समर्थन कोड में) कहीं और से कहा जाता है, और, समय call अनुदेश निष्पादित किया जाता है पर, %rsp (ढेर के शीर्ष जो सबसे कम पता है की ओर इशारा करेगा - ढेर नीचे की ओर बढ़ता है), जो कुछ भी है कि हो सकता है (वास्तव में क्या यह है मामला यहाँ नहीं करता है):

:    :       ^
| whatever | <--- %rsp     | increasing addresses 
+----------------+        | 

इस बिंदु पर %rsp का मूल्य है "कॉल स्थल पर ढेर सूचक का मूल्य", यानी कल्पना द्वारा परिभाषित सीएफए।

रूप call अनुदेश निष्पादित किया जाता है, यह ढेर पर एक 64-बिट (8 बाइट) वापसी पता चली जाएगी:

:    : 
| whatever | <--- CFA 
+----------------+ 
| return address | <--- %rsp == CFA - 8 
+----------------+ 

अब हम main पर कोड है, जो subq $8, %rsp कार्यान्वित एक और आरक्षण चल रहे हैं खुद के लिए ढेर के 8 बाइट्स:

:    : 
| whatever | <--- CFA 
+----------------+ 
| return address | 
+----------------+ 
| reserved space | <--- %rsp == CFA - 16 
+----------------+ 

ढेर सूचक के परिवर्तन .cfi_def_cfa_offset निर्देशों का उपयोग डिबगिंग जानकारी में घोषित किया जाता है, और आप देख सकते हैं कि सीएफए एक में है वर्तमान स्टैक सूचक से 16 बाइट्स की ऑफसेट।

फ़ंक्शन के अंत में, addq $8, %rsp निर्देश स्टैक पॉइंटर को फिर से बदलता है, इसलिए .cfi_def_cfa_offset निर्देश यह इंगित करने के लिए डाला जाता है कि सीएफए अब स्टैक पॉइंटर से केवल 8 बाइट्स के ऑफसेट पर है।

(लेबल में संख्या "22" केवल एक मनमाना मूल्य है।संकलक जैसे बुनियादी ब्लॉक के अपने आंतरिक नंबर के रूप में अद्वितीय लेबल कुछ कार्यान्वयन विस्तार, के आधार पर नाम उत्पन्न होगा।)

+3

वास्तव में बहुत अच्छी व्याख्या। आम तौर पर लेबल क्रमशः क्रमांकित होते हैं (फ़ंक्शन स्कोप के संबंध में), यहां हम केवल उनको देख सकते हैं क्योंकि ऑप्टिमाइज़र ने अन्य लेबल हटा दिए हैं। – JohnTortugo

+0

एक बहुत स्पष्ट स्पष्टीकरण के लिए बहुत बहुत धन्यवाद! – namanhams

+2

.cfi_ * निर्देशों को समझने के लिए, आपको https://sourceware.org/binutils/docs/as/CFI-directives.html भी देखना चाहिए। यह पतला है, लेकिन यह आधिकारिक है। –

1

मैं विधानसभा में .cfi_def_cfa_offset निर्देशों जीसीसी द्वारा उत्पन्न के साथ प्रयोग किया मूल्यों के लिए एक स्पष्टीकरण चाहते हैं।

मैथ्यू ने एक अच्छी व्याख्या प्रदान की। यहाँ गैस के मैनुअल में Section 7.10 CFI Directives से परिभाषा है:

.cfi_def_cfa_offset कंप्यूटिंग सीएफए के लिए एक नियम संशोधित करता है। रजिस्टर वही रहता है, लेकिन ऑफ़सेट नया है। ध्यान दें कि यह पूर्ण ऑफसेट है जिसे सीएफए पते की गणना करने के लिए एक निर्धारित रजिस्टर में जोड़ा जाएगा।

और .cfi_adjust_cfa_offset: .cfi_def_cfa_offset रूप

ही लेकिन ऑफसेट एक रिश्तेदार मूल्य है कि जोड़ा जाता है/पिछले ऑफसेट से substracted है।

 संबंधित मुद्दे

  • कोई संबंधित समस्या नहीं^_^