mcpField
L
linker-scripts

linker-scripts

github.com/mohitmishra786開発269537 回インストール18 週間前に更新
リポジトリ

linker-scripts について

組み込みターゲット向けに GNU ld リンカースクリプトを作成・変更するエージェント用スキルです。メモリ配置、セクション配置、起動時の初期化、一般的なリンクエラーを扱います。

主な機能

  1. 01MEMORY と SECTIONS の設定
  2. 02VMA と LMA の違いの説明
  3. 03.data と .bss の起動時初期化
  4. 04特定のメモリ領域へのコード配置
  5. 05KEEP、ALIGN、PROVIDE の使用
  6. 06リンカーエラーの診断

活用シーン

  1. 01MCU 用リンカースクリプトの作成
  2. 02重要な関数の RAM 配置
  3. 03FLASH または RAM の容量超過の調査
  4. 04弱シンボルと起動セクションの設定

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/mohitmishra786/low-level-dev-skills --skill linker-scripts

インストール後、Claude Code で/linker-scriptsを入力して読み込まれたか確認します。

同梱ファイルreferences/linker-script-anatomy.md

詳細

リンカースクリプト

目的

組み込みターゲット向けの GNU ld リンカースクリプトの作成と変更をエージェントに案内します。MEMORY コマンドと SECTIONS コマンド、コード再配置における VMA と LMA の違い、起動時の .bss/.data 初期化、特定の領域へのセクション配置、PROVIDE/KEEP/ALIGN ディレクティブの使用方法を扱います。

トリガー

  • 「MCU 用のリンカースクリプトはどう書けばよいですか?」
  • 「特定のフラッシュ/RAM 領域に関数を配置するにはどうすればよいですか?」
  • 「リンカースクリプトにおける VMA と LMA の違いは何ですか?」
  • 「起動時の .bss と .data の初期化はどのように行われますか?」
  • 「リンカーエラー:region 'FLASH' overflowed」
  • 「リンカースクリプトで弱いシンボルを使うにはどうすればよいですか?」

ワークフロー

1. リンカースクリプトの構造
/* Minimal Cortex-M linker script */

ENTRY(Reset_Handler)            /* entry point symbol */

MEMORY
{
    FLASH (rx)  : ORIGIN = 0x08000000, LENGTH = 512K
    RAM   (rwx) : ORIGIN = 0x20000000, LENGTH = 128K
}

SECTIONS
{
    .text :                     /* code section */
    {
        KEEP(*(.isr_vector))    /* interrupt vector must be first */
        *(.text)
        *(.text.*)
        *(.rodata)
        *(.rodata.*)
        . = ALIGN(4);
        _etext = .;             /* end of flash content */
    } > FLASH

    .data : AT(_etext)          /* VMA = RAM, LMA = FLASH */
    {
        _sdata = .;
        *(.data)
        *(.data.*)
        . = ALIGN(4);
        _edata = .;
    } > RAM

    .bss :
    {
        _sbss = .;
        *(.bss)
        *(.bss.*)
        *(COMMON)
        . = ALIGN(4);
        _ebss = .;
    } > RAM

    /* Stack at top of RAM */
    _estack = ORIGIN(RAM) + LENGTH(RAM);
}
2. VMA と LMA
  • VMA(仮想メモリアドレス):実行時にセクションが配置されるアドレスです
  • LMA(ロードメモリアドレス):イメージ内でセクションが格納されるアドレス(フラッシュ)です

.data はフラッシュに格納され(LMA)、起動時に RAM にコピーされます(VMA)。

/* AT() sets LMA explicitly */
.data : AT(ADDR(.text) + SIZEOF(.text))
{
    _sdata = .;
    *(.data)
    _edata = .;
} > RAM          /* VMA goes in RAM */

AT(_etext) を使用すると、.data の LMA は .text の後に自動的に配置されます。

3. 起動時の .bss/.data 初期化

C ランタイムは main() の前に、.data をフラッシュから RAM にコピーし、.bss をゼロクリアする必要があります。

// startup.c or startup.s equivalent in C
extern uint32_t _sdata, _edata, _sidata; // _sidata = LMA of .data
extern uint32_t _sbss, _ebss;

void Reset_Handler(void) {
    // Copy .data from flash to RAM
    uint32_t *src = &_sidata;
    uint32_t *dst = &_sdata;
    while (dst < &_edata) *dst++ = *src++;

    // Zero-initialize .bss
    dst = &_sbss;
    while (dst < &_ebss) *dst++ = 0;

    // Call C++ constructors
    // (call __libc_init_array() if using newlib)

    main();
    for (;;);  // should never return
}

リンカースクリプトは _sidata(.data の LMA)を提供します。

.data : AT(_etext)
{
    _sdata = .;
    *(.data)
    _edata = .;
} > RAM

_sidata = LOADADDR(.data);    /* LMA of .data for startup code */
4. 特定の領域へのコードの配置
/* Place time-critical code in RAM for faster execution */
MEMORY
{
    FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K
    RAM   (rwx): ORIGIN = 0x20000000, LENGTH = 128K
    CCM   (rwx): ORIGIN = 0x10000000, LENGTH = 64K   /* Cortex-M4 CCM */
}

.fast_code : AT(_etext)
{
    _sfast = .;
    *(.fast_code)   /* sections marked __attribute__((section(".fast_code"))) */
    _efast = .;
} > CCM              /* runs from CCM RAM */
// Mark a function to go in fast_code section
__attribute__((section(".fast_code")))
void critical_isr_handler(void) {
    // runs from CCM RAM
}
5. KEEP、ALIGN、PROVIDE
/* KEEP — prevent garbage collection of section */
KEEP(*(.isr_vector))        /* linker gc won't remove interrupt table */
KEEP(*(.init))
KEEP(*(.fini))

/* ALIGN — advance location counter to alignment boundary */
. = ALIGN(8);               /* align to 8 bytes */

/* PROVIDE — define symbol only if not already defined (weak default) */
PROVIDE(_stack_size = 0x400);  /* default 1KB stack; override in code */

/* Symbols for stack */
.stack :
{
    . = ALIGN(8);
    . += _stack_size;
    _stack_top = .;
} > RAM

/* FILL — fill unused bytes */
.text :
{
    *(.text)
    . = ALIGN(4);
    FILL(0xFF)             /* fill flash gaps with 0xFF (erased state) */
} > FLASH
6. 弱いシンボル
/* In linker script — provide weak default ISR */
PROVIDE(NMI_Handler        = Default_Handler);
PROVIDE(HardFault_Handler  = Default_Handler);
PROVIDE(SysTick_Handler    = Default_Handler);
// In C — weak default handler
__attribute__((weak)) void Default_Handler(void) {
    for (;;);  // spin — override this in application
}

// Override by defining a non-weak symbol with the same name
void SysTick_Handler(void) {
    tick_count++;
}
7. よくあるリンカーエラー
エラー原因解決方法
region 'FLASH' overflowedバイナリがフラッシュに収まらないLTO と -Os を有効にし、未使用コードを削除します。--gc-sections を使用します
region 'RAM' overflowedRAM の使用量が多すぎますスタックサイズを減らし、静的バッファーを使用して、.bss のサイズを確認します
undefined reference to '_estack'リンカースクリプトにシンボルがありませんリンカースクリプトで _estack を定義します
no rule to process file.ld 拡張子が認識されません-T script.ld を指定します
cannot find linker scriptパスが間違っています-L dir -T name.ld を使用します
データセクション .data のアドレスが間違っていますLMA が設定されていません.data セクションの定義の後に AT(_etext) を追加します
# Analyze section sizes
arm-none-eabi-size firmware.elf
arm-none-eabi-size -A firmware.elf    # verbose per-section

# Show all sections and their addresses
arm-none-eabi-objdump -h firmware.elf

# Check if .data LMA is in flash range
arm-none-eabi-readelf -S firmware.elf | grep -A2 "\.data"

リンカースクリプトの構造の詳細については、references/linker-script-anatomy.md を参照してください。

関連スキル

  • リンカースクリプトで定義されたアドレスへの書き込みには skills/embedded/openocd-jtag を使用します
  • 特定の RAM 領域への FreeRTOS ヒープ配置には skills/embedded/freertos を使用します
  • リンカーの LTO とシンボルフラグには skills/binaries/linkers-lto を使用します
  • セクションのサイズとアドレスの確認には skills/binaries/elf-inspection を使用します

コメント