5

我正在尝试将一些可怕的混淆代码从 Codewarrior 移植到 Crossworks。这些库是用 C 语言编写的,但我认为它正在尝试模仿 C++ 对象。

当这些对象被声明时,它们是通过使用宏的宏来完成的,这些宏使用宏,这使得它很难遵循!我使用预处理器扩展了它们,使其更容易理解。

现在,在基于 [工作] Codwarrior Eclipse 的系统下,有一段文本,在源代码中指定为静态 const,最终在 RAM 中。据我所见,链接器将其他指定为静态常量的东西放入闪存中。在 Crossworks 中,一切都以一闪而过——这对我来说是有道理的。

以下是从宏扩展后有问题的声明的一个示例:

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

D4D标签定义如下:

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;

D4D_STRING 定义如下:

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;

这个 D4D_LABEL 被放入一个 D4D_OBJECT 中,如下所示:

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) };

D4D_OBJECT 是这样定义的:

// 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;

据我所知,放入 D4D_OBJECT scrSplash_lblSID 的第一件事是指向 D4D_LABEL scrSplash_lblSID_params 的指针。该 D4D 标签被声明为静态常量,因此被放入闪存中。Crossworks 可以做到这一点,但 Codewarrior 将它放在 RAM 中。

使用此功能时:

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);
  }

}

通过以下行:

D4D_SetText(&scrSplash_lblSID, SIdString);

p_TextBuff 是 Codewarrior 中的 RAM 位置和 Crossworks 中的闪存位置。ChangeText 函数尝试将 pText 指向的字符串复制到闪存中,当然,处理器(飞思卡尔的 Cortex M4 - Kinetis 处理器)崩溃了!

以上是否有足够的信息可以为我提供建议?我猜想 Codewarrior 项目的链接器文件中有一些东西设法使相关字符串最终出现在 RAM 中而不是闪存中。我看不出链接器是如何神奇地知道将静态 const 放入 RAM 而不是像其他东西一样闪存!

链接器文件在下面,以防万一它可能是相关的。

非常感谢!

# 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

3 回答 3

3

也添加为答案:

查找链接器脚本文件或在您的平台上设置部分的文件。这是一个神奇的文件,它告诉链接器部分在 RAM 中的位置 - .text 到 0xf00,.bss 到 0xbabe 等。如果设置为将字符串放入系统上的 RAM,您可能能够解决此问题.

于 2013-05-20T16:31:48.460 回答
3

声明对象无关紧要static const;您尝试写入的字符串是内部的指针D4D_STRING

typedef struct D4D_STRING_S 
{
  char *pText;

这是从字符串文字初始化的" Unit ID: 42949672955",写入字符串文字是未定义的行为。

如果您的编译器接受该-fwritable-strings选项(4.0 之前的 gcc,某些版本的 clang),那么您可以使用该选项将字符串文字放入 RAM。首选的替代方法是使用可变字符缓冲区:

char scrSplash_lblSID_params_text[] = "   Unit ID: 42949672955";
于 2013-05-20T12:24:22.270 回答
2

TL;博士

标题中问题的简短回答是:因为它没有由 C 语言标准指定。AC 实现可以自由地将静态 const 对象存储在它想要的位置。

并且字符串文字可以放在只读内存中,所以不要试图修改它们。

于 2013-05-20T11:59:27.370 回答