说明:本文针对嵌入式开发编写,其他开发可作为参考
创作不易,转载请注明出处,您的点赞、关注+收藏是对开源创作的莫大支持,谢谢!
初始化代码如何做到自动化调用?
在我们开发程序过程中,往往需要对 bsp 部分进行外设配置,以及一些模块、参数进行初始化,比较常见的作法便是:
这种方法比较简单、常用,亦能解决问题,但是此类写法在一些方面仍然存在不足:
那是否有比较完美的方式来解决此问题呢?
答案是肯定的,本文将向大家介绍一种自动初始化的实现方式,注意,此方案在不同的平台,由于链接器使用的链接脚本可能不一致,容易出现问题,需要大家重点注意,细节在下文中将详细介绍。
为了更好的阐述此方案的实现方式,接下来将通过给大家展示一个demo程序,之后对此demo进行细致讲解的方式来阐述此方案的实现,以下是此demo程序:
#include
int a = 0;
int b = 0;
int c = 0;
typedef void (*init_func)(void);
//#define SECTION(x) __attribute__((used, section(x)))
//#define INIT_FUNC(fn, level) const func_test init_##fn SECTION(".duan."#level) = fn
#define INIT_PORT(fn, level) const init_func init_##fn __attribute__((used, section(".init."level))) = fn
void start(void)
{
a = 1;
return;
}
INIT_PORT(start, "1");
void end(void)
{
a = 2;
return;
}
INIT_PORT(end, "3");
void test1(void)
{
b = 1;
}
INIT_PORT(test1, "1");
void test2(void)
{
b = 2;
}
INIT_PORT(test2, "2");
void system_init(void)
{
const init_func *func_p;
for (func_p = &init_start; func_p < &init_end; func_p ++) {
(*func_p)();
}
}
关于宏:#define INIT_PORT(fn, level) const init_func init_##fn __attribute__((used, section(".init."level))) = fn
代码分析如下:
typedef void (*init_func)(void);
,所有初始化函数此指针类型#define INIT_PORT(fn, level)
作为一个接口,后续初始化函数可以通过此接口加入自动初始化列表内
const init_func init_##fn
,其中##
为连接符,假设参数fn
为 test
,则init_##fn
为 init_test
;init_func
为指针类型const init_func init_##fn
与 const int *p
是同一概念,只不过指针类型不一样const init_func init_##fn
定义了一个init_func
类型的指针变量,此指针还没有赋值,因此将参数fn
赋值给此变量,宏定义可以简化为#define INIT_PORT(fn, level) const init_func init_##fn = fn
(__attribute__先忽略)__attribute__((used, section(".init."level)))
这也是一个关键字进行修饰用的,可以拆解为__attribute__((used))
和 __attribute__((section(".init."level)))
__attribute__((used))
用来告诉编译器,此函数如果没有被调用,也不要被优化__attribute__((section(".init."level)))
用来将修饰的内容放入指定的段".init."level
中(编译器在你编译的时候帮你去完成的),注意这里level
为宏的第二个传入参数,传入进来的时候他是一个字符串,所用不用加#
进行拼接,两个字符串会自动拼接综上分析,因此宏#define INIT_PORT(fn, level) const init_func init_##fn __attribute__((used, section(".init."level))) = fn
,其实就是定义了一个init_func
类型的函数指针,并将此函数指针通过__attribute__((section(".init."level)))
指定存放到特定的段内。
Demo程序中定义了四个函数:
void start(void)
void end(void)
void test1(void)
void test2(void)
并分别通过宏INIT_PORT(fn, level)
添加到自动初始化段内
INIT_PORT(start, "1");
INIT_PORT(end, "3");
INIT_PORT(test1, "1");
INIT_PORT(test2, "2");
这里大家注意观察下,有几个注意点:
level
参数是一个字符串,而不是数字test1
和test2
的level
需要在start
和 end
的 level
值中间,这是由于编译器采用__attribute__((section(".init."level)))
指定放入到指定段的时候,还会针对其进行排序,keil默认采用根据名称的方式排序,因此需要放置在用户自定义的,放置在用 start
和 end
中间,方便后续遍历 start
和 end
中间部分进行完整初始化说明下,顺带发现了一个可能出现的bug,
INIT_PORT(test1, "1");
的level
建议不要设置为1
,如果这么设置,在map文件里面排序是按照".init"level
的值进行排序的,那么test1和start的顺序不能百分百确定,虽然这里侥幸没有出问题,但是建议大家不要这么操作
最后看到 system_init
初始化函数
void system_init(void)
{
const init_func *func_p;
for (func_p = &init_start; func_p < &init_end; func_p ++) {
(*func_p)();
}
}
此函数实现的便是通过 for
循环,遍历 start
和 end
中间的段,并进行调用进行初始化
这样用户初始化函数只需要调用宏 INIT_PORT(fn, level)
即可完成自动初始化,当然 system_init
函数肯定是需要在main里面调用的
此方案的好处是将各模块的初始化顺利实现了解耦,不用每个初始化都去动main函数了,此外系统框架类的初始化也可以做到不让业务感知!
针对不同类型的初始化,可以在此基础上稍微改动点,将start和end之间距离拉大点,一部分做外设初始化,一部分做参数初始化,直接挂代码吧
INIT_PORT(start, "1");
INIT_PORT(end, "4");
再对外开放接口宏
#define INIT_BSP_PORT(func) INIT_PORT(func, "2");
#define INIT_DATA_PORT(func) INIT_PORT(func, "3");
用户通过调用 BSP_INIT_PORT
和 DATA_INIT_PORT
进行注册
在上述方法中,我们使用 __attribute__((section(".init."level)))
将数据存入指定的段内,那么是否成功了呢,以及排序方式是否符合我们的预期呢?接下来我们需要通过检查map文件进行确认
keil/mdk编译完程序之后,双击工程栏处的工程,可以查看map文件,还不知道的可以网上搜下
以下是上述demo的map文件中关键字段,我们可以看到我们需要的数据存放在正确的段内,并且排序也是正常的,注意一定要检查排序和字段是否完整!
大家也可以尝试下修改,把 __attribute__((used, section(".init."level)))
修改为 __attribute__(( section(".init."level)))
去掉used
,看看有什么不一样,条件允许的话,还可以单步调试下,看下程序怎么跑的,加深下理解
auto_init.c
源文件:
#include
typedef void (*func_test)(void);
//#define SECTION(x) __attribute__((used, section(x)))
//#define INIT_FUNC(fn, level) const func_test test_##fn SECTION(".duan."#level) = fn
//#define INIT_FUNC(fn, level) const func_test test_##fn __attribute__((used, section(".duan."level))) = fn
#define INIT_FUNC(fn, level) __attribute__((used)) const func_test test_##fn __attribute__((section(".duan."level))) = fn
#define STRING(level) ("string"#level)
//__attribute__((used, section(".duan")))void start(void)
void start(void)
{
printf("start\n");
return;
}
INIT_FUNC(start, "1");
void end(void)
{
return;
}
INIT_FUNC(end, "6");
void test1(void)
{
printf("test1");
}
INIT_FUNC(test1, "1");
void test2(void)
{
printf("test2");
}
INIT_FUNC(test2, "2");
int main()
{
func_test a = NULL;
a = start;
a();
printf("Hello world\n");
return 0;
}
gcc auto_init.c -Wl,-Map=auto_init.map
gcc auto_init.c -Wl,--verbose
生成的Map文件如下:
Archive member included to satisfy reference by file (symbol)
/usr/lib/x86_64-linux-gnu/libc_nonshared.a(elf-init.oS)
/usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o (__libc_csu_init)
Merging program properties
As-needed library included to satisfy reference by file (symbol)
libc.so.6 /tmp/ccDz4GV7.o (puts@@GLIBC_2.2.5)
Discarded input sections
.note.GNU-stack
0x0000000000000000 0x0 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o
.note.gnu.property
0x0000000000000000 0x20 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crti.o
.note.GNU-stack
0x0000000000000000 0x0 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crti.o
.note.GNU-stack
0x0000000000000000 0x0 /usr/lib/gcc/x86_64-linux-gnu/9/crtbeginS.o
.note.gnu.property
0x0000000000000000 0x20 /usr/lib/gcc/x86_64-linux-gnu/9/crtbeginS.o
.note.GNU-stack
0x0000000000000000 0x0 /tmp/ccDz4GV7.o
.note.gnu.property
0x0000000000000000 0x20 /tmp/ccDz4GV7.o
.note.GNU-stack
0x0000000000000000 0x0 /usr/lib/x86_64-linux-gnu/libc_nonshared.a(elf-init.oS)
.note.gnu.property
0x0000000000000000 0x20 /usr/lib/x86_64-linux-gnu/libc_nonshared.a(elf-init.oS)
.note.GNU-stack
0x0000000000000000 0x0 /usr/lib/gcc/x86_64-linux-gnu/9/crtendS.o
.note.gnu.property
0x0000000000000000 0x20 /usr/lib/gcc/x86_64-linux-gnu/9/crtendS.o
.note.gnu.property
0x0000000000000000 0x20 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crtn.o
.note.GNU-stack
0x0000000000000000 0x0 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crtn.o
Memory Configuration
Name Origin Length Attributes
*default* 0x0000000000000000 0xffffffffffffffff
Linker script and memory map
LOAD /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o
LOAD /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crti.o
LOAD /usr/lib/gcc/x86_64-linux-gnu/9/crtbeginS.o
LOAD /tmp/ccDz4GV7.o
LOAD /usr/lib/gcc/x86_64-linux-gnu/9/libgcc.a
LOAD /usr/lib/gcc/x86_64-linux-gnu/9/libgcc_s.so
START GROUP
LOAD /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/libgcc_s.so.1
LOAD /usr/lib/gcc/x86_64-linux-gnu/9/libgcc.a
END GROUP
LOAD /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/libc.so
START GROUP
LOAD /lib/x86_64-linux-gnu/libc.so.6
LOAD /usr/lib/x86_64-linux-gnu/libc_nonshared.a
LOAD /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
END GROUP
LOAD /usr/lib/gcc/x86_64-linux-gnu/9/libgcc.a
LOAD /usr/lib/gcc/x86_64-linux-gnu/9/libgcc_s.so
START GROUP
LOAD /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/libgcc_s.so.1
LOAD /usr/lib/gcc/x86_64-linux-gnu/9/libgcc.a
END GROUP
LOAD /usr/lib/gcc/x86_64-linux-gnu/9/crtendS.o
LOAD /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crtn.o
[!provide] PROVIDE (__executable_start = SEGMENT_START ("text-segment", 0x0))
0x0000000000000318 . = (SEGMENT_START ("text-segment", 0x0) + SIZEOF_HEADERS)
.interp 0x0000000000000318 0x1c
*(.interp)
.interp 0x0000000000000318 0x1c /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o
.note.gnu.property
0x0000000000000338 0x20
.note.gnu.property
0x0000000000000338 0x20 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o
.note.gnu.build-id
0x0000000000000358 0x24
*(.note.gnu.build-id)
.note.gnu.build-id
0x0000000000000358 0x24 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o
.note.ABI-tag 0x000000000000037c 0x20
.note.ABI-tag 0x000000000000037c 0x20 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o
.hash
*(.hash)
.gnu.hash 0x00000000000003a0 0x24
*(.gnu.hash)
.gnu.hash 0x00000000000003a0 0x24 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o
.dynsym 0x00000000000003c8 0xc0
*(.dynsym)
.dynsym 0x00000000000003c8 0xc0 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o
.dynstr 0x0000000000000488 0x89
*(.dynstr)
.dynstr 0x0000000000000488 0x89 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o
.gnu.version 0x0000000000000512 0x10
*(.gnu.version)
.gnu.version 0x0000000000000512 0x10 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o
.gnu.version_d 0x0000000000000528 0x0
*(.gnu.version_d)
.gnu.version_d
0x0000000000000528 0x0 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o
.gnu.version_r 0x0000000000000528 0x20
*(.gnu.version_r)
.gnu.version_r
0x0000000000000528 0x20 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o
.rela.dyn 0x0000000000000548 0x120
*(.rela.init)
*(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
.rela.text 0x0000000000000548 0x0 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o
*(.rela.fini)
*(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
*(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
.rela.data.rel.ro
0x0000000000000548 0x0 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o
.rela.data.rel.local
0x0000000000000548 0x18 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o
*(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
*(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
*(.rela.ctors)
*(.rela.dtors)
*(.rela.got)
.rela.got 0x0000000000000560 0x78 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o
*(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
.rela.bss 0x00000000000005d8 0x0 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o
*(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.*)
*(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*)
*(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*)
*(.rela.ifunc)
.rela.ifunc 0x00000000000005d8 0x0 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o
.rela.fini_array
0x00000000000005d8 0x18 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o
.rela.init_array
0x00000000000005f0 0x18 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o
.rela.duan.1 0x0000000000000608 0x30 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o
.rela.duan.6 0x0000000000000638 0x18 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o
.rela.duan.2 0x0000000000000650 0x18 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o
.rela.plt 0x0000000000000668 0x30
*(.rela.plt)
.rela.plt 0x0000000000000668 0x30 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o
*(.rela.iplt)
0x0000000000001000 . = ALIGN (CONSTANT (MAXPAGESIZE))
.init 0x0000000000001000 0x1b
*(SORT_NONE(.init))
.init 0x0000000000001000 0x16 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crti.o
0x0000000000001000 _init
.init 0x0000000000001016 0x5 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crtn.o
.plt 0x0000000000001020 0x30
*(.plt)
.plt 0x0000000000001020 0x30 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o
*(.iplt)
.plt.got 0x0000000000001050 0x10
*(.plt.got)
.plt.got 0x0000000000001050 0x10 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o
0x0000000000001050 __cxa_finalize@@GLIBC_2.2.5
.plt.sec 0x0000000000001060 0x20
*(.plt.sec)
.plt.sec 0x0000000000001060 0x20 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o
0x0000000000001060 puts@@GLIBC_2.2.5
0x0000000000001070 printf@@GLIBC_2.2.5
.text 0x0000000000001080 0x1f5
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
*(.text.exit .text.exit.*)
*(.text.startup .text.startup.*)
*(.text.hot .text.hot.*)
*(SORT_BY_NAME(.text.sorted.*))
*(.text .stub .text.* .gnu.linkonce.t.*)
.text 0x0000000000001080 0x2f /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o
0x0000000000001080 _start
.text 0x00000000000010af 0x0 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crti.o
*fill* 0x00000000000010af 0x1
.text 0x00000000000010b0 0xb9 /usr/lib/gcc/x86_64-linux-gnu/9/crtbeginS.o
.text 0x0000000000001169 0x92 /tmp/ccDz4GV7.o
0x0000000000001169 start
0x0000000000001180 end
0x000000000000118b test1
0x00000000000011a7 test2
0x00000000000011c3 main
*fill* 0x00000000000011fb 0x5
.text 0x0000000000001200 0x75 /usr/lib/x86_64-linux-gnu/libc_nonshared.a(elf-init.oS)
0x0000000000001200 __libc_csu_init
0x0000000000001270 __libc_csu_fini
.text 0x0000000000001275 0x0 /usr/lib/gcc/x86_64-linux-gnu/9/crtendS.o
.text 0x0000000000001275 0x0 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crtn.o
*(.gnu.warning)
.fini 0x0000000000001278 0xd
*(SORT_NONE(.fini))
.fini 0x0000000000001278 0x8 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crti.o
0x0000000000001278 _fini
.fini 0x0000000000001280 0x5 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crtn.o
[!provide] PROVIDE (__etext = .)
[!provide] PROVIDE (_etext = .)
[!provide] PROVIDE (etext = .)
0x0000000000002000 . = ALIGN (CONSTANT (MAXPAGESIZE))
0x0000000000002000 . = SEGMENT_START ("rodata-segment", (ALIGN (CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 0x1))))
.rodata 0x0000000000002000 0x22
*(.rodata .rodata.* .gnu.linkonce.r.*)
.rodata.cst4 0x0000000000002000 0x4 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o
0x0000000000002000 _IO_stdin_used
.rodata 0x0000000000002004 0x1e /tmp/ccDz4GV7.o
.rodata1
*(.rodata1)
.eh_frame_hdr 0x0000000000002024 0x64
*(.eh_frame_hdr)
.eh_frame_hdr 0x0000000000002024 0x64 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o
0x0000000000002024 __GNU_EH_FRAME_HDR
*(.eh_frame_entry .eh_frame_entry.*)
.eh_frame 0x0000000000002088 0x188
*(.eh_frame)
.eh_frame 0x0000000000002088 0x30 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o
0x2c (size before relaxing)
*fill* 0x00000000000020b8 0x0
.eh_frame 0x00000000000020b8 0x28 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o
0x40 (size before relaxing)
.eh_frame 0x00000000000020e0 0x18 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o
0x30 (size before relaxing)
.eh_frame 0x00000000000020f8 0x18 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o
0x30 (size before relaxing)
.eh_frame 0x0000000000002110 0xa0 /tmp/ccDz4GV7.o
0xb8 (size before relaxing)
.eh_frame 0x00000000000021b0 0x5c /usr/lib/x86_64-linux-gnu/libc_nonshared.a(elf-init.oS)
0x78 (size before relaxing)
.eh_frame 0x000000000000220c 0x4 /usr/lib/gcc/x86_64-linux-gnu/9/crtendS.o
*(.eh_frame.*)
.gcc_except_table
*(.gcc_except_table .gcc_except_table.*)
.gnu_extab
*(.gnu_extab*)
.exception_ranges
*(.exception_ranges*)
0x0000000000003db0 . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE))
.eh_frame
*(.eh_frame)
*(.eh_frame.*)
.gnu_extab
*(.gnu_extab)
.gcc_except_table
*(.gcc_except_table .gcc_except_table.*)
.exception_ranges
*(.exception_ranges*)
.tdata 0x0000000000003db0 0x0
[!provide] PROVIDE (__tdata_start = .)
*(.tdata .tdata.* .gnu.linkonce.td.*)
.tbss
*(.tbss .tbss.* .gnu.linkonce.tb.*)
*(.tcommon)
.preinit_array 0x0000000000003db0 0x0
[!provide] PROVIDE (__preinit_array_start = .)
*(.preinit_array)
[!provide] PROVIDE (__preinit_array_end = .)
.init_array 0x0000000000003db0 0x8
0x0000000000003db0 PROVIDE (__init_array_start = .)
*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))
*(.init_array EXCLUDE_FILE(*crtend?.o *crtend.o *crtbegin?.o *crtbegin.o) .ctors)
.init_array 0x0000000000003db0 0x8 /usr/lib/gcc/x86_64-linux-gnu/9/crtbeginS.o
0x0000000000003db8 PROVIDE (__init_array_end = .)
.fini_array 0x0000000000003db8 0x8
[!provide] PROVIDE (__fini_array_start = .)
*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))
*(.fini_array EXCLUDE_FILE(*crtend?.o *crtend.o *crtbegin?.o *crtbegin.o) .dtors)
.fini_array 0x0000000000003db8 0x8 /usr/lib/gcc/x86_64-linux-gnu/9/crtbeginS.o
[!provide] PROVIDE (__fini_array_end = .)
.ctors
*crtbegin.o(.ctors)
*crtbegin?.o(.ctors)
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
*(SORT_BY_NAME(.ctors.*))
*(.ctors)
.dtors
*crtbegin.o(.dtors)
*crtbegin?.o(.dtors)
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
*(SORT_BY_NAME(.dtors.*))
*(.dtors)
.jcr
*(.jcr)
.data.rel.ro 0x0000000000003dc0 0x0
*(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*)
*(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*)
.data.rel.ro 0x0000000000003dc0 0x0 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o
.dynamic 0x0000000000003dc0 0x1f0
*(.dynamic)
.dynamic 0x0000000000003dc0 0x1f0 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o
0x0000000000003dc0 _DYNAMIC
.got 0x0000000000003fb0 0x50
*(.got.plt)
.got.plt 0x0000000000003fb0 0x28 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o
0x0000000000003fb0 _GLOBAL_OFFSET_TABLE_
*(.igot.plt)
*(.got)
.got 0x0000000000003fd8 0x28 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o
*(.igot)
0x0000000000004000 . = DATA_SEGMENT_RELRO_END (., 0x0)
.data 0x0000000000004000 0x10
*(.data .data.* .gnu.linkonce.d.*)
.data 0x0000000000004000 0x4 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o
0x0000000000004000 data_start
0x0000000000004000 __data_start
.data 0x0000000000004004 0x0 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crti.o
.data 0x0000000000004004 0x0 /usr/lib/gcc/x86_64-linux-gnu/9/crtbeginS.o
*fill* 0x0000000000004004 0x4
.data.rel.local
0x0000000000004008 0x8 /usr/lib/gcc/x86_64-linux-gnu/9/crtbeginS.o
0x0000000000004008 __dso_handle
.data 0x0000000000004010 0x0 /tmp/ccDz4GV7.o
.data 0x0000000000004010 0x0 /usr/lib/x86_64-linux-gnu/libc_nonshared.a(elf-init.oS)
.data 0x0000000000004010 0x0 /usr/lib/gcc/x86_64-linux-gnu/9/crtendS.o
.data 0x0000000000004010 0x0 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crtn.o
.tm_clone_table
0x0000000000004010 0x0
.tm_clone_table
0x0000000000004010 0x0 /usr/lib/gcc/x86_64-linux-gnu/9/crtbeginS.o
.tm_clone_table
0x0000000000004010 0x0 /usr/lib/gcc/x86_64-linux-gnu/9/crtendS.o
.duan.1 0x0000000000004010 0x10
.duan.1 0x0000000000004010 0x10 /tmp/ccDz4GV7.o
0x0000000000004010 test_start
0x0000000000004018 test_test1
.duan.6 0x0000000000004020 0x8
.duan.6 0x0000000000004020 0x8 /tmp/ccDz4GV7.o
0x0000000000004020 test_end
.duan.2 0x0000000000004028 0x8
.duan.2 0x0000000000004028 0x8 /tmp/ccDz4GV7.o
0x0000000000004028 test_test2
.data1
*(.data1)
0x0000000000004030 _edata = .
[!provide] PROVIDE (edata = .)
0x0000000000004030 . = .
0x0000000000004030 __bss_start = .
.bss 0x0000000000004030 0x8
*(.dynbss)
.dynbss 0x0000000000004030 0x0 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o
*(.bss .bss.* .gnu.linkonce.b.*)
.bss 0x0000000000004030 0x0 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o
.bss 0x0000000000004030 0x0 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crti.o
.bss 0x0000000000004030 0x1 /usr/lib/gcc/x86_64-linux-gnu/9/crtbeginS.o
.bss 0x0000000000004031 0x0 /tmp/ccDz4GV7.o
.bss 0x0000000000004031 0x0 /usr/lib/x86_64-linux-gnu/libc_nonshared.a(elf-init.oS)
.bss 0x0000000000004031 0x0 /usr/lib/gcc/x86_64-linux-gnu/9/crtendS.o
.bss 0x0000000000004031 0x0 /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crtn.o
*(COMMON)
0x0000000000004038 . = ALIGN ((. != 0x0)?0x8:0x1)
*fill* 0x0000000000004031 0x7
.lbss
*(.dynlbss)
*(.lbss .lbss.* .gnu.linkonce.lb.*)
*(LARGE_COMMON)
0x0000000000004038 . = ALIGN (0x8)
0x0000000000004038 . = SEGMENT_START ("ldata-segment", .)
.lrodata
*(.lrodata .lrodata.* .gnu.linkonce.lr.*)
.ldata 0x0000000000006038 0x0
*(.ldata .ldata.* .gnu.linkonce.l.*)
0x0000000000006038 . = ALIGN ((. != 0x0)?0x8:0x1)
0x0000000000006038 . = ALIGN (0x8)
0x0000000000004038 _end = .
[!provide] PROVIDE (end = .)
0x0000000000006038 . = DATA_SEGMENT_END (.)
.stab
*(.stab)
.stabstr
*(.stabstr)
.stab.excl
*(.stab.excl)
.stab.exclstr
*(.stab.exclstr)
.stab.index
*(.stab.index)
.stab.indexstr
*(.stab.indexstr)
.comment 0x0000000000000000 0x2b
*(.comment)
.comment 0x0000000000000000 0x2b /usr/lib/gcc/x86_64-linux-gnu/9/crtbeginS.o
0x2c (size before relaxing)
.comment 0x000000000000002b 0x2c /tmp/ccDz4GV7.o
.comment 0x000000000000002b 0x2c /usr/lib/gcc/x86_64-linux-gnu/9/crtendS.o
.gnu.build.attributes
*(.gnu.build.attributes .gnu.build.attributes.*)
.debug
*(.debug)
.line
*(.line)
.debug_srcinfo
*(.debug_srcinfo)
.debug_sfnames
*(.debug_sfnames)
.debug_aranges
*(.debug_aranges)
.debug_pubnames
*(.debug_pubnames)
.debug_info
*(.debug_info .gnu.linkonce.wi.*)
.debug_abbrev
*(.debug_abbrev)
.debug_line
*(.debug_line .debug_line.* .debug_line_end)
.debug_frame
*(.debug_frame)
.debug_str
*(.debug_str)
.debug_loc
*(.debug_loc)
.debug_macinfo
*(.debug_macinfo)
.debug_weaknames
*(.debug_weaknames)
.debug_funcnames
*(.debug_funcnames)
.debug_typenames
*(.debug_typenames)
.debug_varnames
*(.debug_varnames)
.debug_pubtypes
*(.debug_pubtypes)
.debug_ranges
*(.debug_ranges)
.debug_macro
*(.debug_macro)
.debug_addr
*(.debug_addr)
.gnu.attributes
*(.gnu.attributes)
/DISCARD/
*(.note.GNU-stack)
*(.gnu_debuglink)
*(.gnu.lto_*)
OUTPUT(a.out elf64-x86-64)
检查上述map文件,我们可以发现段 段排序和Keil采用的方式不一样,因此在gcc环境下直接使用会存在问题
这是由于采用gcc编译.c文件时,默认通过链接文件生成链接脚本,生成的这个链接脚本,对于数据段采用的排序方式未采用按照名称排序的方式,我们可以通过指令查看采用的gcc auto_init.c -Wl,--verbose
链接脚本内容,如下所示:
GNU ld (GNU Binutils for Ubuntu) 2.34
Supported emulations:
elf_x86_64
elf32_x86_64
elf_i386
elf_iamcu
elf_l1om
elf_k1om
i386pep
i386pe
using internal linker script:
==================================================
/* Script for -pie -z combreloc -z separate-code -z relro -z now */
/* Copyright (C) 2014-2020 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("elf64-x86-64", "elf64-x86-64",
"elf64-x86-64")
OUTPUT_ARCH(i386:x86-64)
ENTRY(_start)
SEARCH_DIR("=/usr/local/lib/x86_64-linux-gnu"); SEARCH_DIR("=/lib/x86_64-linux-gnu"); SEARCH_DIR("=/usr/lib/x86_64-linux-gnu"); SEARCH_DIR("=/usr/lib/x86_64-linux-gnu64"); SEARCH_DIR("=/usr/local/lib64"); SEARCH_DIR("=/lib64"); SEARCH_DIR("=/usr/lib64"); SEARCH_DIR("=/usr/local/lib"); SEARCH_DIR("=/lib"); SEARCH_DIR("=/usr/lib"); SEARCH_DIR("=/usr/x86_64-linux-gnu/lib64"); SEARCH_DIR("=/usr/x86_64-linux-gnu/lib");
SECTIONS
{
PROVIDE (__executable_start = SEGMENT_START("text-segment", 0)); . = SEGMENT_START("text-segment", 0) + 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) }
.rela.dyn :
{
*(.rela.init)
*(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
*(.rela.fini)
*(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
*(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
*(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
*(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
*(.rela.ctors)
*(.rela.dtors)
*(.rela.got)
*(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
*(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.*)
*(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*)
*(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*)
*(.rela.ifunc)
}
.rela.plt :
{
*(.rela.plt)
*(.rela.iplt)
}
. = ALIGN(CONSTANT (MAXPAGESIZE));
.init :
{
KEEP (*(SORT_NONE(.init)))
}
.plt : { *(.plt) *(.iplt) }
.plt.got : { *(.plt.got) }
.plt.sec : { *(.plt.sec) }
.text :
{
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
*(.text.exit .text.exit.*)
*(.text.startup .text.startup.*)
*(.text.hot .text.hot.*)
*(SORT(.text.sorted.*))
*(.text .stub .text.* .gnu.linkonce.t.*)
/* .gnu.warning sections are handled specially by elf.em. */
*(.gnu.warning)
}
.fini :
{
KEEP (*(SORT_NONE(.fini)))
}
PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
. = ALIGN(CONSTANT (MAXPAGESIZE));
/* Adjust the address for the rodata segment. We want to adjust up to
the same address within the page on the next page up. */
. = SEGMENT_START("rodata-segment", ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)));
.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*) }
/* 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*) }
/* Thread Local Storage sections */
.tdata :
{
PROVIDE_HIDDEN (__tdata_start = .);
*(.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.plt) *(.igot.plt) *(.got) *(.igot) }
. = DATA_SEGMENT_RELRO_END (0, .);
.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 do not
pad the .data section. */
. = ALIGN(. != 0 ? 64 / 8 : 1);
}
.lbss :
{
*(.dynlbss)
*(.lbss .lbss.* .gnu.linkonce.lb.*)
*(LARGE_COMMON)
}
. = ALIGN(64 / 8);
. = SEGMENT_START("ldata-segment", .);
.lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
{
*(.lrodata .lrodata.* .gnu.linkonce.lr.*)
}
.ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
{
*(.ldata .ldata.* .gnu.linkonce.l.*)
. = ALIGN(. != 0 ? 64 / 8 : 1);
}
. = ALIGN(64 / 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) }
.gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) }
/* 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) }
.debug_addr 0 : { *(.debug_addr) }
.gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }
}
==================================================
/usr/bin/ld: mode elf_x86_64
attempt to open /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o succeeded
/usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o
attempt to open /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crti.o succeeded
/usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crti.o
attempt to open /usr/lib/gcc/x86_64-linux-gnu/9/crtbeginS.o succeeded
/usr/lib/gcc/x86_64-linux-gnu/9/crtbeginS.o
attempt to open /tmp/cc86xswz.o succeeded
/tmp/cc86xswz.o
attempt to open /usr/lib/gcc/x86_64-linux-gnu/9/libgcc.so failed
attempt to open /usr/lib/gcc/x86_64-linux-gnu/9/libgcc.a succeeded
/usr/lib/gcc/x86_64-linux-gnu/9/libgcc.a
attempt to open /usr/lib/gcc/x86_64-linux-gnu/9/libgcc_s.so succeeded
opened script file /usr/lib/gcc/x86_64-linux-gnu/9/libgcc_s.so
/usr/lib/gcc/x86_64-linux-gnu/9/libgcc_s.so
opened script file /usr/lib/gcc/x86_64-linux-gnu/9/libgcc_s.so
attempt to open libgcc_s.so.1 failed
attempt to open /usr/lib/gcc/x86_64-linux-gnu/9/libgcc_s.so.1 failed
attempt to open /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/libgcc_s.so.1 succeeded
/usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/libgcc_s.so.1
attempt to open /usr/lib/gcc/x86_64-linux-gnu/9/libgcc.so failed
attempt to open /usr/lib/gcc/x86_64-linux-gnu/9/libgcc.a succeeded
/usr/lib/gcc/x86_64-linux-gnu/9/libgcc.a
attempt to open /usr/lib/gcc/x86_64-linux-gnu/9/libc.so failed
attempt to open /usr/lib/gcc/x86_64-linux-gnu/9/libc.a failed
attempt to open /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/libc.so succeeded
opened script file /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/libc.so
/usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/libc.so
opened script file /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/libc.so
attempt to open /lib/x86_64-linux-gnu/libc.so.6 succeeded
/lib/x86_64-linux-gnu/libc.so.6
attempt to open /usr/lib/x86_64-linux-gnu/libc_nonshared.a succeeded
/usr/lib/x86_64-linux-gnu/libc_nonshared.a
(/usr/lib/x86_64-linux-gnu/libc_nonshared.a)elf-init.oS
attempt to open /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 succeeded
/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
/usr/lib/x86_64-linux-gnu/libc_nonshared.a
/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
attempt to open /usr/lib/gcc/x86_64-linux-gnu/9/libgcc.so failed
attempt to open /usr/lib/gcc/x86_64-linux-gnu/9/libgcc.a succeeded
/usr/lib/gcc/x86_64-linux-gnu/9/libgcc.a
attempt to open /usr/lib/gcc/x86_64-linux-gnu/9/libgcc_s.so succeeded
opened script file /usr/lib/gcc/x86_64-linux-gnu/9/libgcc_s.so
/usr/lib/gcc/x86_64-linux-gnu/9/libgcc_s.so
opened script file /usr/lib/gcc/x86_64-linux-gnu/9/libgcc_s.so
attempt to open libgcc_s.so.1 failed
attempt to open /usr/lib/gcc/x86_64-linux-gnu/9/libgcc_s.so.1 failed
attempt to open /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/libgcc_s.so.1 succeeded
/usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/libgcc_s.so.1
attempt to open /usr/lib/gcc/x86_64-linux-gnu/9/libgcc.so failed
attempt to open /usr/lib/gcc/x86_64-linux-gnu/9/libgcc.a succeeded
/usr/lib/gcc/x86_64-linux-gnu/9/libgcc.a
attempt to open /usr/lib/gcc/x86_64-linux-gnu/9/crtendS.o succeeded
/usr/lib/gcc/x86_64-linux-gnu/9/crtendS.o
attempt to open /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crtn.o succeeded
/usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crtn.o
ld-linux-x86-64.so.2 needed by /lib/x86_64-linux-gnu/libc.so.6
found ld-linux-x86-64.so.2 at /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
关键描述字段如下:
其中 text 段由于配置了*(SORT(.text.sorted.*))
,因此采用了按名称排序的方式,而 data 段没有采用此排序方式,而我们定义的函数指针实际上是存放在data数据段,所以才会出现上述问题
如果要实现data段也采用按照名称大小的排序方式,大家可以将此链接脚本保存在工程路径下,之后修改.data段的描述,之后gcc编译的时候指定此链接脚本即可
定义宏的时候注意 const int *p
与 int *const p
的区别:
const int *p
const修饰的是int *p
,表明指针指向的对象不可以修改,但是指针可以修改,称之为指针常量int *const p
const修饰的是p
,表明指针不可以修改,但是指向的内容可以被修改,称之为常量指针const int *p
和 int const *p
一致参考RT-thread内核代码初始化设计,如果大家直接上手rtthread的自动初始化部分代码,可能会是一头雾水,那么现在再去看应该就很清楚了哈