【问题标题】:Reserve memory space in m_text memory region of FLASH on embedded target在嵌入式目标上的 FLASH 的 m_text 内存区域中保留内存空间
【发布时间】:2015-06-08 14:22:20
【问题描述】:

我有一个微控制器,它有很多闪存,分为 1k 个闪存扇区。 我想在闪存期间将质数闪存到特定的内存区域,然后在第一次启动期间将生成一个加密密钥,然后质数将被擦除并覆盖。

我希望将质数隐藏在 m_text 中,而不是使用链接描述文件为质数创建读/写内存区域。

固件、素数和引导加载程序分别编译,生成 3 个用于闪存的 .hex 文件。

假设固件代码从 0x2000 开始,长度为 0x2000,在该区域内,我想分配一个 1024 字节的扇区,以后可以擦除和覆盖该扇区,而不会使固件变砖。

使用以下代码,我可以读取、擦除和写入数据到闪存,但我有一些问题:

  1. 使用以下代码 gcc 会在 0x3000 分配扇区吗?如果没有,怎么办?
  2. 您知道更好的方法吗?

代码:

...
typedef uint8_t sector[1024];
uint32_t* prime = (sector*)0x3000;
uint32_t data = *prime;
uint32_t dataToWrite = 0xdeadbeef;

flash_init();
flash_sector_erase(0x3000);
flash_block(0x3000,(uint8_t*)&dataToWrite,4);
data = *prime;
...

链接脚本

MEMORY {
  ...
  m_text(rx): ORIGIN = 0x00002000, LENGTH = 0x2000
  ...
}

更新: 我必须使用 GCC 在给定的闪存地址保留空间,这表明其他编译器对此有解决方案,但使用 GCC 我必须使用链接器脚本。

来自here 我读到这个:

特殊的链接器变量点 `.'始终包含当前输出 位置计数器。自 .总是指输出中的一个位置 部分,它只能出现在 SECTIONS 中的表达式中 命令。这 。符号可能出现在普通符号所在的任何地方 允许在表达式中。

为 .将导致位置计数器移动。 这可用于在输出部分创建孔。那个地点 计数器可能永远不会向后移动。

SECTIONS
{
  output :
    {
      file1(.text)
      . = . + 1000;
      file2(.text)
      . += 1000;
      file3(.text)
    } = 0x1234;
}

在前面的示例中,.text' section fromfile1' 位于 在输出部分的开头 output'. It is followed by a 1000 byte gap. Then the.text' 部分来自 file2' appears, also with a 1000 byte gap following before the.text' 部分来自 file3'. The notation= 0x1234' 指定要写入的数据 间隙(请参阅输出部分填充部分)。

我的 m_text 部分如下所示:

  .text :
  {
    . = ALIGN(4);
    *(.text)                 /* .text sections (code) */
    *(.text*)                /* .text* sections (code) */
    *(.rodata)               /* .rodata sections (constants, strings, etc.) */
    *(.rodata*)              /* .rodata* sections (constants, strings, etc.) */
    *(.glue_7)               /* glue arm to thumb code */
    *(.glue_7t)              /* glue thumb to arm code */
    *(.eh_frame)
    KEEP (*(.init))
    KEEP (*(.fini))
    . = ALIGN(4);
  } > m_text

所以我能做的就是把它改成:

  .text :
  {
    . = ALIGN(4);
    *(.text)                 /* .text sections (code) */
    . = NEXT(0x400);         /* move to start of next  1kb section*/
    . += 0x400;              /* jump 1k forward */
    *(.text*)                /* .text* sections (code) */
    *(.rodata)               /* .rodata sections (constants, strings, etc.) */
    *(.rodata*)              /* .rodata* sections (constants, strings, etc.) */
    *(.glue_7)               /* glue arm to thumb code */
    *(.glue_7t)              /* glue thumb to arm code */
    *(.eh_frame)
    KEEP (*(.init))
    KEEP (*(.fini))
    . = ALIGN(4);
  } > m_text

现在我们在闪存上保留了数据,但地址将取决于 .text 的大小,这并不理想,但如果我们将 FW 代码中的直接寻址更改为节名然后取来自 FW 项目的 .text 的大小并填充到下一个 1024 字节扇区以获取我们将导入到 Prime number 项目的地址。

我对扇区之前的填充也不太满意,在理想情况下,我们会用“垃圾代码”或随机数据填充它,我已经看到您可以指定要填充的模式,但任何一致的模式将向逆向工程师发出多达 0xffffff 或 0x00000 ;)

有更好的想法吗?

【问题讨论】:

标签: c embedded bare-metal linker-scripts


【解决方案1】:

不确定您使用的是什么编译器,但使用 GCC,您可以使用 section 属性 details here 指定部分。

【讨论】:

    【解决方案2】:

    您可以使用 gcc __attribute__((section("m_text") )) 将数组定位到 m_text 部分。

    内存区域不是一个段。因此,您需要将此部分添加到链接描述文件中,将其放入此内存区域(不确定,如果两者都使用不同的命名空间,但最好为区域和部分使用不同的名称)。如果程序没有加载它,它必须是NOLOAD(很像.bss)。

    或者您只使用 C 构造,根本不使用链接器工具。但是,这将阻止数据与程序一起加载,因此仅当您打算将该区域与程序分开编程时才有效。

    【讨论】:

    • 素数和bootloader分别编译,产生3个.hex文件用于刷机。
    • @Maidenone:然后我要么使用 C-only 方法,使用转换为实际类型的绝对地址(很像外围寄存器 - 你可以使用 const 来防止无意写入),或者NOLOAD 方法。
    • 但是我如何控制内存的分配位置?假设程序从 0 开始,长度为 200,我想将素数设为 50,而不覆盖我的程序数据。
    • @Maidenone:您必须更改程序的闪存区域以排除保留的(m_text)区域。最好的建议是将最上面的扇区用于数组/表,并将所有低于该扇区的扇区用于程序,反之亦然(对于 ARM,您最好保留较低的两个扇区,因为 ARM 期望其复位向量位于较低的 1/2 字)。请注意,如果您想从引导加载程序中单独擦除/写入表,则需要为每个单独的扇区。
    • @Maidenone:请注意,您不是分配,而是保留该区域。这是一个很小但很重要的区别。
    猜你喜欢
    • 2011-01-30
    • 1970-01-01
    • 2018-12-18
    • 1970-01-01
    • 2014-06-22
    • 1970-01-01
    • 2020-08-12
    • 2021-06-05
    • 1970-01-01
    相关资源
    最近更新 更多