可能大家都熟悉 "char a[] PROGMEM={1,2,3,4}; "的定义方式,但是这种方式定义出来的变量地址
是由编译器和连接器分配的,不能确定. 那有什么办法没呢? 答案是有.
在网上搜索到2种方法:
1. 在makefile 中定义section,如下:
LDFLAGS = -Wl,--section-start=.mydatasection=0x001000,-Map=$(TARGET).map,--cref
然后引用
const unsigned char data[] __attribute__((section(".mydatasection")))={
0x10,0x20,0x30
};
2. 在连接脚本里修改设置.
在实验方法1
在makefile 中设置
LDFLAGS += -Wl,--section-start=.mydatasection=0x001500
在main.c中引用
const unsigned char mydata[4] __attribute((section(".mydatasection"))) = {'9','1','2','3'};
但是要注意,mydatasection 的定位地址,要是其它段没有用到的才可以,否则会报错,有地址重叠.
实验方法2(修改连接脚本),winavr20071221 版本,默认用的是avr4.x 脚本.
先是研读了下)《GNU-ld链接脚本浅析》:http://blog.chinaunix.net/u/13991/showart_177822.html
(惭愧啊,现在也还是没读太明白).
我修改后的脚本内容部分:
.start : /*原来这里是.text,我改成.start*/
{
*(.vectors)
KEEP(*(.vectors))
/* For data that needs to reside in the lower 64k of progmem. */
*(.progmem.gcc*)
*(.progmem*) /*呵呵,常用到的 "PROGMEM" 是在这里定义的啊 */
. = ALIGN(2);
__trampolines_start = . ;
/* The jump trampolines for the 16-bit limited relocs will reside here. */
*(.trampolines)
*(.trampolines*)
__trampolines_end = . ;
/* For future tablejump instruction arrays for 3 byte pc devices.
We don't relax jump/call instructions within these sections. */
*(.jumptables)
*(.jumptables*)
/* For code that needs to reside in the lower 128k progmem. */
*(.lowtext)
*(.lowtext*)
__ctors_start = . ;
*(.ctors)
__ctors_end = . ;
__dtors_start = . ;
*(.dtors)
__dtors_end = . ;
KEEP(SORT(*)(.ctors))
KEEP(SORT(*)(.dtors))
/* From this point on, we don't bother about wether the insns are
below or above the 16 bits boundary. */
*(.init0) /* Start here after reset. */
KEEP (*(.init0))
*(.init1)
KEEP (*(.init1))
*(.init2) /* Clear __zero_reg__, set up stack pointer. */
KEEP (*(.init2))
*(.init3)
KEEP (*(.init3))
*(.init4) /* Initialize data and BSS. */
KEEP (*(.init4))
*(.init5)
KEEP (*(.init5))
*(.init6) /* C++ constructors. */
KEEP (*(.init6))
*(.init7)
KEEP (*(.init7))
*(.init8)
KEEP (*(.init8))
*(.init9) /* Call main(). */
KEEP (*(.init9))
}
.first_data 0x100 : AT(0x100) /*这里开始定义第一个自己section,注意要 VMA 和LMA 都要设置,且
相同,否则编译会有错,可能是因为不支持VMA与LMA不同地址*/
{
. = ALIGN(2);
*(.first_data)
*(.first_data*) /*注意这行哦,*(.first_data*) 表示用改section 定义的数据放在这里*/
}
.second_data 0x180 : AT(0x180 ) /*这里第2个*/
{
. = ALIGN(2);
*(.second_data)
*(.second_data*)
}
.text 0x200 : AT(0x200) /*这里第3个*/
{
*(.text)
. = ALIGN(2);
*(.text.*)
. = ALIGN(2);
*(.fini9) /* _exit() starts here. */
KEEP (*(.fini9))
*(.fini8)
KEEP (*(.fini8))
*(.fini7)
KEEP (*(.fini7))
*(.fini6) /* C++ destructors. */
KEEP (*(.fini6))
*(.fini5)
KEEP (*(.fini5))
*(.fini4)
KEEP (*(.fini4))
*(.fini3)
KEEP (*(.fini3))
*(.fini2)
KEEP (*(.fini2))
*(.fini1)
KEEP (*(.fini1))
*(.fini0) /* Infinite loop after program termination. */
KEEP (*(.fini0))
_etext = . ;
} > text
.third_data 0x1400 : AT(0x1400) /*这里第4个*/
{
. = ALIGN(2);
*(.third_data)
*(.third_data*)
}
.data : AT (ADDR (.third_data) + SIZEOF (.third_data))
{
PROVIDE (__data_start = .) ;
*(.data)
*(.data*)
*(.rodata) /* We need to include .rodata here if gcc is used */
*(.rodata*) /* with -fdata-sections. */
*(.gnu.linkonce.d*)
. = ALIGN(2);
_edata = . ;
PROVIDE (__data_end = .) ;
} > data
文件中引用:
const unsigned char buff2[4] __attribute((section(".first_data"))) = {'9','1','2','3'};
const unsigned char buff3[4] __attribute((section(".first_data"))) = {'9','1','2','3'};
看编译后的map
first_data 0x00000100 0x8 load address 0x00000100
0x00000100 . = ALIGN (0x2)
*(.first_data)
.first_data 0x00000100 0x8 main.o
0x00000104 buff3
0x00000100 buff2
*(.first_data*)
.second_data 0x00000180 0x0 load address 0x00000180
0x00000180 . = ALIGN (0x2)
*(.second_data)
*(.second_data*)
third_data 0x00001400 0x0 load address 0x00001400
0x00001400 . = ALIGN (0x2)
*(.third_data)
*(.third_data*)
.data 0x00800100 0x0 load address 0x00001400
0x00800100 PROVIDE (__data_start, .)
读取函数还是跟 用 PROGMEM 定义的一样, PROGMEM,只是告诉编译器或连接器把该变量放到什么地方去.
另外,该ld脚本是经过修改,可能就适合这个特定项目,可以在makefile 中指定该项目的特定的脚本,而不是用默认的
方法: LDFLAGS += -Wl,-T ./avr4.x
文章评论(0条评论)
登录后参与讨论