This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] TMS320F28379D:生成的 cinit 复制表错误、导致缓冲区溢出。

Guru**** 2418210 points
Other Parts Discussed in Thread: SYSCONFIG, C2000WARE

请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/1532185/tms320f28379d-the-generated-cinit-copy-table-wrong-causing-buffer-overflow

部件号:TMS320F28379D
Thread 中讨论的其他器件:SysConfigC2000WARE

工具/软件:

我定义了一个变量

static uint16_t myvar = 0;

我需要这个变量位于共享 ram (RAM_GS) 中

因此、我在 SysConfig 中添加了一个名为  LOCAL_RAM_GS 的用户节、在 CMD 文件中将这一行指定给该行

 LOCAL_RAM_GS {  }      >  RAM_GS

并向变量声明中添加了一个 pragma、看起来像这样。

#pragma DATA_SECTION( myvar, "LOCAL_RAM_GS" )
static bq_size_t myvar = 0;

一切都很好,直到我开始得到 ITRAP 例外。

我使用调试器发现另一个模块中 ramfunction 的第一个字节已被零覆盖 (ITRAP0)。

我的调查结果:

链接器为此变量分配 1 个字节、与映射文件中的这些片段一致

GLOBAL SYMBOLS: SORTED ALPHABETICALLY BY Name 

page  address   name                                                            
----  -------   ----                                                            
0     00011774  foo_readData                                   00091204
0     00011770  foo_sendData                                   00091200
0     00088c0d  bar_sendData   


zoo.obj

Run/Load            
Value     Binding   Name (Section)
--------  --------  ---------------
0009017d  global    Isr_IpcFlag0 (.text:retain)
0001176f  local     LOCAL_RAM_GS (LOCAL_RAM_GS)
00015980  local     other_var (.bss)
...
0001176f  local     myvar (LOCAL_RAM_GS)


LINKER GENERATED COPY TABLES

__TI_cinit_table @ 0009432c records: 6, size/record: 4, table size: 24
	.data: load addr=00093e10, load size=00000500 bytes, run addr=00015992, run size=00002d61 bytes, compression=lzss
	LOCAL_RAM_GS: load addr=00094316, load size=00000005 bytes, run addr=0001176f, run size=00000001 bytes, compression=copy
    ...
binit @ 00094348 records: 4, size/record: 6, table size: 26
    ...
	FOO_OBJ_TO_RAM: load addr=00091200, load size=0000010a, run addr=00011770, run size=0000010a, compression=none
	...
	

因此、`myvar`应置于 0x0001176f、且长度为 1

`foo_sendData`应放置在 0x00011770

 我在使用调试器从存储器读取的实际复制表中找到了`foo_sendData`被覆盖的原因。

来查看我找到的加载地址

`到 32 位、因为这就是 Δ___TI_auto_init`读取它的方式

`Handler_Table`是` TI_idx`的 idx、此 idx 指向 Δ__TI_decompress_none

第二个字是计数、通过`m __TI_decompress_none`传递到` emcpy`。 在这里、我发现一个“2",“,而、而不是映射文件中所示的 1。

这意味着 `__TI_decompress_none`->`memcpy`将写入地址 0x0001176f 和 0x00011770

0x00011770 是 foo_sendData 函数的第一个字节。

我尝试更改了用户段的配置、但在 SysConfig 中、我只能找到启用.align (2) 的选项、根据我的了解链接器手册、我需要使用.palign (2) 来确保为这种情况分配足够的存储器。

在一个短期的解决方案中、我看到如果我设置.align (2) 属性、它会将`myvar`放在后面有一个空洞。 但这很可能只是因为`myvar`之后的夹头也对齐了。 换言之、这是一个非常临时的解决办法。

请提供建议。

编辑:

几乎忘记了使用的工具版本:

Code Composer Studio 版本:12.8.1.00005

    器件=“TMS320F28379"</s>“
    工具链=“TI"</s>“
    ToolVersion=“22.6.0.LTS"</s>“
    product=“sysconfig:1.19.0;c2000ware_software_package:5.01.00.1“
    outputType=“可执行“
    outputFormat=“ELF"</s>“
编辑 2:
我已使用最新的编译器 22.6.2 进行了测试、结果相同。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Ping

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Martin:

    对延迟深表歉意。 此主题已分配给主题专家。 请给我们更多时间检查并返回。

    谢谢。此致、

    Sudesshna

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    很遗憾、您遇到了一个已知问题 EXT_EP-10875。  有关详细信息和解决方法、请访问该链接。  您将看到此修复在任何当前版本的 C28x 编译器中都不可用。  此论坛帖子中介绍了另一种权变措施。

    谢谢。此致、

    -乔治

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    你(们)好

    我已经深入研究了这一点。 这两种权变措施对我都不起作用。

    1.使用 `--cinit_compression=rle、lzss`选项无效、链接器仍会对小段使用复制/无处理程序。 (BTW。链接器不接受 `-cinit_compression=rle、lzss`如建议的那样、为 `--cinit_compression=lzss`或 `--cinit_compression=rle`)

    2.论坛帖子“在 main 初始化受影响的变量“。 这是一个 非常幼稚的建议、因为这意味着对于源代码任何部分的每次更改、我都必须检查链接器现在放置在我的小扇区之后... 除了在触发我调查的情况下,这是一个 RAM 函数被覆盖。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    抱歉。  对于您的情况、 此论坛帖子中提到的权 变措施需要进行一些更改。

    您当前应用的所有位置 pragma DATA_SECTION 、将其更改为使用 noinit 属性。  例如:

    __attribute__((noinit))
    static bq_size_t myvar;

    介绍如何在中初始化所有这些变量 _system_post_cinit 是类似的。  如果所有这些变量都在同一源文件中、则您可以继续保留它们 静态 、只要您同时实现 _system_post_cinit 在同一个文件中。  如果这些变量都是静态变量、并且位于不同的文件中、则必须将它们更改为全局变量。

    在链接器命令文件中更改...

     local_RAM_GS { }   > RAM_GS
     

    至...

        .TI.noinit > RAM_GS

    每个变量 noinit 属性位于名为的输入段中 .TI.noinit 。  此代码会创建一个名为的输出段 .TI.noinit 。  它由所有命名的输入节组成 .TI.noinit 。  此输出节将分配给内存范围 RAM_GS

    这意味着对于源代码任何部分的每次更改、我都必须检查链接器现在放在我的小扇区之后的位置

    实施此权变措施后、无需执行此类检查。

    谢谢。此致、

    -乔治

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尽管它解决了您的直接问题、但我对您的使用方式感到不快 palign (2) 。  它会导致输出段 LOCAL_RAM_GS 更大、因此中断的初始化会覆盖从未使用的存储器。  但它仍然存在。  我描述的权变措施完全可以防止中断的初始化发生。   

    谢谢。此致、

    -乔治

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我找到了更好的解决方案。

    下载汇编器/链接器手册中的链接

    8.5.5.2.6 与填充对齐
    与 align 一样、您可以告诉链接器将输出段放置在位于 n 字节边界上的地址处、
    其中 n 是 2 的幂、使用 palign 关键字。 此外、palign 可确保截面的大小为 a
    其位置对齐限制的倍数、会根据需要将段大小填充到这样的边界。

    使用此命令、我可以强制链接器至少分配 2 个字节的内存、因此它将与损坏的复制表匹配。

    该解决方案的唯一问题是、我们用于生成 CMD 文件的 SysConfig 不支持此选项。

    SysConfig 只能设置为生成对齐选项。

    我对此的变通办法(这成为一个变通办法:-)..)

    是向工程中添加一个.cmd 文件、因为 CCS 会自动将该文件映射起来并将其添加到从 SysConfig 生成的文件中。

    在该.cmd 文件中、我可以手动定义 local:gs_RAM 位置。

    SECTIONS
    {
        LOCAL_RAM_GS {  }    >  RAM_GS, PALIGN(2)
    }

    建议

    如果此解决方案支持、我强烈建议您更新 SysConfig 工具以支持配对选项。 并将其配置为在缺失时发出警告、因为如果闪存未设置为最小对齐值 8、它已经发出警告。

    我还强烈建议、如果 CMD 文件包含一个未与最小 2 对齐的小段、则添加警告或最少备注。

    文档也就此进行了更新。

    上述所有内容假定链接器本身的修复仍然很远。

    观察结果。

    我注意到、当我对链接器使用--fill 选项时、复制操作执行的额外写入操作包含该填充值。 这表明写入的不仅仅是一个随机零、而是有意地填充值。 这使我认为、生成实际复制表的链接器部分会看到单字节段被填充、就像我使用 paling (2) 时一样。 我想知道由从 charSize=8 切换到 charSize=16 创建的链接器内部是否存在不匹配。

    align (2) 也可用作权变措施、前提是需要确保满足这些条件 全部 段的对齐最少为 2。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
     它会导致输出段出现 LOCAL_RAM_GS 更大、因此中断的初始化会覆盖从未使用过的内存。

    这或多或少是填充应该做什么的定义。

    摘自同一手册

    如果链接器向初始化的输出段添加填充、则填充空间也会被初始化。 默认情况下、
    填充空间的填充值为 0(零)。 但是、如果为输出段指定了填充值、则不指定任何填充值
    该段的填充也将使用该填充值进行填充。

    正如我在观察到的那样、复制操作执行的额外写入操作是使用给定的填充值。 因此复制操作实际上是填充的。

    而填充本身不是问题, 实际上有几个地方,它是自动填充。 如果我查看最新的映射文件、我发现这个代码片段 “--hole --[fill =“ 6 次、这意味着链接器在存储器映射中填充了 6 次“空洞“。

    真正的问题是 创建内存映射的链接器部分没有考虑 LOCAL_RAM_GS 段的填充、因此复制表和内存映射不匹配、我们存在缓冲区溢出的风险。

    因此、通过提供此选项、我不会更改复制操作的作用或复制表的生成方式。 但它确实确保链接器的两端就此达成一致、并使链接器创建一个与复制表匹配的存储器映射。

    介绍如何在中初始化所有这些变量 _system_post_cinit 是类似的。  如果所有这些变量都在同一源文件中、则您可以继续保留它们 静态 、只要您同时实现 _system_post_cinit 在同一个文件中。  如果这些变量都是静态变量、并且位于不同的文件中、则必须将它们更改为全局变量。

    [/报价]

    我们制作可测试、可重复使用和可读的软件模块,因此我们不使用全局变量

    如果我只是想快速修复这个单一的案例,并让下一个开发人员在不知情的情况下再次遇到这个问题。 我本来可以删除 静态变量的显式初始化。

    此代码使变量通过在 cinit 中复制进行初始化。

    #pragma DATA_SECTION( myvar, "LOCAL_RAM_GS" )
    static bq_size_t myvar = 0;

    此代码使变量由 cinit 在 zero_init 中初始化、而 zero_init 不会受到此错误的影响。

    #pragma DATA_SECTION( myvar, "LOCAL_RAM_GS" )
    static bq_size_t myvar;

    尽管= 0静态变量的``初始化值在 C 中是多余的、但我经常将其放在那里以帮助代码的可读性。

    用作硅基指示器 。 我有点惊讶的是、编译器/链接器不会将第一个代码示例识别为零 init。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    确实希望对此做出一些答复、要么告诉我为什么我错了、要么确认此解决方案。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    告诉我为什么错误或确认此解决方案。

    “对不起,我不能接受。“  我已经解释了为什么我认为我建议的权变措施更好。  您不同意、希望使用其他解决方法。  我同意您的解决方法足以满足您的特定情况。  我认为这是一个合理的选择。

    谢谢。此致、

    -乔治