什么是Copy Table及如何使用Copy Table

admin 2024年11月27日11:06:18评论2 views字数 6444阅读21分28秒阅读模式

目录

什么是Copy Table及如何使用Copy Table

前言

嵌入式工程师应该都知道没有初始值的全局变量或者静态局部变量存放在.BSS段,有初始值的全局变量或者静态局部变量存放在.DATA段,芯片上电后我们需要将.BSS段都初始化为0值,将ROM中保存的全局变量或者静态局部变量的初始值拷贝到RAM中也就是.DATA段中。

那么问题来了,在哪个地方进行.BSS段清零以及.DATA段中RAM初始值的拷贝了?

熟悉英飞凌TC3xx芯片的朋友应该知道英飞凌芯片的启动分为6个阶段(Phase1 - Phase6),在__StartUpSoftware_Phase6()中完成.BSS段和.DATA段的初始值拷贝。TC3xx芯片的启动流程参考以下的文章:

参考文章:https://zhuanlan.zhihu.com/p/644563274

如下图所示,最终由Ifx_Ssw_C_InitInline()函数完成初始化C运行时变量,也就说.BSS段的清零及.DATA段的初始化。

Ifx_Ssw_C_InitInline()函数的具体实现根据编译的不同而不同,本文就来介绍3个常用编译器如何完成C运行时变量的初始化

什么是Copy Table及如何使用Copy Table

什么是Copy Table及如何使用Copy Table

什么是Copy Table及如何使用Copy Table

注:本文章引用了一些第三方工具和文档,若有侵权,请联系作者删除!

正文

1.GHS编译器

1.1. Clear and Copy Tables

Green Hills编译器会自动在.secinfo段(section)中定义三个表(Tables),Clear Table, Copy Table,以及compressed Copy table.

Table Type

Start address

End address

Clear Table

__ghsbinfo_clear

__ghseinfo_clear

Copy Table

__ghsbinfo_copy

__ghseinfo_copy

compressed Copy table

__ghsbinfo_comcopy

__ghseinfo_comcopy

注意:我们这里只套路Clear TableCopy Table, compressed copy table还不知道咋用的。

什么是Copy Table及如何使用Copy Table

Clear Table中存放的就是初始化.BSS段相关信息(未初始化的全局变量/静态局部变量的RAM地址、数据长度)。

什么是Copy Table及如何使用Copy Table

Copy Table中中存放的就是初始化.DATA段相关信息(初始化的全局变量/静态局部变量的RAM地址、初始化的全局变量/静态局部变量的初始值所在的ROM地址,数据长度)。

什么是Copy Table及如何使用Copy Table

1.2 Ifx_Ssw_C_InitInline实现

有了以上的理论分析,如下的代码实现应该容易看懂了:

typedef int          ptrdiff_t;typedef unsigned int syze_t;typedef signed int   signed_size_t;#define size_t syze_textern void *memcpy(void *s1, const void *s2, syze_t n);extern void *memset(void *s, int c, syze_t n);/* rodata is absolute */typedef const char rodata_ptr[];#define PICBASE     0#define PIDBASE     0#define PIRBASE     0#define CONST_FUNCP *constIFX_SSW_INLINE void Ifx_Ssw_C_InitInline(void){    /*----------------------------------------------------------------------*/    /*                  */    /*  Clear BSS              */    /*                  */    /*----------------------------------------------------------------------*/    {#pragma ghs rodata        extern rodata_ptr __ghsbinfo_clear;#pragma ghs rodata        extern rodata_ptr __ghseinfo_clear;#pragma ghs rodata        extern rodata_ptr __ghsbinfo_aclear;        void            **b = (void **)((char *)__ghsbinfo_clear);        void            **e = (void **)((char *)__ghseinfo_clear);        void            **a = __ghsbinfo_aclear != 0 ?                              ((void **)((char *)__ghsbinfo_aclear)) : e;        /* Warning:  This code assumes         * __ghsbinfo_clear <= __ghsbinfo_aclear <= __ghseinfo_clear         * Which is currently enforced with elxr         * OR         * __ghsbinfo_aclear == 0 (i.e.: undefined)         */        int OFFSET = PIDBASE;        while (b != e)        {            void     *t;        /* target pointer  */            ptrdiff_t v;        /* value to set    */            size_t    n;        /* set n bytes    */            while (b != a)            {                t = OFFSET + (char *)(*b++);                v = *((ptrdiff_t *)b); b++;                n = *((size_t *)b); b++;                (void)memset(t, v, n);            }            OFFSET = 0;            a      = e;        }    }    /*----------------------------------------------------------------------*/    /*                  */    /*  Copy from ROM to RAM            */    /*                  */    /*----------------------------------------------------------------------*/    {#pragma ghs rodata        extern rodata_ptr __ghsbinfo_copy;#pragma ghs rodata        extern rodata_ptr __ghsbinfo_tcopy;#pragma ghs rodata        extern rodata_ptr __ghseinfo_copy;        void            **b = (void **)((char *)__ghsbinfo_copy);        void            **m = (void **)((char *)__ghsbinfo_tcopy);        void            **e = (void **)((char *)__ghseinfo_copy);        while (b != e)        {            void  *t;               /* target pointer  */            void  *s;               /* source pointer  */            size_t n;               /* copy n bytes    */            t = ((b < m) ? PIDBASE : PICBASE) + (char *)(*b); b++;            s = PIRBASE + (char *)(*b++);            n = *((size_t *)b); b++;                   (void)memcpy(t, s, n);        }    }}

2.GNU编译器

2.1 Clear and Copy Tables

GNUGCC编译器不会自动给我们创建Clear TablesCopy Tables,需要我们在Link file(连接器脚本)中自定义Cleare TablesCopy Table这些标识符(地址符号)。

什么是Copy Table及如何使用Copy Table

参考文章:https://www.cnblogs.com/uestcliming666/p/11464709.html

__clear_table__copy_tablememory layout如下所示:

什么是Copy Table及如何使用Copy Table

2.2 Ifx_Ssw_C_InitInline实现

有了以上的理论分析,如下的代码实现应该容易看懂了:

extern unsigned int __clear_table[];  /**< clear table entry */extern unsigned int __copy_table[];   /**< copy table entry */IFX_SSW_INLINE void Ifx_Ssw_C_InitInline(void){    Ifx_Ssw_CTablePtr pBlockDest, pBlockSrc;    unsigned int      uiLength, uiCnt;    unsigned int     *pTable;    /* clear table */    pTable = (unsigned int *)&__clear_table;    while (pTable)    {        pBlockDest.uiPtr = (unsigned int *)*pTable++;        uiLength         = *pTable++;        /* we are finished when length == -1 */        if (uiLength == 0xFFFFFFFF)        {            break;        }        uiCnt = uiLength / 8;        while (uiCnt--)        {            *pBlockDest.ullPtr++ = 0;        }        if (uiLength & 0x4)        {            *pBlockDest.uiPtr++ = 0;        }        if (uiLength & 0x2)        {            *pBlockDest.usPtr++ = 0;        }        if (uiLength & 0x1)        {            *pBlockDest.ucPtr = 0;        }    }    /* copy table */    pTable = (unsigned int *)&__copy_table;    while (pTable)    {        pBlockSrc.uiPtr  = (unsigned int *)*pTable++;        pBlockDest.uiPtr = (unsigned int *)*pTable++;        uiLength         = *pTable++;        /* we are finished when length == -1 */        if (uiLength == 0xFFFFFFFF)        {            break;        }        uiCnt = uiLength / 8;        while (uiCnt--)        {            *pBlockDest.ullPtr++ = *pBlockSrc.ullPtr++;        }        if (uiLength & 0x4)        {            *pBlockDest.uiPtr++ = *pBlockSrc.uiPtr++;        }        if (uiLength & 0x2)        {            *pBlockDest.usPtr++ = *pBlockSrc.usPtr++;        }        if (uiLength & 0x1)        {            *pBlockDest.ucPtr = *pBlockSrc.ucPtr;        }    }}

3.Tasking编译器

3.1 Clear and Copy Tables

Tasking编译器不再区分Clear TableCopy Tables,统一都用一个copy table来存放.bss.data段的相关信息。_lc_ub_table标识符表示copy table的开始地址,_lc_ue_table标识符表示copy table的结束地址。

什么是Copy Table及如何使用Copy Table

值得注意的是,如果我们想让Tasking编译器生成_lc_ub_table_lc_ue_table标识符的地址信息,就必须不能勾选如下的编译选项

如果勾选了如下选项,就意味着需要和GNU编译器一样在连接器脚本中自定义copy table相关的标识符。

什么是Copy Table及如何使用Copy Table

Copy Tablememory layout如下所示:

什么是Copy Table及如何使用Copy Table

3.2 Ifx_Ssw_C_InitInline实现

有了以上的理论分析,如下的代码实现应该容易看懂了:

/* * Startup_CompilerTasking.c * *  Created on: 2024年10月27日 *      Author: Administrator */#include "Std_Types.h"#define LC_UB_TABLE_TYPE_BSS  (0x2u)#define LC_UB_TABLE_TYPE_DATA (0x1u)extern uint32 _lc_ub_table[];extern uint32 _lc_ue_table[];uint32* g_lc_ub_table;uint32* g_lc_ue_table;void _c_init(void){  const uint32* copyTable;  const uint32* currentPtr;  const uint32* srcU32Ptr;  uint32* dstU32Ptr;  uint32 sectionType;  uint32 length;  uint32 value;  uint32 count;  uint16* srcU16Ptr;  uint16* dstU16Ptr2;  uint8* srcU8Ptr;  uint8* dstU8Ptr;   /*Just for debug*/  g_lc_ub_table = (uint32*)&_lc_ub_table;  g_lc_ue_table = (uint32*)&_lc_ue_table;  for(copyTable = (uint32*)&_lc_ub_table;      copyTable != (uint32*)&_lc_ue_table;      copyTable += 4)  {    currentPtr = copyTable;    sectionType = currentPtr[0];    dstU32Ptr = (uint32*)currentPtr[1];    length = currentPtr[3];    if(LC_UB_TABLE_TYPE_BSS == sectionType)    {      value = currentPtr[2];      for(count = length / 4; count > 0; count--)      {        *dstU32Ptr++ = value;      }      dstU16Ptr2 = (uint16*)dstU32Ptr;      if(length & 0x2)      {        *dstU16Ptr2++ = (uint16)value;      }      dstU8Ptr = (uint8*)dstU16Ptr2;      if(length & 0x1)      {        *dstU8Ptr = (uint8)value;      }    }    else if(LC_UB_TABLE_TYPE_DATA == sectionType)    {      srcU32Ptr = (uint32*)currentPtr[2];      for(count = length / 4; count > 0; count--)      {        *dstU32Ptr++ = *srcU32Ptr++;      }      dstU16Ptr2 = (uint16*)dstU32Ptr;      srcU16Ptr = (uint16*)srcU32Ptr;      if(length & 0x2)      {        *dstU16Ptr2++ = *srcU16Ptr++;      }      dstU8Ptr = (uint8*)dstU16Ptr2;      srcU8Ptr = (uint8*)srcU16Ptr;      if(length & 0x1)      {        *dstU8Ptr = *srcU8Ptr;      }    }    else    {      //Do nothing    }  }}

3.3 调试分析

Copy Table的起始地址_lc_ub_table = 0x 80003036, 结束地址_lc_ue_table = 0x80003E3C

什么是Copy Table及如何使用Copy Table

TC387芯片中Copy TableMemory Layout的解析如下所示:

什么是Copy Table及如何使用Copy Table

4.总结

Copy Table用来初始化C环境下全局变量或者静态局部变量,Copy Table中保存了全局变量或者静态局部变量的RAM地址或者初始值的ROM地址以及数据长度信息,开发者需要在Startup代码中使用Copy Table完成全局变量或者静态局部变量的初始值从ROMRAM的搬运(或者清零.BSS段)。而这个过程,由于编译器特性不一样,需要开发者根据编译器特性来具体实现,具体参考正文内容。

值得注意的是,实际开发中如果我们使用编译器的启动代码,这个工作往往编译器自动帮忙我们实现了(很多初级的工程师可能都不知道这个copy table的存在)。但是,如果我们从芯片上电到Main函数之前的启动代码都是自己实现的(安全启动),Copy Table就必须要考虑了。

End

原文始发于微信公众号(汽车电子嵌入式):什么是Copy Table及如何使用Copy Table

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年11月27日11:06:18
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   什么是Copy Table及如何使用Copy Tablehttps://cn-sec.com/archives/3433619.html

发表评论

匿名网友 填写信息