Cortex M3 .bss領域の初期化用のベアメタルスタートアップコード


10

ここから着想を得て、腕皮質M3のベアメタルスタートアップコードを開発しました。ただし、次の問題が発生します。main.cでunsigned char型など、初期化されていないグローバル変数を宣言するとします。

#include ...
unsigned char var; 
...
int main()
{
 ...
}

これにより、STM32 f103の.bss領域は、_BSS_START = 0x20000000で始まり、_BSS_END = 0x20000001で終わります。さて、スタートアップコード

    unsigned int * bss_start_p = &_BSS_START; 
    unsigned int * bss_end_p = &_BSS_END;

    while(bss_start_p != bss_end_p)
    {
        *bss_start_p = 0;
        bss_start_p++;
    }

.bss領域全体をゼロに初期化しようとします。ただし、そのwhileループ内では、ポインターは4バイトで増加します。したがって、1ステップ後にbss_start_p = 0x20000004なので、無限ループなどにつながるbss_end_pとは常に異なります。

これに対する標準的な解決策はありますか?どういうわけか、.bss領域の次元を4の倍数に「強制」すると思いますか?または、unsigned charへのポインターを使用して.bss領域をウォークスルーする必要がありますか?おそらく次のようなものです:

    unsigned char * bss_start_p = (unsigned char *)(&_BSS_START); 
    unsigned char * bss_end_p = (unsigned char *)(&_BSS_END);

    while(bss_start_p != bss_end_p)
    {
        *bss_start_p = 0;
        bss_start_p++;
    }
```

より少ない使用。ブートストラップは、何らかの理由でアセンブリで記述されています。まず、.dataの問題が発生しました。Cが最低でも.text、.bss、および.dataに依存して動作することを前提としていますが、Cコードが機能することを確認するCコードを記述しており、 Cの動作に依存するCコードで記述されたブートストラップ。
old_timer

.dataをコピーするコードは.bssに非常に似ていますが、上記のコードのように記述する場合、.dataをコピーするために.dataをコピーする必要があります。
old_timer

回答:


15

ご想像のとおり、これはunsigned intデータ型のサイズが4バイトであるために発生しています。各*bss_start_p = 0;ステートメントは実際にbss領域の4バイトをクリアします。

bssのメモリ範囲を正しく調整する必要があります。_BSS_STARTと_BSS_ENDを定義して合計サイズを4の倍数にすることもできますが、これは通常、リンカースクリプトで開始位置と停止位置を定義できるようにすることで処理されます。

例として、私のプロジェクトの1つにあるリンカーセクションを次に示します。

.bss (NOLOAD) : ALIGN(4)
{
    __bss_start__ = .;
    *(.bss)
    . = ALIGN(4);
    __bss_end__ = .;
} >RAM

ALIGN(4)文は、物事の世話をします。

また、変更することもできます

while(bss_start_p != bss_end_p)

while(bss_start_p < bss_end_p)

これは問題を防ぐことはできませんが(必要以上に1〜3バイトをクリアしている可能性があるため)、影響を最小限に抑えることができます。


@CMarius反映すると、より多くのサイクルが必要になりますが、charポインターのアイデアはうまく機能すると思います。しかし、次のメモリ領域が整列していないという問題が発生するかどうかは
わかり

1
while(bss_start_p < bss_end_p - 1)その後、残りのメモリ範囲をバイト単位でクリアすると、最後の問題が解消されます。
glglgl

4

標準ソリューションはmemset()次のとおりです。

#include <string.h>
memset(&_BSS_START, 0, &_BSS_END - &_BSS_START)

標準ライブラリを使用できない場合は、メモリ領域のサイズを4バイトに丸めて、引き続き使用しても大丈夫かどうかを判断する必要がありますunsigned int *。または、厳密にする必要がある場合は、を使用する必要がありますunsigned char *

最初のループのようにサイズを切り上げると、bss_start_p実際にはそれよりも大きくなる可能性がありますが、不等式テストの代わりに「bss_end_pより小」の比較を処理するのは簡単<です。

もちろん、メモリ領域の大部分を32ビット転送で埋め、最後の数バイトを8ビット転送で埋めることもできますが、特にスタートアップコードの一部である場合は、ほとんど効果がありません。


1
の使用に非常に同意しますmemset()。しかし、4バイトへのアライメントは多かれ少なかれ必須です。それで、なぜそれをしないのですか?
Codo

3
形や形がブートストラップのmemsetを使用するための標準的なソリューションではありません。
old_timer

同じ言語を使用してその言語をブートストラップしない
old_timer

2
ブートストラップコードとリンカースクリプトは非常によく似ています。リンカースクリプトが少なくとも4バイトの境界で.bssを整列およびサイズ設定して、(ブートストラップでの)フィルをバイト単位で4倍ずつ向上させることが一般的です。 (32ビットバスを想定(最小)はアームに一般的ですが、例外があります)
old_timer

3
@old_timer、メモリを特定の値に設定する標準のC関数はmemset()であり、Cはそれらがプログラミングしているように見えます。の単純な実装memset()もループにすぎず、他の多くに依存しているわけではありません。それはマイクロコントローラーなので、動的リンクなどが発生していないことも想定しています(そしてリンクを見ると、リンクはありません。main()ゼロループの後の呼び出しにすぎません)。コンパイラーはmemset()そこにドロップできるはずです。その他の関数と共に(またはインラインで実装するため)。
ilkkachu


3

他にも無数のサイトや例があります。数万とは言わないまでも数千。リンカースクリプトとブーストラップコードを備えたよく知られたCライブラリ、特にnewlib、glibcがありますが、他にも見つけることができます。CでCをブートストラップしても意味がありません。

正確でない可能性のあるものを正確に比較しようとしている、既知の境界で開始されていない、または既知の境界で終了していない可能性があるという質問に回答しました。したがって、より少ないことを行うことができますが、コードが正確な比較で機能しなかった場合は、.bssを過ぎて次のセクションにゼロ設定されているため、問題が発生する場合と発生しない場合があります。ソリューション。

TLはここにあり、DRは問題ありません。あなたはその言語で言語をブートストラップしないでください、あなたはそれを確実に逃れることができます、しかしあなたがそれをするときあなたは火で遊んでいます。あなたがこれを行う方法を学んでいるだけの場合、あなたは注意を怠る必要があります。運やまだ明らかにしていない事実を馬鹿にしないでください。

リンカスクリプトとブートストラップコードは非常に親密な関係にあり、それらは結婚していて、ヒップで結合されています。大規模な障害につながる他の1つなしで1つを開発することはできません。残念ながら、リンカースクリプトはリンカーによって定義され、アセンブリー言語はアセンブラーによって定義されているため、ツールチェーンを変更すると、両方を書き直す必要があると予想されます。なぜアセンブリ言語なのか?ブートストラップは必要ありませんが、コンパイルされた言語は一般的に必要です。Cは、言語の使用を制限したくない場合は、最小限のツールチェーン固有の要件を持つ非常にシンプルなものから始めます。.bss変数がゼロであると想定しないでください(変数がその言語で初期化されない場合、コードが読みにくくなります) 、これを回避しようとしますが、ローカル変数には当てはまりません。そのため、それを使用するときはボールに乗っている必要があります。では、なぜ.bssと.dataについて話しているのですか?(グローバルはこのレベルの作業には適していますが、これは別のトピックです))簡単な解決策のもう1つのルールは、宣言で変数を初期化しないで、コードで初期化することです。はい、より多くのフラッシュを燃やします。一般的には十分ですが、すべての変数が定数で初期化されるわけではなく、結果として命令を消費することになります。

cortex-mの設計から、ブートストラップコードはまったくないため、.dataも.bssもサポートされていないと考えていたことがわかります。グローバルを使用するほとんどの人々は、これがないと生きていけません。

gnuツールチェーンを使用して、すべてのcortex-msのこれをより最小限に抑えた機能的な例にすることができます。現在の9.xxからどのバージョンを始めればよいか覚えていません。私がより多くを学び、gnuが私の最初のものを壊した何かを変更したとき、xxまたは4.xx。

ブートストラップ:

.thumb

.thumb_func
.global _start
_start:
stacktop: .word 0x20000800
.word reset
.word done
.word done
.word done

.thumb_func
reset:
    bl centry
    b done

.thumb_func
done:   b .

.thumb_func
.globl bounce
bounce:
    bx lr

Cコードへのエントリポイント:

void bounce ( unsigned int );

unsigned int a;

int centry ( void )
{
    a = 7;
    bounce(a);
    return(0);
}

リンカースクリプト。

MEMORY
{
    rom : ORIGIN = 0x00000000, LENGTH = 0x1000
    ram : ORIGIN = 0x20000000, LENGTH = 0x1000
}

SECTIONS
{
    .text : { *(.text*) } > rom
    .rodata : { *(.rodata*) } > rom
    .bss : { *(.bss*) } > ram
}

これらはすべて小さくても機能する可能性があり、実際に動作することを確認するために、ここにいくつか追加の要素を追加しました。

最適化されたビルドとリンク。

00000000 <_start>:
   0:   20001000
   4:   00000015
   8:   0000001b
   c:   0000001b
  10:   0000001b

00000014 <reset>:
  14:   f000 f804   bl  20 <centry>
  18:   e7ff        b.n 1a <done>

0000001a <done>:
  1a:   e7fe        b.n 1a <done>

0000001c <bounce>:
  1c:   4770        bx  lr
    ...

00000020 <centry>:
  20:   2207        movs    r2, #7
  22:   b510        push    {r4, lr}
  24:   4b04        ldr r3, [pc, #16]   ; (38 <centry+0x18>)
  26:   2007        movs    r0, #7
  28:   601a        str r2, [r3, #0]
  2a:   f7ff fff7   bl  1c <bounce>
  2e:   2000        movs    r0, #0
  30:   bc10        pop {r4}
  32:   bc02        pop {r1}
  34:   4708        bx  r1
  36:   46c0        nop         ; (mov r8, r8)
  38:   20000000    andcs   r0, r0, r0

Disassembly of section .bss:

20000000 <a>:
20000000:   00000000    andeq   r0, r0, r0

一部のベンダーでは、フラッシュがそこにマップされ、一部のブートモードで0x00000000にミラーリングされるため、0x08000000または0x01000000または他の同様のアドレスを使用する必要があります。フラッシュの多くが0x00000000でミラーリングされているものもあるので、ベクターテーブルがゼロではなくアプリケーションのフラッシュスペースを指すようにする必要があります。ベクターテーブルベースであるため、すべて機能します。

最初に、cortex-msは親指専用のマシンであり、何らかの理由で親指機能アドレスを適用したことに注意してください。これは、lsbitが奇数であることを意味します。ツールを知って、.thumb_funcディレクティブは、次のラベルがつまみ関数のアドレスであることをgnuアセンブラーに伝えます。テーブルで+1を実行すると失敗します。実行しようとしないで、正しく実行してください。関数を宣言する他のgnuアセンブラーの方法があります。これは最小のアプローチです。

   4:   00000015
   8:   0000001b
   c:   0000001b
  10:   0000001b

ベクトルテーブルが正しくない場合は起動しません。

おそらく、スタックポインターベクトル(自分でコードにスタックポインターを設定したい場合は、そこに何かを置くことができます)とリセットベクトルのみが必要です。特に理由はありませんが、ここに4つ入れました。通常は16を入れますが、この例を短くしたいと思いました。

では、Cブートストラップが行う必要のある最小限のことは何でしょうか。1.スタックポインターを設定する2.ゼロ.bss 3. .dataをコピーする4. Cエントリポイントに分岐するか呼び出す

Cエントリポイントは通常main()と呼ばれます。しかし、一部のツールチェーンはmain()を参照し、コードに余分なゴミを追加します。意図的に別の名前を使用しています。YMMV。

これがすべてRAMベースの場合、.dataのコピーは必要ありません。cortex-mマイクロコントローラーであることは技術的には可能ですが、そうではないため、.dataコピーが必要です。

私の最初の例とコーディングスタイルは、この例のように、.dataや.bssに依存しないことです。Armがスタックポインタを処理するため、残っているのはエントリポイントを呼び出すことだけです。私はそれがエントリーポイントが戻ることができるように持っているのが好きです、多くの人々はあなたがそれをするべきではないと主張します。次に、これを行うことができます:

.thumb_func
.global _start
_start:
stacktop: .word 0x20000800
.word centry
.word done
.word done
.word done

centry()から返されず、リセットハンドラコードもありません。

00000020 <centry>:
  20:   2207        movs    r2, #7
  22:   b510        push    {r4, lr}
  24:   4b04        ldr r3, [pc, #16]   ; (38 <centry+0x18>)
  26:   2007        movs    r0, #7
  28:   601a        str r2, [r3, #0]
  2a:   f7ff fff7   bl  1c <bounce>
  2e:   2000        movs    r0, #0
  30:   bc10        pop {r4}
  32:   bc02        pop {r1}
  34:   4708        bx  r1
  36:   46c0        nop         ; (mov r8, r8)
  38:   20000000    andcs   r0, r0, r0

Disassembly of section .bss:

20000000 <a>:
20000000:   00000000

リンカは私たちが尋ねたところに物事を置きました。そして全体として、完全に機能するプログラムがあります。

したがって、最初にリンカースクリプトを作成します。

MEMORY
{
    bob : ORIGIN = 0x00000000, LENGTH = 0x1000
    ted : ORIGIN = 0x20000000, LENGTH = 0x1000
}

SECTIONS
{
    .text : { *(.text*) } > bob

    .rodata : { *(.rodata*) } > bob

   __data_rom_start__ = .;
   .data : {
    __data_start__ = .;
    *(.data*)
   } > ted AT > bob
   __data_end__ = .;
   __data_size__ = __data_end__ - __data_start__;

   .bss  : {
   __bss_start__ = .;
   *(.bss*)
   } > ted
   __bss_end__ = .;
   __bss_size__ = __bss_end__ - __bss_start__;

}

romとramの名前には意味がないことを強調し、セクション間のリンカのドットを接続するだけです。

.thumb

.thumb_func
.global _start
_start:
stacktop: .word 0x20000800
.word reset
.word done
.word done
.word done

.thumb_func
reset:
    bl centry
    b done

.thumb_func
done:   b .

.thumb_func
.globl bounce
bounce:
    bx lr

.align
.word __data_rom_start__
.word __data_start__
.word __data_end__
.word __data_size__

ツールが何をしたかを確認できるように、いくつかの項目を追加します

void bounce ( unsigned int );

unsigned int a;

unsigned int b=4;
unsigned char c=5;

int centry ( void )
{
    a = 7;
    bounce(a);
    return(0);
}

これらのセクションに配置するアイテムを追加します。そして得る

Disassembly of section .text:

00000000 <_start>:
   0:   20000800    andcs   r0, r0, r0, lsl #16
   4:   00000015    andeq   r0, r0, r5, lsl r0
   8:   0000001b    andeq   r0, r0, r11, lsl r0
   c:   0000001b    andeq   r0, r0, r11, lsl r0
  10:   0000001b    andeq   r0, r0, r11, lsl r0

00000014 <reset>:
  14:   f000 f80c   bl  30 <centry>
  18:   e7ff        b.n 1a <done>

0000001a <done>:
  1a:   e7fe        b.n 1a <done>

0000001c <bounce>:
  1c:   4770        bx  lr
  1e:   46c0        nop         ; (mov r8, r8)
  20:   0000004c    andeq   r0, r0, r12, asr #32
  24:   20000000    andcs   r0, r0, r0
  28:   20000008    andcs   r0, r0, r8
  2c:   00000008    andeq   r0, r0, r8

00000030 <centry>:
  30:   2207        movs    r2, #7
  32:   b510        push    {r4, lr}
  34:   4b04        ldr r3, [pc, #16]   ; (48 <centry+0x18>)
  36:   2007        movs    r0, #7
  38:   601a        str r2, [r3, #0]
  3a:   f7ff ffef   bl  1c <bounce>
  3e:   2000        movs    r0, #0
  40:   bc10        pop {r4}
  42:   bc02        pop {r1}
  44:   4708        bx  r1
  46:   46c0        nop         ; (mov r8, r8)
  48:   20000008    andcs   r0, r0, r8

Disassembly of section .data:

20000000 <c>:
20000000:   00000005    andeq   r0, r0, r5

20000004 <b>:
20000004:   00000004    andeq   r0, r0, r4

Disassembly of section .bss:

20000008 <a>:
20000008:   00000000    andeq   r0, r0, r0

ここで私たちはその実験で探しているものです(実際にコードをロードしたり実行したりする理由はありません...あなたのツールを知って、それらを学んでください)

  1c:   4770        bx  lr
  1e:   46c0        nop         ; (mov r8, r8)
  20:   0000004c    andeq   r0, r0, r12, asr #32
  24:   20000000    andcs   r0, r0, r0
  28:   20000008    andcs   r0, r0, r8
  2c:   00000008    andeq   r0, r0, r8

ここで学んだことは、変数の位置はgnuリンカースクリプトでは非常に敏感であることです。位置に注意data_rom_startdata_startをしかし、なぜDATA_ENDの仕事は?それを理解させましょう。リンカスクリプトをいじって単純なプログラミングに取りたくない理由をすでに理解している...

したがって、ここで学んだもう1つのことは、リンカーが配置したdata_rom_startをALIGN(4)にする必要がなかったことです。私たちはそれが常にうまくいくと思いますか?

途中でパディングされたことにも注意してください。5バイトの.dataがありますが、8にパディングされています。ALIGN()がなければ、単語を使用してコピーを実行できます。今日の私のコンピューター上のこのツールチェーンで見たものに基づくと、それは過去と未来に当てはまるのでしょうか?ALIGNが定期的にチェックして、新しいバージョンで問題が発生しなかったことを確認する必要がある場合でも、時々それを実行することは誰にもわかりません。

その実験から、安全のためにこれに移りましょう。

MEMORY
{
    bob : ORIGIN = 0x00000000, LENGTH = 0x1000
    ted : ORIGIN = 0x20000000, LENGTH = 0x1000
}

SECTIONS
{
    .text : { *(.text*) } > bob

    .rodata : { *(.rodata*) } > bob

   . = ALIGN(4);
   __data_rom_start__ = .;
   .data : {
    __data_start__ = .;
    *(.data*)
   . = ALIGN(4);
   __data_end__ = .;
   } > ted AT > bob
   __data_size__ = __data_end__ - __data_start__;

   . = ALIGN(4);
   .bss  : {
   __bss_start__ = .;
   *(.bss*)
   . = ALIGN(4);
   __bss_end__ = .;
   } > ted
   __bss_size__ = __bss_end__ - __bss_start__;

}

端を内側に移動して、他の人が行うことと一致させます。そしてそれはそれを変えませんでした:

0000001c <bounce>:
  1c:   4770        bx  lr
  1e:   46c0        nop         ; (mov r8, r8)
  20:   0000004c    andeq   r0, r0, r12, asr #32
  24:   20000000    andcs   r0, r0, r0
  28:   20000008    andcs   r0, r0, r8
  2c:   00000008    andeq   r0, r0, r8

もう1つの簡単なテスト:

.globl bounce
bounce:
    nop
    bx lr

与える

0000001c <bounce>:
  1c:   46c0        nop         ; (mov r8, r8)
  1e:   4770        bx  lr
  20:   0000004c    andeq   r0, r0, r12, asr #32
  24:   20000000    andcs   r0, r0, r0
  28:   20000008    andcs   r0, r0, r8
  2c:   00000008    andeq   r0, r0, r8

バウンスと.alignの間を埋める必要はありません

ああ、そうですね、_end__を中に入れない理由を今覚えています。それは機能しないので。

MEMORY
{
    bob : ORIGIN = 0x00000000, LENGTH = 0x1000
    ted : ORIGIN = 0x20000000, LENGTH = 0x1000
}

SECTIONS
{
    .text : { *(.text*) } > bob

    .rodata : { *(.rodata*) } > bob

   . = ALIGN(4);
   __data_rom_start__ = .;
   .data : {
    __data_start__ = .;
    *(.data*)
   } > ted AT > bob
   . = ALIGN(4);
   __data_end__ = .;
   __data_size__ = __data_end__ - __data_start__;

   . = ALIGN(4);
   .bss  : {
   __bss_start__ = .;
   *(.bss*)
   } > ted
   . = ALIGN(4);
   __bss_end__ = .;
   __bss_size__ = __bss_end__ - __bss_start__;

}

このリンカスクリプトと連携するいくつかの単純ですが非常に移植可能なコード

.thumb

.thumb_func
.global _start
_start:
stacktop: .word 0x20000800
.word reset
.word done
.word done
.word done

.thumb_func
reset:

    ldr r0,blen
    cmp r0,#0
    beq bss_zero_done
    ldr r1,bstart
    mov r2,#0
bss_zero:
    stmia r1!,{r2}
    sub r0,#4
    bne bss_zero
bss_zero_done:

    ldr r0,dlen
    cmp r0,#0
    beq data_copy_done
    ldr r1,rstart
    ldr r2,dstart
data_copy:
    ldmia r1!,{r3}
    stmia r2!,{r3}
    sub r0,#4
    bne data_copy
data_copy_done:

    bl centry
    b done

.thumb_func
done:   b .

.thumb_func
.globl bounce
bounce:
    nop
    bx lr

.align
bstart: .word __bss_start__
blen:   .word __bss_size__
rstart: .word __data_rom_start__
dstart: .word __data_start__
dlen:   .word __data_size__

与える

Disassembly of section .text:

00000000 <_start>:
   0:   20000800    andcs   r0, r0, r0, lsl #16
   4:   00000015    andeq   r0, r0, r5, lsl r0
   8:   0000003d    andeq   r0, r0, sp, lsr r0
   c:   0000003d    andeq   r0, r0, sp, lsr r0
  10:   0000003d    andeq   r0, r0, sp, lsr r0

00000014 <reset>:
  14:   480c        ldr r0, [pc, #48]   ; (48 <blen>)
  16:   2800        cmp r0, #0
  18:   d004        beq.n   24 <bss_zero_done>
  1a:   490a        ldr r1, [pc, #40]   ; (44 <bstart>)
  1c:   2200        movs    r2, #0

0000001e <bss_zero>:
  1e:   c104        stmia   r1!, {r2}
  20:   3804        subs    r0, #4
  22:   d1fc        bne.n   1e <bss_zero>

00000024 <bss_zero_done>:
  24:   480b        ldr r0, [pc, #44]   ; (54 <dlen>)
  26:   2800        cmp r0, #0
  28:   d005        beq.n   36 <data_copy_done>
  2a:   4908        ldr r1, [pc, #32]   ; (4c <rstart>)
  2c:   4a08        ldr r2, [pc, #32]   ; (50 <dstart>)

0000002e <data_copy>:
  2e:   c908        ldmia   r1!, {r3}
  30:   c208        stmia   r2!, {r3}
  32:   3804        subs    r0, #4
  34:   d1fb        bne.n   2e <data_copy>

00000036 <data_copy_done>:
  36:   f000 f80f   bl  58 <centry>
  3a:   e7ff        b.n 3c <done>

0000003c <done>:
  3c:   e7fe        b.n 3c <done>

0000003e <bounce>:
  3e:   46c0        nop         ; (mov r8, r8)
  40:   4770        bx  lr
  42:   46c0        nop         ; (mov r8, r8)

00000044 <bstart>:
  44:   20000008    andcs   r0, r0, r8

00000048 <blen>:
  48:   00000004    andeq   r0, r0, r4

0000004c <rstart>:
  4c:   00000074    andeq   r0, r0, r4, ror r0

00000050 <dstart>:
  50:   20000000    andcs   r0, r0, r0

00000054 <dlen>:
  54:   00000008    andeq   r0, r0, r8

00000058 <centry>:
  58:   2207        movs    r2, #7
  5a:   b510        push    {r4, lr}
  5c:   4b04        ldr r3, [pc, #16]   ; (70 <centry+0x18>)
  5e:   2007        movs    r0, #7
  60:   601a        str r2, [r3, #0]
  62:   f7ff ffec   bl  3e <bounce>
  66:   2000        movs    r0, #0
  68:   bc10        pop {r4}
  6a:   bc02        pop {r1}
  6c:   4708        bx  r1
  6e:   46c0        nop         ; (mov r8, r8)
  70:   20000008    andcs   r0, r0, r8

Disassembly of section .data:

20000000 <c>:
20000000:   00000005    andeq   r0, r0, r5

20000004 <b>:
20000004:   00000004    andeq   r0, r0, r4

Disassembly of section .bss:

20000008 <a>:
20000008:   00000000    andeq   r0, r0, r0

私たちはそこで停止するか、続行します。リンカスクリプトと同じ順序で初期化する場合は、まだ行っていないため、次の手順に進んでもかまいません。とstm / ldmはワードアラインされたアドレスを使用するためにのみ必要/望ましいので、次のように変更した場合:

    ldr r0,blen
    cmp r0,#0
    beq bss_zero_done
    ldr r1,bstart
    mov r2,#0
    mov r3,#0
    mov r4,#0
    mov r5,#0
bss_zero:
    stmia r1!,{r2,r3,r4,r5}
    sub r0,#16
    ble bss_zero
bss_zero_done:

リンカスクリプトの最初にbssを使用し、はい、blsではなくbleを使用します。

Disassembly of section .text:

00000000 <_start>:
   0:   20000800    andcs   r0, r0, r0, lsl #16
   4:   00000015    andeq   r0, r0, r5, lsl r0
   8:   00000043    andeq   r0, r0, r3, asr #32
   c:   00000043    andeq   r0, r0, r3, asr #32
  10:   00000043    andeq   r0, r0, r3, asr #32

00000014 <reset>:
  14:   480d        ldr r0, [pc, #52]   ; (4c <blen>)
  16:   2800        cmp r0, #0
  18:   d007        beq.n   2a <bss_zero_done>
  1a:   490b        ldr r1, [pc, #44]   ; (48 <bstart>)
  1c:   2200        movs    r2, #0
  1e:   2300        movs    r3, #0
  20:   2400        movs    r4, #0
  22:   2500        movs    r5, #0

00000024 <bss_zero>:
  24:   c13c        stmia   r1!, {r2, r3, r4, r5}
  26:   3804        subs    r0, #4
  28:   ddfc        ble.n   24 <bss_zero>

0000002a <bss_zero_done>:
  2a:   480b        ldr r0, [pc, #44]   ; (58 <dlen>)
  2c:   2800        cmp r0, #0
  2e:   d005        beq.n   3c <data_copy_done>
  30:   4907        ldr r1, [pc, #28]   ; (50 <rstart>)
  32:   4a08        ldr r2, [pc, #32]   ; (54 <dstart>)

00000034 <data_copy>:
  34:   c978        ldmia   r1!, {r3, r4, r5, r6}
  36:   c278        stmia   r2!, {r3, r4, r5, r6}
  38:   3810        subs    r0, #16
  3a:   ddfb        ble.n   34 <data_copy>

0000003c <data_copy_done>:
  3c:   f000 f80e   bl  5c <centry>
  40:   e7ff        b.n 42 <done>

00000042 <done>:
  42:   e7fe        b.n 42 <done>

00000044 <bounce>:
  44:   46c0        nop         ; (mov r8, r8)
  46:   4770        bx  lr

00000048 <bstart>:
  48:   20000000    andcs   r0, r0, r0

0000004c <blen>:
  4c:   00000004    andeq   r0, r0, r4

00000050 <rstart>:
  50:   20000004    andcs   r0, r0, r4

00000054 <dstart>:
  54:   20000004    andcs   r0, r0, r4

00000058 <dlen>:
  58:   00000008    andeq   r0, r0, r8

0000005c <centry>:
  5c:   2207        movs    r2, #7
  5e:   b510        push    {r4, lr}
  60:   4b04        ldr r3, [pc, #16]   ; (74 <centry+0x18>)
  62:   2007        movs    r0, #7
  64:   601a        str r2, [r3, #0]
  66:   f7ff ffed   bl  44 <bounce>
  6a:   2000        movs    r0, #0
  6c:   bc10        pop {r4}
  6e:   bc02        pop {r1}
  70:   4708        bx  r1
  72:   46c0        nop         ; (mov r8, r8)
  74:   20000000    andcs   r0, r0, r0

Disassembly of section .bss:

20000000 <a>:
20000000:   00000000    andeq   r0, r0, r0

Disassembly of section .data:

20000004 <c>:
20000004:   00000005    andeq   r0, r0, r5

20000008 <b>:
20000008:   00000004    andeq   r0, r0, r4

これらのループはより高速になります。現在、私はahbバスが64ビット幅であるかどうかわからないが、フルサイズのアームの場合、これらのものを64ビット境界に揃えたいと思う。64ビット境界ではなく32ビット境界の4つのレジスタldm / stmは、3つの独立したバストランザクションになります。64ビット境界で整列すると、1つのトランザクションで1命令あたり数クロックを節約できます。

私たちはベアメタルをやっていて、私たちが置くことができるすべてのものに対して完全に責任があるので、最初にbss、次にデータ、次にヒープがある場合はスタックが上から下に成長するので、bssをゼロにして、私たちはまだそのメモリを使用していません。次に、.dataをコピーして、ヒープ、ヒープ、またはスタックのための十分な余地がない場合に流出する可能性があるため、誰も/何も踏んでいない(リンカースクリプトで確認している限り)。懸念がある場合は、ALIGN()を大きくして、これらの塗りつぶしのために常にスペース内に収まるようにします。

だから私の簡単な解決策は、それを取るか、そのままにするかです。バグの修正を歓迎します。ハードウェアでもシミュレータでも実行しませんでした...

MEMORY
{
    bob : ORIGIN = 0x00000000, LENGTH = 0x1000
    ted : ORIGIN = 0x20000000, LENGTH = 0x1000
}

SECTIONS
{
    .text : { *(.text*) } > bob

    .rodata : { *(.rodata*) } > bob

   . = ALIGN(8);
   .bss  : {
   __bss_start__ = .;
   *(.bss*)
   } > ted
   . = ALIGN(4);
   __bss_end__ = .;
   __bss_size__ = __bss_end__ - __bss_start__;

   . = ALIGN(8);
   __data_rom_start__ = .;
   .data : {
    __data_start__ = .;
    *(.data*)
   } > ted AT > bob
   . = ALIGN(4);
   __data_end__ = .;
   __data_size__ = __data_end__ - __data_start__;

}



.thumb

.thumb_func
.global _start
_start:
stacktop: .word 0x20000800
.word reset
.word done
.word done
.word done

.thumb_func
reset:

    ldr r0,blen
    cmp r0,#0
    beq bss_zero_done
    ldr r1,bstart
    mov r2,#0
    mov r3,#0
    mov r4,#0
    mov r5,#0
bss_zero:
    stmia r1!,{r2,r3,r4,r5}
    sub r0,#16
    ble bss_zero
bss_zero_done:

    ldr r0,dlen
    cmp r0,#0
    beq data_copy_done
    ldr r1,rstart
    ldr r2,dstart
data_copy:
    ldmia r1!,{r3,r4,r5,r6}
    stmia r2!,{r3,r4,r5,r6}
    sub r0,#16
    ble data_copy
data_copy_done:

    bl centry
    b done

.thumb_func
done:   b .

.thumb_func
.globl bounce
bounce:
    nop
    bx lr

.align
bstart: .word __bss_start__
blen:   .word __bss_size__
rstart: .word __data_rom_start__
dstart: .word __data_start__
dlen:   .word __data_size__


void bounce ( unsigned int );

unsigned int a;

unsigned int b=4;
unsigned char c=5;

int centry ( void )
{
    a = 7;
    bounce(a);
    return(0);
}

arm-none-eabi-as --warn --fatal-warnings flash.s -o flash.o
arm-none-eabi-ld -o hello.elf -T flash.ld flash.o centry.o
arm-none-eabi-objdump -D hello.elf > hello.list
arm-none-eabi-objcopy hello.elf hello.bin -O binary

すべてをまとめると、次のようになります。

Disassembly of section .text:

00000000 <_start>:
   0:   20000800    andcs   r0, r0, r0, lsl #16
   4:   00000015    andeq   r0, r0, r5, lsl r0
   8:   00000043    andeq   r0, r0, r3, asr #32
   c:   00000043    andeq   r0, r0, r3, asr #32
  10:   00000043    andeq   r0, r0, r3, asr #32

00000014 <reset>:
  14:   480d        ldr r0, [pc, #52]   ; (4c <blen>)
  16:   2800        cmp r0, #0
  18:   d007        beq.n   2a <bss_zero_done>
  1a:   490b        ldr r1, [pc, #44]   ; (48 <bstart>)
  1c:   2200        movs    r2, #0
  1e:   2300        movs    r3, #0
  20:   2400        movs    r4, #0
  22:   2500        movs    r5, #0

00000024 <bss_zero>:
  24:   c13c        stmia   r1!, {r2, r3, r4, r5}
  26:   3810        subs    r0, #16
  28:   ddfc        ble.n   24 <bss_zero>

0000002a <bss_zero_done>:
  2a:   480b        ldr r0, [pc, #44]   ; (58 <dlen>)
  2c:   2800        cmp r0, #0
  2e:   d005        beq.n   3c <data_copy_done>
  30:   4907        ldr r1, [pc, #28]   ; (50 <rstart>)
  32:   4a08        ldr r2, [pc, #32]   ; (54 <dstart>)

00000034 <data_copy>:
  34:   c978        ldmia   r1!, {r3, r4, r5, r6}
  36:   c278        stmia   r2!, {r3, r4, r5, r6}
  38:   3810        subs    r0, #16
  3a:   ddfb        ble.n   34 <data_copy>

0000003c <data_copy_done>:
  3c:   f000 f80e   bl  5c <centry>
  40:   e7ff        b.n 42 <done>

00000042 <done>:
  42:   e7fe        b.n 42 <done>

00000044 <bounce>:
  44:   46c0        nop         ; (mov r8, r8)
  46:   4770        bx  lr

00000048 <bstart>:
  48:   20000000    andcs   r0, r0, r0

0000004c <blen>:
  4c:   00000004    andeq   r0, r0, r4

00000050 <rstart>:
  50:   20000008    andcs   r0, r0, r8

00000054 <dstart>:
  54:   20000004    andcs   r0, r0, r4

00000058 <dlen>:
  58:   00000008    andeq   r0, r0, r8

0000005c <centry>:
  5c:   2207        movs    r2, #7
  5e:   b510        push    {r4, lr}
  60:   4b04        ldr r3, [pc, #16]   ; (74 <centry+0x18>)
  62:   2007        movs    r0, #7
  64:   601a        str r2, [r3, #0]
  66:   f7ff ffed   bl  44 <bounce>
  6a:   2000        movs    r0, #0
  6c:   bc10        pop {r4}
  6e:   bc02        pop {r1}
  70:   4708        bx  r1
  72:   46c0        nop         ; (mov r8, r8)
  74:   20000000    andcs   r0, r0, r0

Disassembly of section .bss:

20000000 <a>:
20000000:   00000000    andeq   r0, r0, r0

Disassembly of section .data:

20000004 <c>:
20000004:   00000005    andeq   r0, r0, r5

20000008 <b>:
20000008:   00000004    andeq   r0, r0, r4

これは、ghee whizが使用されなかったため、arm-none-eabi-およびarm-linux-gnueabiと他のバリアントで動作することに注意してください。

あなたが周りを見回すと、人々は彼らのリンカースクリプトのギーウィズのもの、巨大な巨大なキッチンシンクのものに夢中になるでしょう。他の人のものに頼るのではなく、それを行う方法(またはツールを習得して、何が起こっているかを制御できる方法)を理解し、理解していない、または調査したいためにどこで壊れるのかを知らない方が良いそれ。

原則として、同じ言語の言語をブートストラップしないでください(この意味でのブートストラップは、実行中のコードが同じコンパイラーでコンパイラーをコンパイルしないことを意味します)、ブートストラップの少ない単純な言語を使用します。そのため、Cはアセンブリで実行され、リセット後に最初の命令から開始するだけのブートストラップ要件はありません。JAVA、Cでjvmを作成し、そのCをasmでブートストラップし、Cで実行する場合はJAVAをブートストラップして、JavaをCでも実行することを確認してください。

これらのコピーループの仮定を制御しているため、手動で調整したmemcpy / memsetよりも定義が厳密でクリーンです。

他の問題はこれでした:

unsigned int * bss_start_p = &_BSS_START; 
unsigned int * bss_end_p = &_BSS_END;

これらがローカルで問題ない場合、問題ありません。これらがグローバルである場合、最初に.dataを初期化してから機能させる必要があります。そのトリックを.dataにしようとすると、失敗します。ローカル変数、うまくいくでしょう。何らかの理由で静的ローカル(私が呼び出したいローカルグローバル)を作成することにした場合は、再び問題が発生します。あなたはそれについて考える必要がありますが、宣言で割り当てを行うたびに、それはどのように実装され、安全ですか?宣言されていないときに変数がゼロであると想定するたびに、同じことですが、ローカル変数がゼロであると想定されていない場合、グローバルの場合はゼロです。それらがゼロであると決して想定しない場合は、心配する必要はありません。


すごい、これが私が回答の最大文字数を超えたのは2回目です...
old_timer

この質問は、電気工学ではなくスタックオーバーフローに属しています。
old_timer

また、質問の外部リンクに依存することは適切な形式ではありません。リンクが質問の前に消えてしまう場合、質問は意味をなさない可能性があります。
old_timer

この場合、タイトルとコンテンツは、特定のマイクロコントローラーでCをブートストラップしようとし、.bssと.dataの初期化にさまようしていることを知るのに十分です
old_timer

しかし、この場合、他の点では非常に有益なWebサイトによって誤解を招きました。
old_timer
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.