AVR - GNU 链接器脚本 - 如何获取 .data 部分的加载地址

Posted

技术标签:

【中文标题】AVR - GNU 链接器脚本 - 如何获取 .data 部分的加载地址【英文标题】:AVR - GNU linker script - How to get the load address of .data section 【发布时间】:2021-10-10 16:40:09 【问题描述】:

我对 GNU 链接器脚本很陌生。想要为 AVR MCU 创建一个裸机(没有avr-libc)应用程序。在项目的早期阶段,我不需要初始化 .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 是否有特殊功能?

【问题讨论】:

【参考方案1】:

我找到了解决办法。

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

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

Quote from GNU linker manual

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

    .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

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

【讨论】:

以上是关于AVR - GNU 链接器脚本 - 如何获取 .data 部分的加载地址的主要内容,如果未能解决你的问题,请参考以下文章

如何获取 GCC 链接器命令?

使用 GNU ld 链接器脚本包含二进制文件

将文件添加到 GNU 依赖项列表?

GNU链接器:替代--version-script在命令行列出导出的符号?

重新排序 gnu autotools 链接器标志

链接器优化共享库