gpt4 book ai didi

c - 将memcpy移至另一个代码段

转载 作者:太空狗 更新时间:2023-10-29 15:41:56 26 4
gpt4 key购买 nike

我正在构建一个运行在arm cortex-m0+微控制器上的软件。它包括一个USB引导加载程序,在调用函数时作为辅助程序运行。编译期间插入memcpy函数有问题。
背景
链接器脚本是一切的开始。大部分都是直截了当的标准。程序存储在.text中,并从中执行。.text中的所有内容都存储在芯片的闪存部分。
奇怪的是引导加载程序运行的部分。为了能够在不重写引导加载器代码的情况下写入所有flash,我的引导加载器入口点将引导加载器程序的副本初始化到微控制器的sram部分,然后从那里执行它。这样,引导加载程序就可以安全地删除设备上的所有闪存,而不会意外地删除自己。
这是通过在链接器脚本中做一个伪造的“覆盖”来实现的(真实的OVERLAY与我的用例不太匹配):

/**
* The bootloader and general ram live in the same area of memory
* NOTE: The bootloader gets its own special RAM space and it lives on top
* of both .data and .bss.
*/

_shared_start = .;
.bootloader _shared_start : AT(_end_flash)
{
/* We keep the bootloader and its data together */
_start_bootloader_flash = LOADADDR(.bootloader);
_start_bootloader = .;
*(.bootloader.data)
*(.bootloader.data.*)
. = ALIGN(1024); /* Interrupt vector tables must be aligned to a 1024-byte boundary */
*(.bootloader.interrupt_vector_table)
*(.bootloader)
_end_bootloader = .;
}

.data _shared_start : AT(_end_flash + SIZEOF(.bootloader))
{
_start_data_flash = LOADADDR(.data);
_start_data = .;
*(.data)
*(.data.*)
*(.shdata)
_end_data = .;
}
. = _shared_start + SIZEOF (.data);
_bootloader_size = _end_bootloader - _start_bootloader;
_data_size = _end_data - _start_data;

_end_flash是对上一节末尾的引用,该节将其所有数据存储在flash中( .text.rodata.init…基本上任何只读的内容都会被卡在那里)。
这样做的结果是 .data.bss部分通常位于ram中。然而, .bootloader部分也位于ram中的同一位置。编译时,这两个部分按顺序存储到flash中。在我的 crt0例程中, .data部分从flash复制到ram中相应的地址(由 _start_data指定),并且 .bss部分归零。我有一个附加的部分存储在 .text部分,它通过将flash中的数据复制到ram中来启动引导加载程序,覆盖 .data.bss中的内容。Bootloader唯一的退出是系统重置,所以它可以破坏正在运行的程序的数据。将引导加载程序复制到ram后,它将执行它。
问题
显然,在编译覆盖程序并确保所有引用都对齐时可能会出现一些问题。为了减少从普通程序访问引导加载程序代码或从引导加载程序访问普通 .data.bss时出现的问题,我的链接器脚本中有以下三行代码:
NOCROSSREFS(.bootloader .text);
NOCROSSREFS(.bootloader .data);
NOCROSSREFS(.bootloader .bss);

现在,每当我在 .text(可能被引导加载程序擦除)、 .data(引导加载程序位于其上)或 .bss(引导加载程序再次位于其上)与 .bootloader部分之间有交叉时,就会发出编译器错误。
在我真正开始写代码之前,这一切都很成功。我的部分代码包括一些结构复制和其他类似的东西。显然,编译器决定这样做( bootloader_函数位于 .bootloader部分):
20000340 <bootloader_usb_endp0_handler>:
...
20000398: 1c11 adds r1, r2, #0
2000039a: 1c1a adds r2, r3, #0
2000039c: f000 f8e0 bl 20000560 <__memcpy_veneer>
...
20000560 <__memcpy_veneer>:
20000560: b401 push {r0}
20000562: 4802 ldr r0, [pc, #8] ; (2000056c <__memcpy_veneer+0xc>)
20000564: 4684 mov ip, r0
20000566: bc01 pop {r0}
20000568: 4760 bx ip
2000056a: bf00 nop
2000056c: 00000869 andeq r0, r0, r9, ror #16

在我的芯片架构中,地址 0x20000000直到 0xE000000左右都位于sram中(我在设备上只有4kb的地址)。下面的任何地址都位于flash部分。
问题是:在位于我的 0x1fffffc00部分( .bootloader)的函数中,插入了对 bootloader_usb_endp0_handlermemcpy2000039c20000562)的引用,因为我正在执行结构复制等操作。它对 2000056c的引用位于地址 memcpy,该地址位于闪存中…可以擦除。
具体代码如下:
static setup_t last_setup;
last_setup = *((setup_t*)(bdt->addr));

其中 0x00000869是一个双字结构, setup_t是一个 bdt->addr,我知道它指向的数据看起来像一个 void*。此行生成对 setup_t的调用。
我的问题是:我真的很想保留我的结构复制。很方便。有没有什么方法可以指定编译器将memcpy放在默认的部分之外的特定部分?我希望这种情况只发生在引导加载程序模块上。所有其他代码都可以是 memcpy。。我只想为位于 memcpy中的引导加载程序模块提供一个特殊的副本。
如果这根本不可能,我将在程序集中编写整个bootloader(没有那么有趣),或者单独编译bootloader,将其作为一个相当长的十六进制字符串包含在最终程序中,并在将其复制到ram后执行该字符串。这条线对我不太有吸引力,因为它是易碎的,很难实施…所以任何其他的建议也会很感激。
此模块的编译行为:
arm-none-eabi-gcc -Wall -fno-common -mthumb -mcpu=cortex-m0plus -ffreestanding -fno-builtin -nodefaultlibs -nostdlib -O0 -c src/bootloader.c -o obj/bootloader.o

通常情况下,优化是 .bootloader,但我试图摆脱 -Os。。它不起作用。
而且,我已经查看了 this question但它没有解决问题。

最佳答案

我从未尝试过,但您可能会使用EXTERN()链接器脚本指令来强制加载您的newlibmemcpy()两次-首先在引导加载程序链接阶段加载到所需的部分,然后取消定义并再次将其链接到“正常”代码中。

关于c - 将memcpy移至另一个代码段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28104672/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com