如何从C中获取ld链接描述文件中定义的变量值

时间:2018-02-01 11:04:34

标签: c gcc linker

我正在编写一个运行裸机的程序。我试图从自定义链接器脚本中获取变量以在C中使用这是我尝试过的。

来自C:

extern unsigned long* __START_OF_PROG_MEMORY;
volatile unsigned long *StartOfProgram = (unsigned long*) (&__START_OF_PROG_MEMORY);

链接脚本:

SECTIONS
{
    . = 0x80000;
    PROVIDE(__START_OF_PROG_MEMORY = .);
    .text : { KEEP(*(.text.boot)) *(.text .text.* .gnu.linkonce.t*) }
    .rodata : { *(.rodata .rodata.* .gnu.linkonce.r*) }
    PROVIDE(_data = .);
    .data : { *(.data .data.* .gnu.linkonce.d*) }
    .bss (NOLOAD) : {
        . = ALIGN(16);
        __bss_start = .;
        *(.bss .bss.*)
        *(COMMON)
        __bss_end = .;
    }
    _end = .;
    PROVIDE(__END_OF_PROG_MEMORY = .);

   /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) }
}
__bss_size = (__bss_end - __bss_start)>>3;

获取链接描述文件中定义的变量内容的正确方法是什么?

2 个答案:

答案 0 :(得分:3)

通常它就像

一样
// Volatile is normally not needed but it seems you have a special case
extern volatile unsigned char __START_OF_PROG_MEMORY[];
volatile unsigned char * const StartOfProgram = &__START_OF_PROG_MEMORY;

(见this post in Binutils ML)。

答案 1 :(得分:1)

1。访问源代码中的链接描述文件变量的官方文档:

请参阅本页底部的示例: https://sourceware.org/binutils/docs/ld/Source-Code-Reference.html

  

因此,当您在源代码中使用链接器脚本定义的符号时,应始终获取符号的地址,并且切勿尝试使用其值。例如,假设您要将一个名为.ROM的内存段的内容复制到一个名为.FLASH的段中,并且链接脚本包含以下声明:

  start_of_ROM   = .ROM;
  end_of_ROM     = .ROM + sizeof (.ROM);
  start_of_FLASH = .FLASH;
  

然后执行复制的C源代码为:

  extern char start_of_ROM, end_of_ROM, start_of_FLASH;

  memcpy (& start_of_FLASH, & start_of_ROM, & end_of_ROM - & start_of_ROM);
  

请注意使用“&”运算符。这些是正确的。另外,也可以将符号视为向量或数组的名称,然后代码将再次按预期工作:

(我的首选方法):

  extern char start_of_ROM[], end_of_ROM[], start_of_FLASH[];

  memcpy (start_of_FLASH, start_of_ROM, end_of_ROM - start_of_ROM);
  

请注意,使用此方法不需要使用'&'运算符。

2。您的具体情况:

因此,如果我想获取链接程序变量__START_OF_PROG_MEMORY的值以在我的C程序中使用,我会这样做:

#include <stdint.h>

extern uint32_t __START_OF_PROG_MEMORY[]; // linkerscript variable; NOT an array; `[]` is required to access a linkerscript variable like a normal variable--see here: https://sourceware.org/binutils/docs/ld/Source-Code-Reference.html
uint32_t start_of_program = (uint32_t)__START_OF_PROG_MEMORY;

3。请注意,如果您要对STM32微控制器执行此操作:

获取程序存储器(例如闪存,即程序开始位置)起始地址的另一种技巧是简单地获取g_pfnVectors全局ISR向量表数组的地址,这是在您的启动程序集文件中定义的(例如:“ startup_stm32f746xx.s”)。为此,请执行以下操作:

extern uint32_t g_pfnVectors[];  // true array (vector table of all ISRs), from the startup assembly .s file
uint32_t application_start_address = (uint32_t)&g_pfnVectors[0]; // Get the address of the first element of this array and cast it to a 4-byte unsigned integer

Voilá!太神奇了:)。

相关: