__attribute__之section详解

#define __application_init(function)
struct _s_application_init s_a_init##function __app_init_section = {function}

static int application_init_a(void)
{
printf(“execute funtion : %s\n”, FUNCTION);
return 0;
}
__application_init(application_init_a);

static int application_init_b(void)
{
printf(“execute funtion : %s\n”, FUNCTION);
return 0;
}
__application_init(application_init_b);

static int application_init_c(void)
{
printf(“execute funtion : %s\n”, FUNCTION);
return 0;
}
__application_init(application_init_c);

int main(int argc, char *argv)
{
/

* 从段的起始地址开始获取数据,直到末尾地址
*/
struct _s_application_init *pf_init = &_init_start;
do {
printf(“Load init function from address %p\n”, pf_init);
pf_init->function();
++pf_init;
} while (pf_init < &_init_end);
return 0;
}


然后我们还需要编写lds文件,首先使用命令生成默认的文件:



seven@root:~/section/$ ld --verbose > main.lds
seven@root:~/section/$ cat main.lds
GNU ld (GNU Binutils for Ubuntu) 2.26.1
Supported emulations:
elf_i386
i386linux
elf_iamcu
elf32_x86_64
elf_x86_64
elf_l1om
elf_k1om
i386pep
i386pe
using internal linker script:

/* Script for -z combreloc: combine and sort reloc sections /
/
Copyright © 2014-2015 Free Software Foundation, Inc.
Copying and distribution of this script, with or without modification,
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved. /
OUTPUT_FORMAT(“elf32-i386”, “elf32-i386”,
“elf32-i386”)
OUTPUT_ARCH(i386)
ENTRY(_start)
SEARCH_DIR(“=/usr/local/lib/i386-linux-gnu”); SEARCH_DIR(“=/lib/i386-linux-gnu”); SEARCH_DIR(“=/usr/lib/i386-linux-gnu”); SEARCH_DIR(“=/usr/local/lib32”); SEARCH_DIR(“=/lib32”); SEARCH_DIR(“=/usr/lib32”); SEARCH_DIR(“=/usr/local/lib”); SEARCH_DIR(“=/lib”); SEARCH_DIR(“=/usr/lib”); SEARCH_DIR(“=/usr/i686-linux-gnu/lib32”); SEARCH_DIR(“=/usr/i686-linux-gnu/lib”);
SECTIONS
{
/
Read-only sections, merged into text segment: */
PROVIDE (__executable_start = SEGMENT_START(“text-segment”, 0x08048000)); . = SEGMENT_START(“text-segment”, 0x08048000) + SIZEOF_HEADERS;
.interp : { *(.interp) }
.note.gnu.build-id : { *(.note.gnu.build-id) }
.hash : { *(.hash) }
.gnu.hash : { *(.gnu.hash) }
.dynsym : { (.dynsym) }
.dynstr : { (.dynstr) }
.gnu.version : { (.gnu.version) }
.gnu.version_d : { (.gnu.version_d) }
.gnu.version_r : { (.gnu.version_r) }
.rel.dyn :
{
(.rel.init)
(.rel.text .rel.text. .rel.gnu.linkonce.t.
)
(.rel.fini)
(.rel.rodata .rel.rodata. .rel.gnu.linkonce.r.
)
(.rel.data.rel.ro .rel.data.rel.ro. .rel.gnu.linkonce.d.rel.ro.
)
(.rel.data .rel.data. .rel.gnu.linkonce.d.
)
(.rel.tdata .rel.tdata. .rel.gnu.linkonce.td.
)
(.rel.tbss .rel.tbss. .rel.gnu.linkonce.tb.
)
(.rel.ctors)
(.rel.dtors)
(.rel.got)
(.rel.bss .rel.bss. .rel.gnu.linkonce.b.
)
(.rel.ifunc)
}
.rel.plt :
{
(.rel.plt)
PROVIDE_HIDDEN (__rel_iplt_start = .);
(.rel.iplt)
PROVIDE_HIDDEN (__rel_iplt_end = .);
}
.init :
{
KEEP (
(SORT_NONE(.init)))
}
.plt : { (.plt) (.iplt) }
.plt.got : { (.plt.got) }
.text :
{
(.text.unlikely .text._unlikely .text.unlikely.
)
(.text.exit .text.exit.)
(.text.startup .text.startup.)
(.text.hot .text.hot.)
(.text .stub .text. .gnu.linkonce.t.
)
/
.gnu.warning sections are handled specially by elf32.em. /
(.gnu.warning)
}
.fini :
{
KEEP (
(SORT_NONE(.fini)))
}
PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
.rodata : { (.rodata .rodata. .gnu.linkonce.r.
) }
.rodata1 : { (.rodata1) }
.eh_frame_hdr : { (.eh_frame_hdr) (.eh_frame_entry .eh_frame_entry.) }
.eh_frame : ONLY_IF_RO { KEEP (
(.eh_frame)) (.eh_frame.) }
.gcc_except_table : ONLY_IF_RO { (.gcc_except_table
.gcc_except_table.
) }
.gnu_extab : ONLY_IF_RO { (.gnu_extab) }
/
These sections are generated by the Sun/Oracle C++ compiler. /
.exception_ranges : ONLY_IF_RO { (.exception_ranges
.exception_ranges
) }
/
Adjust the address for the data segment. We want to adjust up to
the same address within the page on the next page up. /
. = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));
/
Exception handling /
.eh_frame : ONLY_IF_RW { KEEP (
(.eh_frame)) (.eh_frame.) }
.gnu_extab : ONLY_IF_RW { (.gnu_extab) }
.gcc_except_table : ONLY_IF_RW { (.gcc_except_table .gcc_except_table.) }
.exception_ranges : ONLY_IF_RW { (.exception_ranges .exception_ranges) }
/
Thread Local Storage sections /
.tdata : { (.tdata .tdata. .gnu.linkonce.td.
) }
.tbss : { (.tbss .tbss. .gnu.linkonce.tb.
) (.tcommon) }
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (
(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
}
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (
(SORT_BY_INIT_PRIORITY(.init_array.
) SORT_BY_INIT_PRIORITY(.ctors.
)))
KEEP (
(.init_array EXCLUDE_FILE (crtbegin.o crtbegin?.o crtend.o crtend?.o ) .ctors))
PROVIDE_HIDDEN (__init_array_end = .);
}
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (
(SORT_BY_INIT_PRIORITY(.fini_array.
) SORT_BY_INIT_PRIORITY(.dtors.
)))
KEEP (
(.fini_array EXCLUDE_FILE (*crtbegin.o crtbegin?.o crtend.o crtend?.o ) .dtors))
PROVIDE_HIDDEN (__fini_array_end = .);
}
.ctors :
{
/
gcc uses crtbegin.o to find the start of
the constructors, so we make sure it is
first. Because this is a wildcard, it
doesn’t matter if the user does not
actually link against crtbegin.o; the
linker won’t look for a file to match a
wildcard. The wildcard also means that it
doesn’t matter which directory crtbegin.o
is in. /
KEEP (crtbegin.o(.ctors))
KEEP (crtbegin?.o(.ctors))
/
We don’t want to include the .ctor section from
the crtend.o file until after the sorted ctors.
The .ctor section from the crtend file contains the
end of ctors marker and it must be last /
KEEP (
(EXCLUDE_FILE (crtend.o crtend?.o ) .ctors))
KEEP (
(SORT(.ctors.
)))
KEEP (
(.ctors))
}
.dtors :
{
KEEP (crtbegin.o(.dtors))
KEEP (crtbegin?.o(.dtors))
KEEP (
(EXCLUDE_FILE (crtend.o crtend?.o ) .dtors))
KEEP (
(SORT(.dtors.
)))
KEEP (
(.dtors))
}
.jcr : { KEEP (
(.jcr)) }
.data.rel.ro : { (.data.rel.ro.local .gnu.linkonce.d.rel.ro.local.
) (.data.rel.ro .data.rel.ro. .gnu.linkonce.d.rel.ro.
) }
.dynamic : { *(.dynamic) }
.got : { *(.got) *(.igot) }
. = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 12 ? 12 : 0, .);
.got.plt : { *(.got.plt) (.igot.plt) }
.data :
{
(.data .data. .gnu.linkonce.d.
)
SORT(CONSTRUCTORS)
}
.data1 : { (.data1) }
_edata = .; PROVIDE (edata = .);
. = .;
__bss_start = .;
.bss :
{
(.dynbss)
(.bss .bss. .gnu.linkonce.b.
)
(COMMON)
/
Align here to ensure that the .bss section occupies space up to
end. Align after .bss to ensure correct alignment even if the
.bss section disappears because there are no input sections.
FIXME: Why do we need it? When there is no .bss section, we don’t
pad the .data section. /
. = ALIGN(. != 0 ? 32 / 8 : 1);
}
. = ALIGN(32 / 8);
. = SEGMENT_START(“ldata-segment”, .);
. = ALIGN(32 / 8);
_end = .; PROVIDE (end = .);
. = DATA_SEGMENT_END (.);
/
Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { (.comment) }
/
DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. /
/
DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { (.line) }
/
GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { (.debug_sfnames) }
/
DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { (.debug_pubnames) }
/
DWARF 2 */
.debug_info 0 : { (.debug_info .gnu.linkonce.wi.) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { (.debug_line .debug_line. .debug_line_end ) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { (.debug_macinfo) }
/
SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { (.debug_varnames) }
/
DWARF 3 */
.debug_pubtypes 0 : { *(.debug_pubtypes) }
.debug_ranges 0 : { (.debug_ranges) }
/
DWARF Extension. */
.debug_macro 0 : { (.debug_macro) }
.gnu.attributes 0 : { KEEP (
(.gnu.attributes)) }
/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto
) }
}

==================================================


然后我们修改这个文件:


首先我们需要将默认文件的首尾“==================================================”包含这一行要删除,不然会报格式错误


/usr/bin/ld:test.lds:1: syntax error  
 collect2: error: ld returned 1 exit status


然后选择在“\_\_bss\_start”前添加我们自己的段



. = .;

_init_start = .;/* 获取当前的地址赋值给__init_start,在源码中有使用到,指向“.application_init”段的起始地址 */
.application_init : { (.application_init) }/ 将“.application_init”的所有内容放在这一段 /
_init_end = .;/
获取当前的地址赋值给__init_end,表示“.application_init”段的结束地址 */

__bss_start = .;


 然后我们在*链接*的时候使用一下命令:



seven@root:~/section/$ gcc main.c -Tmain.lds


如无意外的情况下,即可编译出最原始的“a.out”,如果出现错误,请烧香拜佛。



seven@root:~/section$ ./a.out
Load init function from address 0x804a014
execute funtion : application_init_a
Load init function from address 0x804a018
execute funtion : application_init_b
Load init function from address 0x804a01c
execute funtion : application_init_c


可以看到依次的执行了三个初始化函数。



> 
> 注:
> 
> 
> 1. 初始化的宏放置的位置,直接影响初始化函数执行的顺序,同一文件中行号越小越优先。(是注册的顺序,不是函数的位置)
> 2. 多文件中的注册,应该也会存在一定规律,如果初始化顺序有特定的先后顺序的,如需要先初始化GPIO,再初始化LED灯等,则可以采用其他方法进行顺序限定(如优先级值和链表)。
> 3. 在参考的文档中,段的地址貌似可以指定,但是我没有尝试。
> 
> 
> 


## 参考链接


* [gcc \_\_attribute\_\_((section("section\_name"))) 使用方法](https://bbs.youkuaiyun.com/forums/4304bb5a486d4c3ab8389e65ecb71ac0)
* [利用\_\_attribute\_\_((section()))构建初始化函数表](https://bbs.youkuaiyun.com/forums/4304bb5a486d4c3ab8389e65ecb71ac0)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值