Use when explaining System V AMD64, ARM AAPCS, RISC-V psABI, stack frames, variadic calls, or FFI register rules. Not for the Rust FFI binding layer: use rust-ffi.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Use when writing a GNU ld script for a bare-metal target, placing code in a flash or RAM region, wiring .data and .bss startup, or fixing a region overflowed error. Not for LTO: use linkers-lto.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
설치 방법 보기설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.
| Field | Bound contract |
|---|---|
| Trigger | A bare-metal image needs a GNU ld script: MEMORY and SECTIONS, VMA versus LMA for .data, the symbols startup code copies between, a function placed in a named region, weak default handlers, or a region overflow error. |
| Authority | Reversible local: writes only the linker script and the startup source in the project directory the user names; rollback is reverting those files in version control. No remote mutation. |
| Side effect | New or edited .ld and startup files. The image layout changes on the next link. |
| Done | The ELF links, readelf -S shows .data with an LMA inside flash and a VMA inside RAM, .bss and the stack fit the RAM region, and the startup code copies .data and zeroes .bss between the script's symbols before main. |
.isr_vector in the CMSIS templates).__libc_init_array and the .init_array sections) or none.Write MEMORY and the skeleton SECTIONS. ENTRY names the reset symbol; KEEP on the vector table stops --gc-sections from removing it; _estack at the top of RAM is where the startup file points the stack. Done when: the script has one MEMORY block with every region from the datasheet and the link succeeds with -T script.ld.
ENTRY(Reset_Handler)
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 128K
}
SECTIONS
{
.text :
{
KEEP(*(.isr_vector))
*(.text .text.*)
*(.rodata .rodata.*)
. = ALIGN(4);
_etext = .;
} > FLASH
.data :
{
. = ALIGN(4);
_sdata = .;
*(.data .data.*)
. = ALIGN(4);
_edata = .;
} > RAM AT > FLASH
_sidata = LOADADDR(.data);
.bss :
{
_sbss = .;
*(.bss .bss.*)
*(COMMON)
. = ALIGN(4);
_ebss = .;
} > RAM
_estack = ORIGIN(RAM) + LENGTH(RAM);
}
Separate VMA from LMA for .data. The VMA is the address the code runs at (RAM); the LMA is where the bytes sit in the image (flash). > RAM AT > FLASH sets both; AT(_etext) after the section name is the equivalent explicit form. LOADADDR(.data) gives startup code the flash copy's address. Done when: arm-none-eabi-readelf -S firmware.elf shows .data with Addr in RAM and arm-none-eabi-objdump -h shows its LMA in flash.
Copy .data and zero .bss in the reset handler, between the script's symbols. With newlib, call __libc_init_array() before main so C++ constructors and .init_array entries run. Done when: a global initialized to a nonzero value reads that value in main, and a zero-initialized global reads zero.
extern uint32_t _sdata, _edata, _sidata, _sbss, _ebss;
void Reset_Handler(void) {
uint32_t *src = &_sidata, *dst = &_sdata;
while (dst < &_edata) *dst++ = *src++;
for (dst = &_sbss; dst < &_ebss; ) *dst++ = 0;
__libc_init_array();
main();
for (;;);
}
The startup file itself is the subject of baremetal-startup; this skill owns the symbols it consumes.
Place code or data in a named region. Give the input section a name with __attribute__((section(".name"))), collect it into an output section with > REGION AT > FLASH, and copy it at startup like .data when the region is RAM. Done when: objdump -h shows the section in the intended region and the copy loop covers it.
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 128K
CCM (rwx) : ORIGIN = 0x10000000, LENGTH = 64K
}
.fast_code :
{
_sfast = .;
*(.fast_code .fast_code.*)
_efast = .;
} > CCM AT > FLASH
_sifast = LOADADDR(.fast_code);
__attribute__((section(".fast_code"))) void critical_isr_handler(void) { }
CCM on STM32F4 is not on the DMA bus; place DMA buffers in SRAM.
Use KEEP, ALIGN, PROVIDE, and the fill expression where each applies. KEEP protects sections --gc-sections would drop (vector table, .init_array). ALIGN(8) before the stack satisfies the AAPCS 8-byte stack alignment. PROVIDE defines a symbol only if no object defines it, which makes it the default a program can override. The =0xFF fill after an output section writes the erased-flash value into gaps. Done when: every KEEP guards a section the code never references directly, and the stack region starts 8-byte aligned.
PROVIDE(_stack_size = 0x400);
.stack (NOLOAD) :
{
. = ALIGN(8);
. += _stack_size;
_stack_top = .;
} > RAM
.text : { *(.text .text.*) . = ALIGN(4); } > FLASH = 0xFF
Give every exception a weak default handler. PROVIDE(NMI_Handler = Default_Handler) in the script, or __attribute__((weak)) in C, binds the vector to a spin loop until the application defines the real symbol. Done when: a firmware with no SysTick_Handler links, and one that defines it calls the definition.
PROVIDE(NMI_Handler = Default_Handler);
PROVIDE(HardFault_Handler = Default_Handler);
PROVIDE(SysTick_Handler = Default_Handler);
__attribute__((weak)) void Default_Handler(void) { for (;;); }
void SysTick_Handler(void) { tick_count++; } /* overrides the default */
Check sizes and addresses after every layout change. --print-memory-usage (pass as -Wl,--print-memory-usage) prints region use at link time; -Wl,-Map=firmware.map writes the symbol map for the big-symbol hunt. Done when: every region is under 100 percent and .data's LMA is inside flash.
arm-none-eabi-size -A firmware.elf
arm-none-eabi-objdump -h firmware.elf
arm-none-eabi-readelf -S firmware.elf
references/linker-script-anatomy.md has a complete STM32F407 script with the ARM unwind and .init_array sections and the table of built-in functions.
| Error | Cause | Fix |
|---|---|---|
region `FLASH' overflowed by N bytes | Image larger than flash | -Os, -ffunction-sections -fdata-sections with -Wl,--gc-sections, LTO; find the big symbols in the map file. |
region `RAM' overflowed | .data, .bss, heap, and stack exceed RAM | Shrink buffers, cut _stack_size or the heap, move constants to const so they land in .rodata. |
undefined reference to '_estack' | Startup expects a symbol the script does not define | Define _estack = ORIGIN(RAM) + LENGTH(RAM);. |
.data reads garbage at boot | LMA equals VMA, or startup copies the wrong range | Add AT > FLASH; copy from LOADADDR(.data) to _sdata up to _edata. |
| Vector table missing from the image | --gc-sections removed it | Wrap it in KEEP. |
cannot open linker script file | Wrong path | Pass -T path/to/script.ld or add -L dir. |
A linker script and startup symbols in the named directory that link the image into the datasheet's regions, with readelf -S and objdump -h output confirming .data LMA in flash and VMA in RAM and every region within its length.
아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.
로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.
아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.
Use when explaining System V AMD64, ARM AAPCS, RISC-V psABI, stack frames, variadic calls, or FFI register rules. Not for the Rust FFI binding layer: use rust-ffi.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Use when configuring ADC sampling time, DMA-driven ADC, calibration, or DAC channel setup on bare-metal MCUs. Not for the DMA stream itself: use dma-baremetal.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Use when creating AF_XDP sockets, configuring UMEM and XSK rings, writing an XDP redirect program, or choosing copy versus zero-copy mode. Not for full kernel bypass: use dpdk.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Use when a completed session needs an agent-environment retrospective. Not for an engineering retrospective from telemetry: use engineering-retrospective.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Use when a redacted, trimmed agent transcript must be appended to a GitHub PR or issue body, with human approval and preview. Not for automated or model-initiated insertion.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Use when a repo needs agent setup, AGENTS.md added or made lean, CLAUDE.md audited, or agent instructions scored or pruned. Not for remote, credential, publish, deploy, or irreversible changes.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.