2012-01-25 26 views
5

हमारी टीम वर्तमान में जीसीसी 4.5.1 के एक अनुकूलित संस्करण का उपयोग कर एआरएम कॉर्टेक्स एम 3 मंच पर आधारित एक पुराने उत्पाद से पुराने पोर्ट्रक्चर से कुछ पोर्ट कोड का उपयोग कर रही है। हम एक संचार लिंक से डेटा पढ़ रहे हैं, और कच्चे बाइट सरणी को डेटा को स्पष्ट रूप से पार्स करने के लिए एक स्ट्रक्चर में डालने का प्रयास कर रहे हैं। एक संरचना और dereferencing के लिए सूचक कास्टिंग करने के बाद, हमें एक चेतावनी मिल रही है: "dereferencing प्रकार-दंडित सूचक सख्त-एलियासिंग नियम तोड़ देगा"।एम्बेडेड सिस्टम में टाइप-पनिंग को सुरक्षित रूप से कैसे करें

कुछ शोध के बाद, मुझे एहसास हुआ है कि चूंकि चार सरणी में कोई संरेखण नियम नहीं है और संरचना को गठबंधन शब्द होना है, पॉइंटर्स को कास्टिंग अपरिभाषित व्यवहार (एक बुरी बात) का कारण बनता है। मैं सोच रहा हूं कि क्या करने की कोशिश करने का एक बेहतर तरीका है।

मैं जानता हूँ कि हम स्पष्ट रूप से जीसीसी का उपयोग शब्द-संरेखित कर सकते हैं चार सरणी "विशेषता ((गठबंधन (4)))"। मेरा मानना ​​है कि यह हमारा कोड "सुरक्षित" बना देगा, लेकिन चेतावनियां अभी भी हमारे निर्माण को अव्यवस्थित कर देगी, और यदि स्थिति फिर से उत्पन्न होती है तो मैं चेतावनियों को अक्षम नहीं करना चाहता हूं। हम जो चाहते हैं वह सुरक्षित रूप से करने का एक तरीका है जिसे हम कोशिश कर रहे हैं, जो हमें तब भी सूचित करेगा यदि हम बाद में किसी अन्य जगह में असुरक्षित कुछ करने का प्रयास करते हैं। चूंकि यह एक एम्बेडेड सिस्टम है, इसलिए कुछ डिग्री के लिए रैम उपयोग और फ्लैश उपयोग महत्वपूर्ण हैं।

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

#define MESSAGE_TYPE_A 0 
#define MESSAGE_TYPE_B 1 

typedef struct MessageA __attribute__((__packed__)) 
{ 
    unsigned char messageType; 
    unsigned short data1; 
    unsigned int data2; 
} 

typedef struct MessageB __attribute__((__packed__)) 
{ 
    unsigned char messageType; 
    unsigned char data3; 
    unsigned char data4; 
} 


// This gets filled by the comm system, assume from a UART interrupt or similar 
unsigned char data[100]; 


// Assume this gets called once we receive a full message 
void ProcessMessage() 
{ 
    MessageA* messageA; 
    unsigned char messageType = data[0]; 

    if (messageType == MESSAGE_TYPE_A) 
    { 
     // Cast data to struct and attempt to read 
     messageA = (MessageA*)data; // Not safe since data may not be word aligned 
            // This may cause undefined behavior 

     if (messageA->data1 == 4) // warning would be here, when we use the data at the pointer 
     { 
      // Perform some action... 
     } 
    } 
    // ... 
    // process different types of messages 
} 
+1

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

उत्तर

1

कॉर्टेक्स एम 3 असाइन किए गए एक्सेस को ठीक से संभाल सकता है। मैंने इसे एम 3 के साथ समान पैकेट प्रोसेसिंग सिस्टम में किया है। आपको कुछ भी करने की ज़रूरत नहीं है, आप केवल चेतावनी से छुटकारा पाने के लिए ध्वज-फनो-सख्त-एलियासिंग का उपयोग कर सकते हैं।

+0

क्या यह पूरी रैम के लिए मामला है, या क्या सीमाएं हैं? – shenles

+1

कॉर्टेक्स किसी भी पते, रैम, रोम इत्यादि के लिए असाइन किए गए पढ़/लिख सकता है। आपको यूनियनों का उपयोग करने या पैक किए गए ढांचे से बचने के बारे में सभी टिप्पणियों को अवहेलना करना चाहिए। वे क्या कह रहे हैं कुछ CPUs या पोर्टेबल कोड लिखने के लिए सच है। एम्बेडेड सिस्टम में पैकेट प्रोसेसिंग करने पर आमतौर पर आपके आने वाले डेटा संरेखण के बारे में कोई विकल्प नहीं होता है। कोड कोड और गति में यह सबसे कुशल है कि सीपीयू को असाइन किए गए एक्सेस को संभालने दें। – TJD

+1

-फनो-सख्त-एलियासिंग एक बहुत उपयोगी अनुकूलन बंद कर देता है। निश्चित रूप से, यह बुरी तरह लिखित कोड के साथ कुछ समस्याओं के आसपास काम करता है, और हां यह कष्टप्रद चेतावनी को ठीक कोड में चला जाता है जो संकलक (जैसे) को खराब करता है, लेकिन वास्तव में, मैं उस विकल्प का उपयोग करने की सलाह नहीं दूंगा। – ams

2

जीसीसी एक -fno-strict-aliasing झंडा कि सख्त अलियासिंग आधारित अनुकूलन अक्षम करें और अपने कोड सुरक्षित कर देगा है:

यहाँ एक (बहुत सरल) हम वर्तमान में क्या कर रहे हैं उदाहरण है।

यदि आप वास्तव में इसे "ठीक करने" का कोई तरीका ढूंढ रहे हैं, तो आपको अपने कोड के तरीके पर पुनर्विचार करना होगा। तुम बस संरचना जिस तरह से आप की कोशिश कर रहे ओवरले नहीं कर सकता है, तो आप कुछ इस तरह करने की जरूरत है:

MessageA messageA; 
messageA.messageType = data[0]; 
// Watch out - endianness and `sizeof(short)` dependent! 
messageA.data1 = (data[1] << 8) + data[2]; 
// Watch out - endianness and `sizeof(int)` dependent! 
messageA.data2 = (data[3] << 24) + (data[4] << 16) 
       + (data[5] << 8) + data[6]; 

इस विधि आप अपने संरचना है, जो भी में कहीं और इसके प्रदर्शन विशेषताओं में सुधार हो सकता पैकिंग से बचने दूँगी तुम्हारा कोड। वैकल्पिक रूप से:

MessageA messageA; 
memcpy(&messageA, data, sizeof messageA); 

यह आपके पैक किए गए ढांचे के साथ करेगा। यदि आवश्यक हो तो संरचनाओं को एक फ्लैट बफर में वापस अनुवाद करने के लिए आप रिवर्स ऑपरेशंस करेंगे। या char * की तुलना में अलग char की एक हस्ताक्षरित/अहस्ताक्षरित संस्करण के लिए सूचक प्रकार के कलाकारों के माध्यम से

+0

तो यह गारंटी देगा कि चार सरणी शब्द सीमा पर गठबंधन है? मैंने यह विकल्प देखा, लेकिन इस धारणा के तहत था कि यह परिवर्तनीय संरेखण की अंतर्निहित समस्या को ठीक नहीं करेगा। – shenles

+1

@ शेल्स - बिलकुल नहीं। यदि आपका कंपाइलर असाइन किए गए ऑफसेट पर शब्द पहुंचने पर जोर देने जा रहा है, तो संभवतः आप किसी भी * पैक की गई संरचना स्थिति के साथ भाग्य से बाहर हैं। यदि आपको ऐसी कोई समस्या है, तो आपको 'char' सरणी से और अपने संरचनाओं का अनुवाद करने के तरीके के रूप में मेरे उत्तर में दिए गए उदाहरणों में से एक उदाहरण का उपयोग करना होगा। –

+0

हालांकि, यदि आप structs को 'पैक' के रूप में एनोटेट करते हैं, तो जीसीसी उन सदस्यों तक पहुंच पर सुरक्षित कोड उत्पन्न करेगा जो अन्यथा अनचाहे पहुंच के परिणामस्वरूप उत्पन्न होंगे, जेनरेट कोड यहां बिटवाई ऑप्स के समान ही होगा। (कम से कम XScale के लिए, मुझे नहीं पता कि यह सभी लक्ष्यों के लिए है या नहीं) – nos

4

प्रकार punning कड़ाई अनुरूप के रूप में यह सी अलियासिंग के नियमों का उल्लंघन (और कभी कभी संरेखण नियमों अगर कोई ध्यान दिया जाता है) नहीं है।

हालांकि, gcc परमिट प्रकार यूनियन प्रकारों के माध्यम से दंडित करते हैं। gcc की मैनपेज स्पष्ट रूप से इसे दस्तावेजों:

एक अलग संघ सदस्य से पढ़ एक से सबसे हाल ही में (बुलाया "टाइप-punning") को पत्र लिखा आम है का अभ्यास। -fstrict-aliasing के साथ भी, टाइप-पनिंग की अनुमति है, बशर्ते स्मृति प्रकार को यूनियन प्रकार के माध्यम से एक्सेस किया जाए। -fno-strict-aliasing:

साथ gcc (और इस प्रकार कार्यक्रम सी अलियासिंग नियमों को तोड़ने के लिए अनुमति देते हैं), कार्यक्रम के साथ संकलित किया जा सकता aliasing नियमों से संबंधित अनुकूलन अक्षम करने के लिए।ध्यान दें कि इस विकल्प को सक्षम करने के साथ, प्रोग्राम अब सख्ती से अनुरूप नहीं है, लेकिन आपने कहा कि पोर्टेबिलिटी चिंता का विषय नहीं है। जानकारी के लिए, लिनक्स कर्नेल इस विकल्प के साथ संकलित है।

+0

आप सुझाव दे रहे हैं कि मैं प्रत्येक संदेश संरचना के साथ एक संघ बना सकता हूं, फिर बफर से स्थानीय यूनियन प्रकार में एक एकल memcpy प्रदर्शन कर सकते हैं?यह काम कर सकता है, और शायद राम या फ्लैश स्पेस में बहुत दर्दनाक नहीं होगा। – shenles

+0

@ शेल्स संरचना प्रकारों में 'char' के सरणी की तुलना में अलग-अलग संरेखण होते हैं और प्रकार 'संरचना ए' की संरचना के प्रकार 'संरचना बी' की संरचना से भिन्न संरेखण हो सकता है। विभिन्न संरचना (या संरचनाओं और 'char' की सरणी) के एक संघ का उपयोग करने से आपको इन प्रकारों के लिए सही संरेखण मिल सकता है। – ouah

+1

आप इसमें प्रत्येक संदेश प्रकार और एक चार सरणी के साथ एक संघ हो सकता है। फिर आप पैकेट को सीधे संघ में चार सरणी में पढ़ते हैं और इसे अन्य संघ क्षेत्रों के माध्यम से एक्सेस करते हैं। –

3

पैक किए गए ढांचे और memcpy का उपयोग करके सही आकार और प्रकार के चर में अलग-अलग फ़ील्ड का उपयोग करना बंद करें। आप जो हासिल करने की कोशिश कर रहे हैं, वह करने के लिए यह सुरक्षित, पोर्टेबल, साफ तरीका है। यदि आप भाग्यशाली हैं, तो gcc छोटे निश्चित आकार memcpy को कुछ सरल लोड और स्टोर निर्देशों में अनुकूलित करेगा।

+0

किसी संदेश के प्रत्येक तर्क के लिए एक memcpy जोड़ना, समय की संख्या हमारे कोड-स्थान और प्रदर्शन के लिए काफी अपमानजनक होगी। यह एक एम्बेडेड सिस्टम है, जिसमें एक बहुत ही वास्तविक मेमोरी कैप है (हमारे मामले में लगभग 64 के फ्लैश कुल)। – shenles

+1

जैसा कि मैंने कहा, संकलक को उसी लोड निर्देशों में संकलित करना चाहिए क्योंकि असाइनमेंट मान्य था, "असाइनमेंट" होगा। –

4

जैसा कि पहले से ही बताया गया है, कास्टिंग पॉइंटर्स एक डोडी अभ्यास है।

समाधान: एक संघ

struct message { 
    unsigned char messageType; 
    union { 
    struct { 
     int data1; 
     short data2; 
    } A; 
    struct { 
     char data1[5]; 
     int data2; 
    } B; 
    } data; 
}; 

void func (...) { 
    struct message msg; 
    getMessage (&msg); 

    switch (msg.messageType) { 
    case TYPEA: 
     doStuff (msg.data.A.data1); 
     break; 
    case TYPEB: 
     doOtherStuff (msg.data.B.data1); 
     break; 
    } 
} 

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

कूप के, आपको यह सुनिश्चित करना होगा कि संरचना संरेखण और पैकिंग आपके संदेश प्रारूप से मेल खाती है। एंडियन मुद्दों से सावधान रहें और ऐसे में यदि लिंक के दूसरे छोर पर मशीन मेल नहीं खाती है।

0

असाइन किए गए एक्सेस के लिए, linux macros get_unaligned/put_unaligned देखें।

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

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