gcc在优化期间更改映射变量的地址

时间:2015-12-01 23:14:48

标签: c gcc optimization linker memory-mapping

我正在开源环境中使用arm-none-eabi-gcc v4.9.3编译ARM stm32微控制器的C代码。 代码在没有编译器优化的情况下运行良好(gcc -g -O0 ...)。

当我启用最轻微的优化(gcc -g -O1 ...)时,链接器定义变量的地址会发生变化。

file memory.ld

register_cortexm3_ACTLR      = 0xe000e008;
...

MEMORY
{
                 rom (rx ) : ORIGIN = 0x08000000,  LENGTH = 256K
                 ram (rxw) : ORIGIN = 0x20000000,  LENGTH = 64K
        sram_bitband (rw ) : ORIGIN = 0x22000000,  LENGTH = 32768K
          peripheral (rw ) : ORIGIN = 0x40000000,  LENGTH = 1024K
  peripheral_bitband (rw ) : ORIGIN = 0x42000000,  LENGTH = 32768K
                sram (rwx) : ORIGIN = 0x60000000,  LENGTH = 1048576K
        ram_external (rwx) : ORIGIN = 0x60000000,  LENGTH = 1048576K
                code (rwx) : ORIGIN = 0x60000000,  LENGTH = 1048576K
     device_external (rw ) : ORIGIN = 0xa0000000,  LENGTH = 1048576K
  private_peripheral (rw ) : ORIGIN = 0xe0000000,  LENGTH = 1024K
       vendor_memory (rw ) : ORIGIN = 0xe0100000,  LENGTH = 523264K
}

SECTIONS
{
 /* Section for variables mapped onto registers */
 .peripherals (OVERLAY) :
 {
    . = ALIGN(4);
    *(.peripherals)
 } >peripheral

 .private_peripherals (OVERLAY) :
 {
    . = ALIGN(4);
    *(.private_peripherals)
} >private_peripheral

...

file register_cortexm3.h

typedef struct {
    unsigned DISMCYCINT  : 1;
    unsigned DISDEFWBUF  : 1;
    unsigned DISFOLD     : 1;
    unsigned reserved1   : 13;
    unsigned reserved2   : 16;
} __attribute__( ( __packed__ ) ) register_cortexm3_actlr_t;

...

file register_cortexm3.c

void check_same( volatile void* Address1, volatile void* Address2 ) {

    if ( Address1 != Address2 )
    { Assert_Halt_EC( ec_InvalidImplementation ); }
}

volatile register_cortexm3_actlr_t register_cortexm3_ACTLR   
__attribute__( ( section( ".private_peripherals" ) ) ); 

void register_cortexm3_prepare() {

    // checking for correct linker script settings
    check_same(&( register_cortexm3_ACTLR ), ( volatile void* ) 0xe000e008);
}

当启用优化时,上面的比较失败,因为在check_same()函数内,第一个参数是0xe0000000(其内存部分的起始地址),根据gdb:

Breakpoint 1, Assert_Halt_EC   (ErrorCode=ErrorCode@entry=ec_InvalidImplementation) at ttc-lib/ttc_basic.c:65
65      void Assert_Halt_EC( volatile ErrorCode_e ErrorCode ) { // block endless
(gdb) up
#1  0x08004440 in check_same (Address1=Address1@entry=0xe0000000, Address2=Address2@entry=0xe000e008) at ttc-lib/ttc_basic.c:58
58          { Assert_Halt_EC( ec_InvalidImplementation ); }
(gdb) up
#2  0x080034f6 in register_cortexm3_prepare () at ttc-lib/register/register_cortexm3.c:40
40          Assert_SameAddress( &( register_cortexm3_ACTLR ), ( void* ) 0xe000e008 );
(gdb) x &( register_cortexm3_ACTLR )
0xe000e008:     0x00000000

正如您在上一个gdb输出行中所看到的,gdb知道register_cortexm3_ACTLR的正确地址。

这是gcc错误还是功能? 如何解决它?

2 个答案:

答案 0 :(得分:2)

我不确定为什么优化会对此产生任何影响,但基本问题是您已经给出了符号register_cortexm3_ACTLR的两个不同且相互矛盾的定义。您的链接描述文件中的一个定义表示它在地址0xe000e008中没有任何部分,而另一个定义在您的C代码中表示它位于.private_peripherals部分的某个偏移处。

您需要选择其中一个。如果您希望变量位于链接描述文件中给出的地址,请使用extern来引用它。类似的东西:

extern volatile register_cortexm3_actlr_t register_cortexm3_ACTLR;

答案 1 :(得分:0)

把它们放在一起。这就是人们如何将变量映射到固定地址而不是使用指针变量。

映射变量优于指针的优点: - 没有RAM使用(每个指针在32位架构中消耗4个字节) - 没有指针取消引用寄存器访问(少一个内存访问) - 没有初始化代码(指针必须被初始化)

假设我们想要一个变量u32_t register_Foo映射到地址0x12345678。 在链接描述文件中添加一行(此处为memory.ld):

memory.ld

register_Foo = 0x12345678;

在头文件中添加注册结构和extern声明。

foo.h中

typedef struct {
    unsigned DISMCYCINT  : 1;
    unsigned DISDEFWBUF  : 1;
    unsigned DISFOLD     : 1;
    unsigned reserved1   : 13;
    unsigned reserved2   : 16;
} __attribute__( ( __packed__ ) ) register_foo_t;

extern volatile register_foo_t register_Foo;

在源代码中访问您的注册表。

foo.c的

#include "foo.h"

void foo() {
    register_Foo.DISFOLD = 1;
    ...
}

Thanx明白这一点。