首页 > 解决方案 > AVR - GNU 链接器脚本 - 如何获取 .data 部分的加载地址

问题描述

我对 GNU 链接器脚本很陌生。avr-libc想要为 AVR MCU创建一个裸机(不带)应用程序。在项目的早期阶段,我不需要初始化该.data部分。但现在我需要它。

我当前的链接器脚本:

OUTPUT_FORMAT(elf32-avr)
OUTPUT_ARCH(avr51)

ENTRY(_start)

MEMORY {
    FLASH_APP   (rx) : ORIGIN = 0x00000000, LENGTH = 120K
    FLASH_BOOT  (rx) : ORIGIN = 0x0001E000, LENGTH = 8K
    SRAM        (rw) : ORIGIN = 0x00800100, LENGTH = 16K
}

STACK_SIZE = 4K;

SECTIONS {
    .text : {
        _text_s = .;
        KEEP(*(.isr_vector))
        *(.text)
        *(.text*)
        _text_e = .;
    } > FLASH_BOOT
    
    .rodata : {
        . = ALIGN(2);
        _rodata_s = .;
        *(.rodata)
        *(.rodata*)
        _rodata_e = .;
        . = ALIGN(2);
    } > FLASH_BOOT
    
    .data :  {
        . = ALIGN(2);
        _data_s = .;
        *(.data)
        *(.data*)
        _data_e = .;
        . = ALIGN(2);
    } > SRAM AT > FLASH_BOOT
    
    .bss (NOLOAD):  {
        . = ALIGN(2);
        _bss_s = .;
        *(.bss)
        *(.bss*)
        *(COMMON)
        _bss_e = .;
    } > SRAM
    
    HEAP_SIZE = (ORIGIN(SRAM) + LENGTH(SRAM)) - _heap_s - STACK_SIZE;
        
    .heap (NOLOAD): {
        . = ALIGN(2);
        _heap_s = .;
        . = . + HEAP_SIZE;
        _heap_e = .;
    } > SRAM
    
    .stack (NOLOAD):  {
        . = ALIGN(2);
        _stack_s = .;
        . = . + STACK_SIZE;
        _stack_e = .;
    } > SRAM
}

对于该.bss部分,我在链接描述文件中使用符号,我在汇编中使用它来将该.bss部分归零。我编写了这些函数来获取该.bss部分的开始和结束:

/* Get .bss start */
FUNCTION(asm_self_get_bss_s)
    ldi r24, lo8(_bss_s)
    ldi r25, hi8(_bss_s)
    ret

/* Get .bss end */
FUNCTION(asm_self_get_bss_e)
    ldi r24, lo8(_bss_e)
    ldi r25, hi8(_bss_e)
    ret

如何获取.data链接描述文件中该部分的加载地址 (FLASH) 以从 SRAM 中的 FLASH 复制(初始化)数据?符号_data_s_data_e在我的链接器脚本中返回 SRAM 地址。但是我怎样才能从 FLASH 中得到地址呢?GNU-ld 是否有特殊功能?

标签: assemblyavrbare-metallinker-scripts

解决方案


我找到了解决方案。

LOADADDR()是从链接描述文件中的部分获取加载地址的正确函数.data

LOADADDR(section)
返回指定节的绝对加载地址。这通常与 ADDR 相同,但如果在节定义中使用 AT 关键字,则可能会有所不同(请参阅可选节属性一节)。

引用自 GNU 链接器手册

以下内容现在适用于我改进的链接器脚本:

    .data :  {
        . = ALIGN(2);
        _data_s_load = LOADADDR(.data);
        _data_s = .;
        *(.data)
        *(.data*)
        _data_e = .;
        . = ALIGN(2);
    } > SRAM AT > FLASH_BOOT

以及具体的组装功能:

/* Get .data start */
FUNCTION(asm_self_get_data_s)
    ldi r24, lo8(_data_s)
    ldi r25, hi8(_data_s)
    ret

/* Get .data end */
FUNCTION(asm_self_get_data_e)
    ldi r24, lo8(_data_e)
    ldi r25, hi8(_data_e)
    ret

/* Get .data start (load address) */
FUNCTION(asm_self_get_data_s_load)
    ldi r22, lo8(_data_s_load)
    ldi r23, hi8(_data_s_load)
    ldi r24, hh8(_data_s_load)
    eor r25, r25
    ret

我现在可以使用指令将数据从 FLASH 复制(初始化)到 SRAM elpm


推荐阅读