GNURL78でconst領域/Mirror領域をちょっと安全に使えるようにlinker scriptのASSERT()で小技(TIPS)を考えてみた

こんにちは。NoMaYです。#3連投の1つ目です。

先日、以下のスレッドにて、GNURL78のconst領域/Mirror領域のリンカでの取り扱いがあまり安心出来るようなものでは無かったことを知りました。そこで、この領域を幾らかでも安心して使えるようにならないものかと試行錯誤してみたところ、リンカスクリプトでASSERT()を利用してconst領域とMirror領域の関係が適切かどうかチェック出来ることが分かりました。そこで、RL78/G14のプロジェクトを作成し、ファイル一式を以下に固めました。(e2 studio v7.5.0+GNURL78 2019q2(4.9.2.201902)でビルド)(zipファイルをe2 studioに直接インポート可能)

gnurl78_linker_script_improvement_20190823.zip    193KB
含まれるプロジェクト
・large_const_small_text (.textセクションが.rodataセクションの下側(0番地側))
・large_const_large_text (.textセクションが.rodataセクションの上側(0xFFFFF番地側))
(以前の投稿のRL78 FreeRTOSのプロジェクト 1, 2 から派生させたのでちょっと独特なものですが、リンカスクリプトに関しては今回の変更箇所以外はe2 studioで生成した標準的なものです。)

「e2studio + GCC for Renesas RL78」ROMサイズが少し大きくなるといろいろ出る不具合【 near領域のROMサイズに注意しましょう】
japan.renesasrulz.com/cafe_rene/f/forum21/5899/e2studio-gcc-for-renesas-rl78-rom-near-rom

今回、const領域とMirror領域の関係が適切かどうかチェックして、問題があれば以下のエラーメッセージを表示させるようにしてみました。

Error: Too much const data - the size exceeds the mirror area
Please change some of them from 'const' to 'const __far'
Error: No room left for const data - the start address exceeds the mirror area
Please move the .text section from lower address to higher address ← .textが.rodataよりも下側の場合

Error: No room left for const data - the start address exceeds the mirror area
Please check the map file ← .textが.rodataよりも上側の場合
Error: No room left for const data - the end address exceeds the mirror area
Please move the .text section from lower address to higher address ← .textが.rodataよりも下側の場合

Error: No room left for const data - the end address exceeds the mirror area
Please check the map file ← .textが.rodataよりも上側の場合

e2 studioの画面コピー(const領域のサイズがMirror領域のサイズを超えた場合の例)


今回、エラーをチェックする為のリンカスクリプトの変更として、以下の記述を追加しました。(以下の赤文字箇所)

    PROVIDE(__mirror = 0x3000);
    PROVIDE(__mirror_end = __mirror + 28416);
    PROVIDE(__rodata = ADDR(.rodata));
    .rodata MAX(., __mirror):
    {
        . = ALIGN(2);
        *(.rodata)
        *(.rodata.*)
        _erodata = .;
        ASSERT(!(SIZEOF(.rodata) > (__mirror_end - __mirror)), "Error: Too much const data - the size exceeds the mirror area");
        ASSERT(!(SIZEOF(.rodata) > (__mirror_end - __mirror)), "Please change some of them from 'const' to 'const __far'");
        ASSERT(!((SIZEOF(.rodata) <= (__mirror_end - __mirror)) && (SIZEOF(.rodata) > 0) && (ABSOLUTE(__rodata) >= __mirror_end)), "Error: No room left for const data - the start address exceeds the mirror area");
        ASSERT(!((SIZEOF(.rodata) <= (__mirror_end - __mirror)) && (SIZEOF(.rodata) > 0) && (ABSOLUTE(__rodata) < __mirror_end) && (ABSOLUTE(.) > __mirror_end)), "Error: No room left for const data - the end address exceeds the mirror area");
        ASSERT(!((SIZEOF(.rodata) <= (__mirror_end - __mirror)) && (SIZEOF(.rodata) > 0) && (ABSOLUTE(.) > __mirror_end) && (ADDR(.text) < __rodata)), "Please move the .text section from lower address to higher address");
        ASSERT(!((SIZEOF(.rodata) <= (__mirror_end - __mirror)) && (SIZEOF(.rodata) > 0) && (ABSOLUTE(.) > __mirror_end) && (__rodata < ADDR(.text))), "Please check the map file");
    } > ROM

なお、__mirrorと__mirror_endへの代入に使われている値はリンカスクリプトの以下の箇所に記述されている値と同じものです。(リンカのマニュアルを見てはみたのですが、以下の箇所の値を直接利用する方法は見つかりませんでした。) よって、やろうと思えば、e2 studioで生成されるGNURL78プロジェクトのテンプレートのソースがあるフォルダのリンカスクリプトを全部一度に変更するバッチファイル/スクリプトファイルを作成することも可能、な筈です、、、

MEMORY
{
    VEC : ORIGIN = 0x0, LENGTH = 4
    IVEC : ORIGIN = 0x4, LENGTH = 188
    OPT : ORIGIN = 0xC0, LENGTH = 4
    SEC_ID : ORIGIN = 0xC4, LENGTH = 10
    OCDSTAD : ORIGIN = 0xCE, LENGTH = 10
    OCDROM : ORIGIN = 0x3FE00, LENGTH = 512
    ROM : ORIGIN = 0xD8, LENGTH = 261416
    MIRROR : ORIGIN = 0xF3000, LENGTH = 28416
    RAM : ORIGIN = 0xF9F00, LENGTH = 24576
}

また、const領域とMirror領域の関係が不適切になってしまう原因の1つには.textセクションが.rodataセクションの下側(0番地側)に収まらなくなってしまうことがあるのですが、その場合に.textセクションを.rodataセクションの上側(0xFFFFF番地側)へ移し易くする為、以下の.mdataセクションをリンカスクリプトに追加しました。(以下の赤文字箇所)(他に橙文字箇所を削除)

従来

    .tors :
    {
        __CTOR_LIST__ = .;
        . = ALIGN(2);
        ___ctors = .;
        *(.ctors)
        ___ctors_end = .;
        __CTOR_END__ = .;
        __DTOR_LIST__ = .;
        ___dtors = .;
        *(.dtors)
        ___dtors_end = .;
        __DTOR_END__ = .;
        . = ALIGN(2);
        _mdata = .;
    } > ROM
    .text (. + __romdatacopysize):
    {
        *(.text)
        *(.text.*)
        etext = .;
        . = ALIGN(2);
    } > ROM
    .data 0xF9F00: AT(_mdata)
    {
        . = ALIGN(2);
        _data = .;
        *(.data)
        *(.data.*)
        . = ALIGN(2);
        _edata = .;
    } > RAM
    PROVIDE(__romdatacopysize = SIZEOF(.data));

今回

    .tors : /* TODO: Does this section work? Should below items be in the .rodata section? */
    {
        __CTOR_LIST__ = .;
        . = ALIGN(2);
        ___ctors = .;
        *(.ctors)
        ___ctors_end = .;
        __CTOR_END__ = .;
        __DTOR_LIST__ = .;
        ___dtors = .;
        *(.dtors)
        ___dtors_end = .;
        __DTOR_END__ = .;
        . = ALIGN(2);
    } > ROM
    .mdata (NOLOAD) :
    {
        _mdata = .;
        . += __romdatacopysize;
    } > ROM
    .text :
    {
        *(.text)
        *(.text.*)
        etext = .;
        . = ALIGN(2);
    } > ROM
    .data 0xF9F00: AT(_mdata)
    {
        . = ALIGN(2);
        _data = .;
        *(.data)
        *(.data.*)
        . = ALIGN(2);
        _edata = .;
    } > RAM
    PROVIDE(__romdatacopysize = SIZEOF(.data));

あと、添付したプロジェクトのソースでは、テスト用に非常に大きいサイズの関数を作る為に以下の記述を使ってみました。これは、アセンブラの繰り返しマクロ .rept ~ .endr で任意の数のnopを生成させるものです。

__attribute__ ((noinline)) void large_func(void);
void large_func(void)
{
    //__asm volatile (".rept 0xA000"); /* the const startd address exceeds the mirror area */
    //__asm volatile (".rept 0x2000"); /* the const end address exceeds the mirror area */
    __asm volatile (".rept 0");
    __asm volatile ("nop");
    __asm volatile (".endr");
}

 

Parents
  • こんにちは。NoMaYです。

    別スレッドでRL78/G14 Fast Prototyping BoardにRL78 FreeRTOSを移植しようとしたところ、本スレッドの発端となった、GNURL78のconst領域/Mirror領域のリンカでの取り扱いがあまり安心出来るようなものでは無かった、ことによるトラブルに私も遭遇してしまいました、、、(発端となったスレッドと同様に、switch文を実行しようとして暴走してしまいました、、、)

    このボードにはRL78/G14 R5F104MLAFB(ROM/RAM/DFLASH=512K/48K/8K)が搭載されていますが、Mirror領域が0x3000から3840バイトしかありません。e2 studioが生成したリンカスクリプトでは、プログラムが置かれる.textセクションが(通常のnearの)const変数やswtich文の分岐テーブル等が置かれる.rodataセクションの下位アドレス側にありますので、それこそちょっとプログラムが大きくなると.rodataセクションがMirror領域の上位アドレス側に押し出されてしまい、位置関係が不正になって、プログラムが誤動作したり暴走したりしてしまいます。

    自分が遭遇してみて思ったのですが、このスレッドのようにASSERT文を入れるのも手ですが、ROMサイズが大きい≒RAMサイズが大きい=Mirror領域が小さい、そういったデバイスに於いては、e2 studioが生成するリンカスクリプトで始めから.textセクションが.rodataセクションよりも上位アドレス側になっていた方がトラブルが少ない筈かな、と思いました。

    いつものように推測ですけど、Starter Kitとか、そういったデバイスが搭載されますので、FreeRTOSの開発者さんがGNURL78対応をコンパイラの問題に遭遇して放置してしまったのは、この件の可能性もあるのかなぁ、とも思いました、、、

Reply
  • こんにちは。NoMaYです。

    別スレッドでRL78/G14 Fast Prototyping BoardにRL78 FreeRTOSを移植しようとしたところ、本スレッドの発端となった、GNURL78のconst領域/Mirror領域のリンカでの取り扱いがあまり安心出来るようなものでは無かった、ことによるトラブルに私も遭遇してしまいました、、、(発端となったスレッドと同様に、switch文を実行しようとして暴走してしまいました、、、)

    このボードにはRL78/G14 R5F104MLAFB(ROM/RAM/DFLASH=512K/48K/8K)が搭載されていますが、Mirror領域が0x3000から3840バイトしかありません。e2 studioが生成したリンカスクリプトでは、プログラムが置かれる.textセクションが(通常のnearの)const変数やswtich文の分岐テーブル等が置かれる.rodataセクションの下位アドレス側にありますので、それこそちょっとプログラムが大きくなると.rodataセクションがMirror領域の上位アドレス側に押し出されてしまい、位置関係が不正になって、プログラムが誤動作したり暴走したりしてしまいます。

    自分が遭遇してみて思ったのですが、このスレッドのようにASSERT文を入れるのも手ですが、ROMサイズが大きい≒RAMサイズが大きい=Mirror領域が小さい、そういったデバイスに於いては、e2 studioが生成するリンカスクリプトで始めから.textセクションが.rodataセクションよりも上位アドレス側になっていた方がトラブルが少ない筈かな、と思いました。

    いつものように推測ですけど、Starter Kitとか、そういったデバイスが搭載されますので、FreeRTOSの開発者さんがGNURL78対応をコンパイラの問題に遭遇して放置してしまったのは、この件の可能性もあるのかなぁ、とも思いました、、、

Children
No Data