c++ इनलाइन स्थिर डेटा के कारण एक अनुभाग प्रकार संघर्ष होता है




gcc linker (4)

मैं एक कस्टम अनुभाग में कुछ उपयोगकर्ता परिभाषित डेटा को एक ही समय में एप्लिकेशन और एक ऑफ़लाइन विश्लेषक द्वारा पढ़ना चाहता हूं। निम्नलिखित नमूने मान लें:

const int* get_data()
{
  __attribute__((section(".custom")))
  static const int data = 123;

  return & data;
}

inline const int* inline_get_data()
{
  __attribute__((section(".custom")))
  static const int inline_data = 123;

  return & inline_data;
}

int main()
{
  (void) get_data();
  (void) inline_get_data();
  return 0;
}

data का मूल्य और inline_data अनुभाग में दिखाई देगा। .custom क्लैग इस उदाहरण को संकलित करता है और सही परिणाम उत्पन्न करता है, जैसे कि एमएसवीसी करता है, जब __ डेटा का योगदान दिया जाता है, तो इसी प्रगामा द्वारा बदल दिया जाता है।

दुर्भाग्य से, जीसीसी 5.2 निम्नलिखित त्रुटि देता है:

error: inline_data causes a section type conflict with data

समस्या यह है कि दो चर में अलग-अलग लिंकेज हैं ( data एक से चिह्नित किए गए अनुभाग में है, inline_data के अनुभाग को aG साथ चिह्नित किया गया है)। जीसीसी 4.9 उसी तरह विफल हो जाता है यदि दूसरे फ़ंक्शन को इनलाइन के रूप में चिह्नित नहीं किया गया है, लेकिन एक टेम्पलेट (जीसीसी 5.2 संकलित है)।

जीसीसी 5.2 भी ठीक से संकलित करता है यदि एक खंड नाम अस्थायी रूप से बदल दिया गया है और मैन्युअल रूप से जनित विधानसभा में तय किया गया है।

क्या इस मुद्दे के लिए कोई ज्ञात समाधान है? फ़ंक्शन के हस्ताक्षर पर मेरे पास कोई नियंत्रण नहीं है, *data चर मेरे द्वारा दिए गए मैक्रो द्वारा उत्पादित किए जाते हैं, और वे कहीं भी दिखाई दे सकते हैं।


कस्टम अनुभागों के साथ गड़बड़ एक गंदे विषय का एक छोटा कारण है क्योंकि जीआईसी इनैट मूल्य के आधार पर डेटा या बीएसएस पर निर्णय लेता है और उस स्तर पर आपको इसके साथ गड़बड़ी की उम्मीद नहीं करता है।

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

एक छोटे उपयोगकर्ता उदारीकरण, आसानी से पार्सिंग के लिए डेटा अनुभाग में सभी उपयोगकर्ता डेटा -fno-zero-initialized-in-bss लिए -fno-zero-initialized-in-bss साथ बनाया जा सकता है। लेकिन अपने बायनेरिज़ पर ऐसा न करें।


जीसीसी दस्तावेज़ीकरण (उदाहरण के लिए 5.3 ) कहते हैं:

वैश्विक चर के साथ अनुभाग विशेषता का उपयोग करें और स्थानीय चर नहीं [...]

इस प्रकार, आपको कार्य से उन चर को निकालने की आवश्यकता है:

__attribute__((section(".custom"))) static const int data = 123;
__attribute__((section(".custom"))) static const int inline_data = 123;

const int* get_data()
{
  return &data;
}

inline const int* inline_get_data()
{
  return &inline_data;
}

int main()
{
  (void)get_data();
  (void)inline_get_data();
} 

यह सिर्फ जीसीसी -5 5.2 और क्लैग-3.5.1 के साथ ठीक है


अंत में मुझे एक संतोषजनक समाधान मिला। यह वास्तव में पहले से ही ज्ञात तकनीकों का संयोजन है रनटाइम एक सामान्य स्थिर वैरिएबल का उपयोग करता है, जिसका पता इनलाइन असेंबल द्वारा कस्टम अनुभाग में रखा जाता है। एएसएम के बिना, अलग-अलग प्लेटफार्मों (क्लैग, एमएसवीसी), __attribute__ या #pragma __attribute__ पर उसी परिणाम के साथ इस्तेमाल किया जा सकता है। यह समाधान आसानी से एक सामान्य, मंच अज्ञेयवादी मैक्रो में लपेटा जा सकता है।

const int* get_data()
{
  static const int data = 123;
  __asm__(
    ".pushsection .custom, \"?\", @progbits" "\n"
    ".quad %c0" "\n"
    ".popsection" "\n"
    : : "i"(&data)
  );

  return & data;
}

inline const int* inline_get_data()
{
  static const int inline_data = 123;
  __asm__(
    ".pushsection .custom, \"?\", @progbits" "\n"
    ".quad %c0" "\n"
    ".popsection" "\n"
    : : "i"(&inline_data)
  );

  return & inline_data;
}

int main()
{
  (void) get_data();
  (void) inline_get_data();
  return 0;
}

सामान्य अच्छे के लिए, मैं जो पहले से ही जानता हूं उसे दोहराता हूं और क्या @रंबारुक पहले से ही उद्धृत किया गया है: जीसीसी के दस्तावेज़ स्पष्ट रूप से section विशेषता के वैश्विक चर में आवेदन को प्रतिबंधित करते हैं। इसलिए जीसीसी के व्यवहार के लिए वांछित समाधान जीसीसी को विशिष्ट रूप से जीसीसी-विशिष्ट भाषा विस्तार के असमर्थित आवेदन पर बार्क के लिए या टूटा हुआ कोड का उपयोग नहीं करने का एक तरीका है। हमें सफलता की उम्मीद करने या सफलता को लगातार दोहराने योग्य होने की उम्मीद करने का कोई अधिकार नहीं है।

यहां बताया गया है कि जीसीसी किस तरह से और क्यों खंड-प्रकार संघर्ष संकलन त्रुटि का उत्पादन करता है और झगड़ा नहीं करता है। यदि अधीर हो जाए तो फिक्स करने के लिए स्क्रॉल करें, लेकिन रजत बुलेट की अपेक्षा न करें।

प्रदर्शन के प्रयोजनों के लिए मैं आपके द्वारा पोस्ट की गई तुलना में थोड़ा अधिक लाइफिल कार्यक्रम के साथ काम करूंगा, अर्थात्:

source.cpp

const int* get_data()
{
    __attribute__((section(".custom")))
    static const int data = 123;

    return & data;
}

inline const int* inline_get_data()
{
    __attribute__((section(".custom")))
    static const int inline_data = 123;

    return & inline_data;
}

const int* other_get_data()
{
    return inline_get_data();
}

header.h

#ifndef HEADER_H
#define HEADER_H
extern const int* get_data();
extern const int* other_get_data();
#endif

main.cpp

#include "header.h"
#include <iostream>

int main()
{
    std::cout << (*get_data() + *other_get_data()) << std::endl;
    return 0;
}

जैसा कि यह खड़ा है, यह प्रोग्राम अनुभाग-प्रकार संघर्ष त्रुटि को पुन: उत्पन्न करता है जब gcc 5.2 के साथ संकलित किया जाता है:

$ g++-5 -Wall -pedantic -c source.cpp
source.cpp:12:22: error: inline_data causes a section type conflict with data
     static const int inline_data = 123;
                      ^

क्लैग (3.6 / 3.7) की कोई शिकायत नहीं है:

$ clang++ -Wall -pedantic -I. -o prog main.cpp source.cpp 
$ ./prog
246

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

कंपाइलर क्रमशः get_data() और inline_get_data() get_data() लिए लिंक उत्पन्न करने के लिए विभिन्न नियमों को गोद लेता है। get_data() सरल मामला है, inline_get_data() मुश्किल मामला है।

अंतर को देखने के लिए, चलो अस्थायी रूप से "custom" को get_data() "custom" साथ "custom.b" "custom" जगह और get_data() में "custom.a" साथ "custom.a" "custom" को प्रतिस्थापित करके अस्थायी रूप से जीसीसी अनुभाग संघर्ष को inline_get_data()

अब हम जीसीसी के साथ source.cpp संकलित कर सकते हैं और संबंधित प्रतीक तालिका प्रविष्टियों का निरीक्षण कर सकते हैं:

$ objdump -C -t source.o | grep get_data
0000000000000000 l     O .custom.a  0000000000000004 get_data()::data
0000000000000000 l    d  .text._Z15inline_get_datav 0000000000000000 .text._Z15inline_get_datav
0000000000000000 g     F .text  000000000000000b get_data()
0000000000000000 u     O .custom.b  0000000000000004 inline_get_data()::inline_data
0000000000000000  w    F .text._Z15inline_get_datav 000000000000000b inline_get_data()
000000000000000b g     F .text  000000000000000b other_get_data()

get_data() , ज़ाहिर है, एक वैश्विक प्रतीक ( g ) और get_data()::data बनाया गया है स्थानीय प्रतीक ( l )। लेकिन inline_get_data() को एक कमजोर , न तो वैश्विक और न ही स्थानीय प्रतीक ( w ) और inline_get_data()::inline_data बना दिया गया है, हालांकि यह वाक्यविन्यास रूप से ब्लॉक-क्षेत्र स्थिर है, एक अद्वितीय वैश्विक प्रतीक ( u ) बनाया गया है। यह मानक ईएलएफ प्रतीक बाइंडिंग का एक जीएनयू एक्सटेंशन है जिसे रनटाइम लिंकर की आवश्यकता होती है ताकि यह सुनिश्चित हो सके कि पूरे रनटाइल लिंकेज में प्रतीक अद्वितीय है।

inline_get_data() लिए इन विभिन्न लिंकेज की शर्तों में, जीसीसी मुकाबला कर रहा है क्योंकि यह तथ्य के साथ फिट है कि यह फ़ंक्शन बाहरी लिंकेज के साथ इनलाइन है । तथ्य यह है कि समारोह में इनलाइन का मतलब है कि प्रत्येक अनुवाद इकाई में इसका प्रयोग किया जाना चाहिए, जिसमें यह प्रयोग किया जाता है, और यह तथ्य है कि इसमें बाहरी संबंध है इसका मतलब है कि उन सभी परिभाषाओं को उसी inline_data()::get_data संबोधित करना चाहिए। इस प्रकार ब्लॉक-स्कोप स्थैतिक चर, लिंकेज के प्रयोजनों के लिए, सार्वजनिक प्रतीक बनना चाहिए।

एक ही प्रेरणा से, जीसीसी, custom.a खंड custom.a साथ अलग-अलग सौदों को प्राप्त करता है। इन में से get_data() और get_data() में attributed section custom.b गया है। inline_get_data()::inline_data एक अद्वितीय वैश्विक प्रतीक inline_get_data()::inline_data , यह सुनिश्चित करना चाहता है कि इस प्रतीक की कई परिभाषाएं अलग-अलग अनुवाद इकाइयों से अलग-अलग प्रतियां अनुभाग custom.b के लिंक से नहीं पेश की गईं। इसके लिए, यह custom.b GROUP लिंकर विशेषता को लागू करता है: यह (विवरण custom.b करने) इसे एक। सेक्शन डायरेक्टिव उत्पन्न करने के लिए सक्षम बनाता है जो नामांकित अनुभाग-समूह में custom.b प्रदान करता है और लिंकर को उस की एक प्रति को बनाए रखने का निर्देश देता है अनुभाग समूह का निरीक्षण करें:

$ readelf -t source.o
...
...
[ 7] .custom.a
   PROGBITS               PROGBITS         0000000000000000  0000000000000068  0
   0000000000000004 0000000000000000  0                 4
   [0000000000000002]: ALLOC
[ 8] .custom.b
   PROGBITS               PROGBITS         0000000000000000  000000000000006c  0
   0000000000000004 0000000000000000  0                 4
   [0000000000000202]: ALLOC, GROUP
                              ^^^^^
 ...
 ...

और यह अनुभाग-प्रकार विवाद त्रुटि का ट्रिगर है, जब custom.a और custom.b एक और समान हैं जीसीसी एक ऐसा खंड नहीं बना सकता है जो दोनों में है और इसमें GROUP विशेषता नहीं है।

अब अगर get_data() और inline_get_data को अलग-अलग अनुवाद इकाइयों में परिभाषित किया गया था तो कंपाइलर संघर्ष को ध्यान नहीं दे सकता था। तो क्या बात है? उस मामले में क्या गलत होगा?

उस मामले में कुछ भी गलत नहीं हो पाया है, क्योंकि उस मामले में कोई खंड-प्रकार का संघर्ष नहीं है। source.o अनुभाग में जीसीसी द्वारा उत्पन्न एक खंड custom source.oमें एक खंड है यह या तो होना चाहिए या उसके पास GROUP विशेषता नहीं है, लेकिन अन्य तरीकों से समान नाम के एक अनुभाग custom के साथ कोई विवाद नहीं है। इसके विपरीत स्थिति होने पर। ये लिंकर के लिए अलग इनपुट अनुभाग हैं यह GROUP एड के इनपुट custom अनुभागों को डिस्प्लेज करेगा, उनमें से केवल एक प्रति समूह-नाम बनाए रखना होगा। यह इनपुट custom अनुभागों के साथ ऐसा नहीं करेगा जो GROUPed नहीं हैं, और अंत में यह सभी इनपुट custom अनुभागों को मर्ज कर देगा जो बाइनरी में एक आउटपुट custom अनुभाग में छोड़ दिया जाता है, अब गैर-लागू GROUP विशेषता (एस) को धोखा दिया गया है । उस आउटपुट custom अनुभाग में एक get_data()::data एक स्थानीय प्रतीक और inline_get_data()::inline_data को एक अद्वितीय वैश्विक प्रतीक के रूप में शामिल होगा। संघर्ष केवल कंपाइलर में विरोधाभासी नियमों का सामना कर रहा है, चाहे अनुभाग source.o(custom) GROUP एड हो या नहीं।

तो फिर क्यों नहीं झगड़ा एक ही विरोधाभास के बेईमानी? ऐसा इसलिए है क्योंकि झूठ को एक सरल लेकिन कुछ हद तक कम मजबूत दृढ़ता से एक इनलाइन फ़ंक्शन की समस्या के साथ बाहरी डेटा से युक्त लिंक शामिल होता है

वर्गों के भेदभाव के साथ चिपके हुए। custom.a और custom.b , चलो अब custom.b साथ source.cpp संकलित करें और प्रासंगिक प्रतीकों और अनुभाग विशेषताओं का निरीक्षण करें:

$ objdump -C -t source.o | grep get_data
0000000000000000 l     O .custom.a  0000000000000004 get_data()::data
0000000000000000 l    d  .text._Z15inline_get_datav 0000000000000000 .text._Z15inline_get_datav
0000000000000010 g     F .text  000000000000000b other_get_data()
0000000000000000  w    F .text._Z15inline_get_datav 0000000000000010 inline_get_data()
0000000000000000 g     F .text  0000000000000010 get_data()
0000000000000000  w    O .custom.b  0000000000000004 inline_get_data()::inline_data

जीसीसी के उत्पादन में एक अंतर है। जैसा कि हम उम्मीद कर सकते हैं, inline_get_data()::inline_data विशिष्ट प्रतीक को inline_get_data()::inline_data वैश्विक प्रतीक ( u ) के लिए inline_get_data()::inline_data । यह एक कमजोर प्रतीक बनाता है, जैसे कि inline_get_data() खुद।

और हमारे लिए अनुभाग के लक्षण हैं:

$ readelf -t source.o
...
...
[ 8] .custom.a
   PROGBITS               PROGBITS         0000000000000000  0000000000000080  0
   0000000000000004 0000000000000000  0                 4
   [0000000000000002]: ALLOC
[ 9] .custom.b
   PROGBITS               PROGBITS         0000000000000000  0000000000000084  0
   0000000000000004 0000000000000000  0                 4
   [0000000000000002]: ALLOC
...
...

कोई अंतर नहीं है, इसलिए कोई संघर्ष नहीं है यही कारण है कि हम custom नाम से custom नाम के custom नाम। custom और custom.b को प्रति मूल, और सफलतापूर्वक संकलित कर सकते हैं।

inline_get_data()::inline_data की कमजोर बाइंडिंग पर निर्भर करता है कि आवश्यकता के उत्तर देने के लिए कि केवल एक ऐसे प्रतीक को inline_get_data() प्रत्येक कार्यान्वयन से संबोधित किया जाता है जो कि संबंध में हो जाता है यह एक अनुभाग-प्रकार के संघर्ष से बचाता है, लेकिन जीसीसी के अधिक जटिल दृष्टिकोण के संबंध बख़्तरबंद चढ़ाना छोड़ देता है

क्या आप जीसीसी को बता सकते हैं कि मजबूती को छोड़ने और inline_get_data() संकलन के साथ एक inline_get_data() तरह का रास्ता ले लें? आप थोड़ा सा कर सकते हैं, लेकिन पर्याप्त नहीं है जीएनयू-स्पेसिफिक अद्वितीय वैश्विक प्रतीक बाध्यकारी को भूलने के लिए आप संकलक को निर्देश देने के लिए जीसीसी को विकल्प -fno-gnu-unique प्रदान कर सकते हैं। यदि आप ऐसा करते हैं, तो यह inline_get_data()::inline_data एक कमजोर प्रतीक बना देगा, जैसे inline_get_data()::inline_data ; लेकिन वह इसे कुहनी से मारना नहीं करेगा - प्रतीक के गुणित खंड के लिए अनुभाग-ग्रुपिंग लिंकेज को छोड़ना चाहिए - और आप अभी भी अनुभाग-प्रकार के संघर्ष प्राप्त करेंगे। मुझे आपके निस्संदेह बदबूदार समस्या कोड के लिए इस नट-किरकिरी कोड-पीढ़ी के व्यवहार को रोकना कोई विकल्प नहीं मिल सकता है।

ठीक करता है

हमने देखा है कि कैसे और क्यों जीसीसी खंड-प्रकार का संघर्ष विशेष रूप से दो कार्यों की परिभाषाओं की एक ही अनुवाद इकाई में उपस्थिति से उकसाया जाता है, बाहरी लिंकेज के साथ एक इनलाइन , अन्य इनलाइन नहीं है, जिनमें से प्रत्येक एक ही लिंकेज अनुभाग को विशेषता देता है इसकी स्थिर डेटा

मैं दो उपाय सुझा सकता हूं, उनमें से एक सरल और सुरक्षित है, लेकिन समस्या के एक भिन्नता के लिए केवल लागू होता है, अन्य हमेशा लागू होता है, लेकिन कठोर और हताश

सरल सुरक्षित एक

दो तरीके हैं जिसमें परस्पर विरोधी फ़ंक्शन परिभाषाएं एक ही अनुवाद इकाई में मिल सकती हैं: -

  1. उन दोनों को एक ही स्रोत ( .cpp ) फ़ाइल में परिभाषित किया गया है।
  2. गैर-इनलाइन फ़ंक्शन को एक स्रोत फ़ाइल में परिभाषित किया गया है जिसमें एक शीर्षलेख शामिल होता है जिसमें इनलाइन फ़ंक्शन परिभाषित किया जाता है।

यदि आपके पास प्रकार 1 के मामले हैं, तो यह केवल उस व्यक्ति के हिस्से पर एक गंदगी है, जो स्रोत फ़ाइल को इनलाइन फ़ंक्शन को बाहरी लिंकेज के साथ कोड करने के लिए कहते हैं। इस मामले में इनलाइन फ़ंक्शन उसके अनुवाद इकाई के लिए स्थानीय है और static होना चाहिए। यदि इसे static बना दिया गया है तो जीसीसी के बाहरी संबंध जुड़ाव गायब हो जाते हैं और उनके साथ खंड-प्रकार के विरोधाभास आपने कहा है कि आपके उस कोड पर कोई नियंत्रण नहीं है जिसमें आपका श्रेय अनुभाग सामग्री मैक्रो-इंजेक्शन है, लेकिन इसके लेखकों को इस तथ्य की स्वीकार्यता होनी चाहिए कि शीर्षलेख के बजाय स्रोत फ़ाइल में इनलाइन बाह्य फ़ंक्शन लिखना एक गलती है और इसके लिए तैयार होना चाहिए इसे सही करें।

कठोर मायूस एक

प्रकार 2 के मामले अधिक संभावना है। इन के लिए, जहाँ तक मैं देख सकता हूं, आपकी एक उम्मीद है कि जीसीसी निर्माण में एक असेंबली हैगिंग को शामिल करना है ताकि जीसीसी के। इनलाइन बाहरी फ़ंक्शन परिभाषाओं में दिए जाने वाले खंड के बारे में संबंधित निर्देश प्रोग्राम के अनुसार वस्तु से पहले क्लैग-जैसी होते हैं कोड उत्पन्न होता है

जाहिर है, ऐसा समाधान केवल जीसीसी संस्करणों के कुछ सेटों के लिए व्यवहार्य होगा जो आप जानते हैं कि "गलत तरीके से सही पैटर्न। .section निर्देश" जो आपके सुधारात्मक हैक को लक्षित करने के लिए है, और एक बिल्ड सिस्टम का उपयोग करने के लिए इसे विवेक-जांच करना चाहिए ऑपरेटिव जीसीसी संस्करण अग्रिम में

एक आवश्यक प्रारंभिक आपके मैक्रो को संशोधित करना है जो custom अनुभाग विशेषताओं को उत्पन्न करता है ताकि एक ही तरह से नाम का .custom किया जा .custom इसके बजाय .custom.1 को अनुक्रम .custom.1 , custom.2 , ..., custom.N पर लगातार custom.N उत्पन्न करता है। एक अनुवाद इकाई ऐसा करने के लिए प्रीप्रोसेसर निर्मित __COUNTER__ का प्रयोग करें, उदा

#define CAT2(x,y) x##y
#define CONCAT(x,y) CAT2(x,y)
#define QUOT(x) #x
#define QUOTE(x) QUOT(x) 
#define SET_SECT() __attribute__((section(QUOTE(CONCAT(.custom.,__COUNTER__)))))

इसका मतलब यह है कि जीसीसी प्रीप्रोसेस कोड को ऐसा करना है:

const int* get_data()
{
    SET_SECT()
    static const int data = 123;

    return & data;
}

inline const int* inline_get_data()
{
    SET_SECT()
    static const int inline_data = 123;

    return & inline_data;
}

जैसे कोड में:

const int* get_data()
{

    __attribute__((section(".custom.0")))
    static const int data = 123;

    return & data;
}

inline const int* inline_get_data()
{

    __attribute__((section(".custom.1")))
    static const int inline_data = 123;

    return & inline_data;
}

यह खंड-प्रकार के संघर्षों को भड़काने नहीं देगा।

इसके साथ में और source.cpp लागू हो, आप फ़ाइल को जीसीसी के साथ इकट्ठा कर सकते हैं:

g++ -S source.cpp

और आउटपुट source.s में निरीक्षण करें कि custom.0 अनुभाग custom.0 प्राप्त करें। सेक्शन डायरेक्टिव:

.section    .custom.0,"a",@progbits

जबकि समस्याग्रस्त खंड custom.1 मिलता है:

.section    .custom.1,"aG",@progbits,_ZZ15inline_get_datavE11inline_data,comdat

जहां _ZZ15inline_get_datavE11inline_data अनुभाग-समूह का नाम है और comdat लिंकर को इस अनुभाग-समूह को डुप्लिकेट करने के लिए कहता है।

इस झुमके से दोहराएं और देखें कि इसी निर्देश हैं:

.section    .custom.0,"a",@progbits
.section    .custom.1,"a",@progbits

अनुभाग नाम के अलावा कोई अंतर नहीं के साथ

तो असेंबली आपको हैक करने की आवश्यकता है जो एक की तरह बदल जाएगा:

.section    .custom.0,"a",@progbits
.section    .custom.1,"aG",@progbits,_ZZ15inline_get_datavE11inline_data,comdat

में:

.section    .custom,"a",@progbits

इसे एक sed प्रतिस्थापन द्वारा व्यक्त किया जा सकता है:

s|^\t\.section\t\.custom\.[0-9]\{1,\},"a\(G\)*",@progbits.*$|\t\.section\t\.custom,"a",@progbits|g

डेमो कार्यक्रम के लिए, मैक्रो तंत्र में आवश्यक बदलाव मानते हुए कठोर समाधान एक मेकअप में तैयार किया जा सकता है ताकि:

CXX ?= g++
SRCS = main.cpp source.cpp
ASMS = $(SRCS:.cpp=.s)
OBJS = $(SRCS:.cpp=.o)
CPPFLAGS = -I.
CXXFLAGS = -fno-gnu-unique

%.o: %.cpp

%.s: %.cpp
%.s: %.cpp
    $(CXX) $(CPPFLAGS) $(CXXFLAGS) -S -o [email protected] $<

%.o: %.s    
%.o: %.s
    sed -i 's|^\t\.section\t\.custom\.[0-9]\{1,\},"a\(G\)*",@progbits.*$$|\t\.section\t\.custom,"a",@progbits|g' $<
    $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o [email protected] $<

.PHONY: all clean
.INTERMEDIATE: $(ASMS)

all: prog

prog: $(OBJS)
    $(CXX) -o [email protected] $^

clean:
    rm -f prog $(OBJS) $(ASMS)

जिसमें से ./prog जीसीसी के साथ बनाया जा सकता है जो stdout पर 246 छपाई की अपेक्षा पूरी करता है।

मेसफाइल के तीन विवरणों की सूचना दें: -

  • हमें खाली पैटर्न के नियमों को लिखना है जैसे कि %.o: %.cpp उन नियमों के लिए मेक इनबिल्ट व्यंजनों को हटाने के लिए।
  • sed कमांड में हमें *$$ आवश्यकता होती है क्योंकि ईओएल मार्कर के रूप में $ विस्तार-विस्तार से बचने के लिए
  • -fno-gnu-unique को भरने के लिए संकलक फ्लैग में -fno-gnu-unique पारित किया गया है

यह एक ऐसा समाधान नहीं है, जिसे मैं एक खुले उपयोगकर्ता-आधार के रूप में छोड़ना चाहता हूं, जैसे कि स्टॉप-गैप। अगर यह सब से दूर ले जाना है तो मैं इनकार नहीं करूँगा: क्या समस्या की अंतर्निहितता पर हमला करने का कोई बेहतर तरीका नहीं है?