How does a structure declared as a static constant get into RAM? (in C)

I am trying to port some terribly confusing code from Codewarrior to Crossworks. Libraries are written in C, but I think they are trying to mimic C ++ objects.

When these objects are declared, they are done this way with macros that use macros, that use macros, which are very difficult to follow! I expanded them using a preprocessor to make it a little easier to understand.

Now, within the framework of the [working] Codwarrior Eclipse system, there is a section of text indicated in the source code as a static const that ends in RAM. As far as I can tell, the other things that are set as static const, the linker is placed in flash. In Crossworks, it all ends in flash - which makes sense to me.

Here is one example of a problem declaration after expanding it from macros:

static const D4D_LABEL scrSplash_lblSID_params = { { " Unit ID: 42949672955" , sizeof(" Unit ID: 42949672955"), 0, &scrSplash_lblSID_strPrties}, { 6, 76 }, { 118, 16 }, 8 }; 

D4D Label is defined as follows:

 typedef struct { D4D_STRING textBuff; // label text D4D_POINT scrPos; // position on the screen D4D_SIZE scrSize; // size on the screen (focus rect only, bitmaps have own size) D4D_COOR radius; // corner radius } D4D_LABEL; 

And D4D_STRING is defined below:

 typedef struct D4D_STRING_S { char *pText; D4D_INDEX buffSize; D4D_FONT fontId; D4D_STR_PROPERTIES *str_properties; D4D_INDEX printLen; D4D_INDEX printOff; }D4D_STRING; 

This D4D_LABEL is placed in D4D_OBJECT as follows:

 const D4D_OBJECT scrSplash_lblSID = { (void*)&(scrSplash_lblSID_params), (D4D_OBJECT_SYS_FUNCTION*)&d4d_labelSysFunc, (void*)0, (void*)0, (0x01 | 0x02 | 0x40), &(scrSplash_lblSID_flags), (void*)0, &(scrSplash_lblSID_pScreen) }; 

And D4D_OBJECT is defined as follows:

 // this is allocated in ROM always typedef struct D4D_OBJECT_S { void* pParam; D4D_OBJECT_SYS_FUNCTION* pObjFunc; Byte (*OnUsrMessage)(struct D4D_MESSAGE_S* pMsg); void *userPointer; D4D_OBJECT_INITFLAGS initFlags; D4D_OBJECT_FLAGS* flags; struct D4D_CLR_SCHEME_S* clrScheme; struct D4D_SCREEN_S** pScreen; } D4D_OBJECT; 

So, as far as I can see, the first thing that is placed in D4D_OBJECT, scrSplash_lblSID is a pointer to DSPD_LABEL scrSplash_lblSID_params. This D4D label is declared as a static constant and therefore is placed in a flash. Crossworks does this, Codewarrior has it in RAM though.

When using this function:

 void D4D_SetText(D4D_OBJECT_PTR pObject, char* pText) { D4D_STRING* p_TextBuff = NULL; if(pObject->pObjFunc->GetTextBuffer) p_TextBuff = pObject->pObjFunc->GetTextBuffer((D4D_OBJECT*)pObject); // ABOVE line equates to: return &(((D4D_LABEL*)((pThis)->pParam))->textBuff); if(p_TextBuff) { D4D_ChangeText(p_TextBuff, pText, 0); D4D_InvalidateObject(pObject, D4D_FALSE); } } 

In the next line:

 D4D_SetText(&scrSplash_lblSID, SIdString); 

p_TextBuff is the RAM location in Codewarrior and the Crossworks flash location. The ChangeText function tries to copy the line pointed to by pText to flash, and, of course, the processor (Cortex M4 from Freescale - the Kinetis processor) will work!

Is the above information sufficient to advise me? I guess there is something in the Codewarrior project linker file, which somehow allows you to make the corresponding line in RAM, rather than blinking. I do not see how the linker magically puts this static const in RAM and does not flash like other material!

The linker file is below, just in case this may be relevant.

Thank you very much!

 # Default linker command file. MEMORY { m_interrupts (RX) : ORIGIN = 0x00000000, LENGTH = 0x000001E0 # Interrupts m_text (RX) : ORIGIN = 0x00004400, LENGTH = 0x0003BC00 # Code and read only data m_data (RW) : ORIGIN = 0x1FFF0000, LENGTH = 0x00020000 # Read/write data } KEEP_SECTION { .vectortable } KEEP_SECTION { .cfmconfig } SECTIONS { .interrupts : { __vector_table = .; * (.vectortable) . = ALIGN (0x4); } > m_interrupts # All the stuff that lives in flash: the application (.text), read only data (.rodata) and .init - whatever the latter is .app_text: { ALIGNALL(4); * (.init) * (.text) .= ALIGN(0x8) ; * (.rodata) .= ALIGN(0x4) ; ___ROM_AT = .; } > m_text # App data is INITIALISED data. So stuff that was specified in flash, but gets copied to RAM at boot .app_data: AT(___ROM_AT) { * (.sdata) * (.data) .= ALIGN(0x4) ; *(.ARM.extab) .= ALIGN(0x4) ; __exception_table_start__ = .; EXCEPTION __exception_table_end__ = .; .= ALIGN(0x4) ; __sinit__ = .; STATICINIT .= ALIGN(0x8) ; } > m_data # .bss is UNINITIALISED data that just lives in normal RAM - after the initialised stuff .bss : { .= ALIGN(0x4) ; __START_BSS = .; * (.bss) __END_BSS = .; .= ALIGN(0x8) ; } >> m_data _romp_at = ___ROM_AT + SIZEOF(.app_data); .romp : AT(_romp_at) { __S_romp = _romp_at; WRITEW(___ROM_AT); WRITEW(ADDR(.app_data)); WRITEW(SIZEOF(.app_data)); WRITEW(0); WRITEW(0); WRITEW(0); } __SP_INIT = . + 0x00008000; __heap_addr = __SP_INIT; __heap_size = 0x00008000; } 
+4
source share
3 answers

It does not matter that the object is declared static const ; the line you are trying to write is the pointer inside D4D_STRING :

 typedef struct D4D_STRING_S { char *pText; 

This is initialized from the string literal " Unit ID: 42949672955" , and undefined behavior is written to the string literal.

If your compiler accepts the -fwritable-strings parameter (gcc up to 4.0, some versions of clang), you can use this option to place string literals in RAM. A preferred alternative is to use a mutable character buffer:

 char scrSplash_lblSID_params_text[] = " Unit ID: 42949672955"; 
+3
source

Added as answer:

Find the script linker file or something that sets up the sections of your platform. This is a magic file that tells the linker where the partitions go to RAM -.text goes to 0xf00, .bss to 0xbabe, etc. If this is a setting for storing lines in RAM on your system, you can work around this problem.

+3
source

TL DR

The short answer to the question is in the title: because it is not specified by the C language standard. The C implementation freely stores static const objects where it wants.

And string literals can be put into read-only memory, so don't try to modify them.

+2
source

Source: https://habr.com/ru/post/1481748/


All Articles