__attribute__のsectionの詳細
15902 ワード
前言
最初に「section」に触れたのは、会社のSTM 32のプロジェクトコードで、元エンジニアがすべての初期化関数で使用する「section」に属性を設定したものです.その目的は分かっていたが、原因は分からなかった.その後Linuxのドライバに触れたところ、linuxのドライバ登録のマクロ定義の階層解析以降も使用されている「section」が修飾されていることが判明したが、当時は教程を見てメモリの特定の位置に限定しなければならないと考え、経験不足であったため、深く研究しなかった.しかし今Linuxアプリを書いていると、SDKでも「section」を使ってプログラムの修飾をしていることに気づき、何時間もかけていろいろなフォーラムを調べて、比較的深く勉強したのではないでしょうか.
sectionを使用すると、関数を初期化するときに、メイン関数に新しい初期化プログラムを追加する必要がなく、自分の関数モジュールに登録するだけでいいです.あるいは、いくつかのコマンドを実装するときに、そのコマンドのサポートを追加または削除すると便利です.
使用方法
「section」キーは、物理メモリ上の特定の場所ではなく、実行可能なファイルの特定のセグメント内に修飾された変数または関数を特定の場所にコンパイルします.コンパイルされたプログラムでは、コマンドを使用できます.
以上のように、プログラムは多くのセグメントに分けられており、「.アプリケーション_init」は後述するステップでカスタマイズされたセグメントである.
テストソースコードは次のとおりです.
次にldsファイルを作成し、まずコマンドを使用してデフォルトのファイルを生成する必要があります.
このファイルを変更します.
まず、デフォルトファイルの先頭と末尾の「==========================================================================================
/usr/bin/ld:test.lds:1: syntax error collect2: error: ld returned 1 exit status
次に「_bss_start」の前に自分のセグメントを追加することを選択します.
リンクするときにコマンドを使用します.
意外なことがなければ、最も原始的な「a.out」をコンパイルすることができ、エラーが発生した場合は、お線香をあげて仏を拝んでください.
3つの初期化関数が順次実行されていることがわかります.
注意:初期化されたマクロの配置位置は、初期化関数の実行順序に直接影響し、同じファイルの行番号が小さいほど優先されます.(登録の順序であり、関数の位置ではない) マルチファイルの登録にも一定の法則があるはずですが、初期化順序に特定の前後順序がある場合、GPIOを初期化してからLEDランプを初期化する必要がある場合などは、他の方法で順序限定(優先度値やチェーンテーブルなど)を行うことができます. 参照ドキュメントでは、セグメントのアドレスを指定できるようですが、試していません.
リファレンスリンク gcc __attribute__((section(「section_name」)使用方法 利用_attribute__(section()構築初期化関数テーブル
最初に「section」に触れたのは、会社のSTM 32のプロジェクトコードで、元エンジニアがすべての初期化関数で使用する「section」に属性を設定したものです.その目的は分かっていたが、原因は分からなかった.その後Linuxのドライバに触れたところ、linuxのドライバ登録のマクロ定義の階層解析以降も使用されている「section」が修飾されていることが判明したが、当時は教程を見てメモリの特定の位置に限定しなければならないと考え、経験不足であったため、深く研究しなかった.しかし今Linuxアプリを書いていると、SDKでも「section」を使ってプログラムの修飾をしていることに気づき、何時間もかけていろいろなフォーラムを調べて、比較的深く勉強したのではないでしょうか.
sectionを使用すると、関数を初期化するときに、メイン関数に新しい初期化プログラムを追加する必要がなく、自分の関数モジュールに登録するだけでいいです.あるいは、いくつかのコマンドを実装するときに、そのコマンドのサポートを追加または削除すると便利です.
使用方法
「section」キーは、物理メモリ上の特定の場所ではなく、実行可能なファイルの特定のセグメント内に修飾された変数または関数を特定の場所にコンパイルします.コンパイルされたプログラムでは、コマンドを使用できます.
seven@root:~/section/$ readelf -S a.out
There are 37 section headers, starting at offset 0x201c:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .interp PROGBITS 08048154 000154 000013 00 A 0 0 1
[ 2] .note.ABI-tag NOTE 08048168 000168 000020 00 A 0 0 4
[ 3] .note.gnu.build-i NOTE 08048188 000188 000024 00 A 0 0 4
[ 4] .gnu.hash GNU_HASH 080481ac 0001ac 00002c 04 A 5 0 4
[ 5] .dynsym DYNSYM 080481d8 0001d8 000050 10 A 6 1 4
[ 6] .dynstr STRTAB 08048228 000228 00004c 00 A 0 0 1
[ 7] .gnu.version VERSYM 08048274 000274 00000a 02 A 5 0 2
[ 8] .gnu.version_r VERNEED 08048280 000280 000020 00 A 6 1 4
[ 9] .rel.dyn REL 080482a0 0002a0 000018 08 A 5 0 4
[10] .init PROGBITS 080482b8 0002b8 000023 00 AX 0 0 4
[11] .plt PROGBITS 080482e0 0002e0 000010 04 AX 0 0 16
[12] .plt.got PROGBITS 080482f0 0002f0 000018 00 AX 0 0 8
[13] .text PROGBITS 08048310 000310 000212 00 AX 0 0 16
[14] .fini PROGBITS 08048524 000524 000014 00 AX 0 0 4
[15] .rodata PROGBITS 08048538 000538 00007f 00 A 0 0 4
[16] .eh_frame_hdr PROGBITS 080485b8 0005b8 000044 00 A 0 0 4
[17] .eh_frame PROGBITS 080485fc 0005fc 00012c 00 A 0 0 4
[18] .init_array INIT_ARRAY 08049f08 000f08 000004 00 WA 0 0 4
[19] .fini_array FINI_ARRAY 08049f0c 000f0c 000004 00 WA 0 0 4
[20] .jcr PROGBITS 08049f10 000f10 000004 00 WA 0 0 4
[21] .dynamic DYNAMIC 08049f14 000f14 0000e0 08 WA 6 0 4
[22] .got PROGBITS 08049ff4 000ff4 00000c 04 WA 0 0 4
[23] .got.plt PROGBITS 0804a000 001000 00000c 04 WA 0 0 4
[24] .data PROGBITS 0804a00c 00100c 000008 00 WA 0 0 4
[25] .application_init PROGBITS 0804a014 001014 00000c 00 WA 0 0 4
[26] .bss NOBITS 0804a020 001020 000004 00 WA 0 0 1
[27] .comment PROGBITS 00000000 001020 000035 01 MS 0 0 1
[28] .debug_aranges PROGBITS 00000000 001055 000020 00 0 0 1
[29] .debug_info PROGBITS 00000000 001075 000200 00 0 0 1
[30] .debug_abbrev PROGBITS 00000000 001275 0000e3 00 0 0 1
[31] .debug_line PROGBITS 00000000 001358 000079 00 0 0 1
[32] .debug_str PROGBITS 00000000 0013d1 0001c9 01 MS 0 0 1
[33] .debug_loc PROGBITS 00000000 00159a 0000f1 00 0 0 1
[34] .shstrtab STRTAB 00000000 001ebd 00015e 00 0 0 1
[35] .symtab SYMTAB 00000000 00168c 000560 10 36 59 4
[36] .strtab STRTAB 00000000 001bec 0002d1 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings)
I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
O (extra OS processing required) o (OS specific), p (processor specific)
以上のように、プログラムは多くのセグメントに分けられており、「.アプリケーション_init」は後述するステップでカスタマイズされたセグメントである.
テストソースコードは次のとおりです.
#include
#include
struct _s_application_init {
int(*function)(void);
};
struct _s_application_init _init_start;// ".application_init" , *.lds
struct _s_application_init _init_end;// ".application_init" , *.lds
#define __app_init_section __attribute__((section(".application_init")))
#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
", __FUNCTION__);
return 0;
}
__application_init(application_init_a);
static int application_init_b(void)
{
printf("execute funtion : %s
", __FUNCTION__);
return 0;
}
__application_init(application_init_b);
static int application_init_c(void)
{
printf("execute funtion : %s
", __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
", 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 (C) 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
3つの初期化関数が順次実行されていることがわかります.
注意:
リファレンスリンク