I am trying to port some hideously obfuscated code from Codewarrior to Crossworks. The libraries are written in C, but - I think - are trying to mimic C++ objects.
When these objects are declared they are done so with macros that use macros that use macros which makes it very difficult to follow! I have expanded them out using the preprocessor to make it a little easier to understand.
Now, under the [working] Codwarrior Eclipse based system, there is a section of text, specified in the source code as static const that ends up in RAM. As far as I can see, other stuff that is specified as static const, the linker puts into flash. In Crossworks, it all ends up in flash - which to me makes sense.
Here's one example of a problematic declaration after it's been expanded from the 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 put into a 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 thus:
// 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 put into the D4D_OBJECT scrSplash_lblSID is a pointer to the D4D_LABEL scrSplash_lblSID_params. That D4D label is declared as static const and so put into flash. Crossworks does that, Codewarrior has it in RAM though.
When this function is used:
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);
}
}
By the following line:
D4D_SetText(&scrSplash_lblSID, SIdString);
p_TextBuff is a RAM location in Codewarrior and a flash location Crossworks. ChangeText function tries to copy the string pointed to by pText into flash and, of course, the processor (a Cortex M4 by Freescale - a Kinetis processor) crashes!
Is the above anywhere near enough information to be able to advise me? I am guessing there's something in the linker file on the Codewarrior project that somehow manages to make the relevant string end up in RAM not flash. I cannot see how the linker magically knows to put that static const in RAM and not flash like the other stuff!
The linker file is below just in case it might be relevant.
Many thanks!
# 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;
}
It's irrelevant that the object is declared static const
; the string that you're trying to write to is the pointer inside D4D_STRING
:
typedef struct D4D_STRING_S
{
char *pText;
This is initialized from the string literal " Unit ID: 42949672955"
, and it is undefined behavior to write to a string literal.
If your compiler accepts the -fwritable-strings
option (gcc before 4.0, some versions of clang) then you can use that option to put string literals in RAM. The preferred alternative is to use a mutable character buffer:
char scrSplash_lblSID_params_text[] = " Unit ID: 42949672955";
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With