ARM Cortex-M0+ マイクロコントローラーで実行するためのソフトウェアを構築しています。関数の呼び出し時にセカンダリ プログラムとして実行される種類の USB ブートローダーが含まれています。memcpy
コンパイル中の関数の挿入に問題があります。
バックグラウンド
リンカー スクリプトがすべての始まりです。そのほとんどは非常に簡単で標準的なものです。プログラムはそこに保存され.text
、そこからも実行されます。すべてが.text
チップのフラッシュセクションに保存されます。
奇妙なのは、ブートローダーが実行される部分です。ブートローダ コードを上書きせずにすべてのフラッシュを書き込めるようにするために、私のブートローダ エントリ ポイントは、マイクロコントローラの 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
すべてのデータをフラッシュに保存した前のセクションの最後への参照です ( .text
、.rodata
、.init
...基本的に読み取り専用のものはすべてそこにスタックします)。
これにより、セクション.data
と.bss
セクションは通常 RAM に存在します。ただし、.bootloader
セクションは RAM の同じ場所にも存在します。両方のセクションは、コンパイル時に順番にフラッシュに保存されます。私のcrt0
ルーチンでは、.data
セクションはフラッシュから RAM 内の適切なアドレス ( で指定_start_data
) にコピーされ、.bss
セクションはゼロになります。.text
フラッシュから RAM にデータをコピーしてブートローダーを開始するセクションに追加のセクションを保存し、.data
とにあったものを上書きします.bss
。ブートローダからの唯一の終了はシステム リセットであるため、実行中のプログラムのデータが破壊されても問題ありません。ブートローダを RAM にコピーした後、それを実行します。
質問
明らかに、オーバーレイされたプログラムをコンパイルし、すべての参照が揃っていることを確認する際に、いくつかの問題が発生する可能性があります。.data
通常のプログラムからブートローダー コードにアクセスしたり、通常のプログラムやブートローダーからアクセスしたりする際に発生する問題を軽減するため.bss
に、リンカー スクリプトに次の 3 行を追加しました。
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 しかありません)。以下のアドレスはすべて0x1fffffc00
フラッシュ セクションにあります。
.bootloader
問題はこれです: 私のセクション ( bootloader_usb_endp0_handler
) にある私の関数では、memcpy
( 2000039c
、20000562
、および2000056c
) への参照が挿入されました。これは、特に構造体のコピーを行っているためです。それが置かれた参照は、フラッシュに存在するmemcpy
アドレスにあります...消去される可能性があります。0x00000869
特定のコードは次のとおりです。
static setup_t last_setup;
last_setup = *((setup_t*)(bdt->addr));
どこsetup_t
でbdt->addr
_ void*
_ setup_t
_ この行は への呼び出しを生成しますmemcpy
。
私の質問は、構造体のコピーを維持したいということです。それは便利です。memcpy をデフォルト以外の特定のセクションに配置するようにコンパイラに指定する方法はありますか? ブートローダーモジュールだけでそれが起こるようにしたい. 他のすべてのコードはそれを持つことができますmemcpy
...内部にあるブートローダーモジュールの特別なコピーが欲しいだけです.bootloader
。
これが単純に不可能な場合は、ブートローダ全体をアセンブリに書き込むか (面白くない)、ブートローダを個別にコンパイルして、かなり長い 16 進数の文字列としてエンド プログラムに含めて実行します。 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
通常、最適化は になりますが-Os
、私はそれを取り除こうとしていましたmemcpy
... うまくいきませんでした。
また、私はこの質問を見てきましたが、問題は解決しませんでした。