如何使用gcc的__attribute__((section (__sect__)))

        __attribute__((section("section_name")))其作用是将作用的函数或数据放入指定名为"section_name"输入段。

这里还要注意一下两个概念:输入段和输出段

        输入段和输出段是相对于要生成最终的elf或binary时的Link过程说的,Link过程的输入大都是由源代码编绎生成的目标文件.o,那么这些.o文件中包含的段相对link过程来说就是输入段,而Link的输出一般是可执行文件elf或库等,这些输出文件中也包含有段,这些输出文件中的段就叫做输出段。输入段和输出段本来没有什么必然的联系,是互相独立,只是在Link过程中,Link程序会根据一定的规则(这些规则其实来源于Link Script),将不同的输入段重新组合到不同的输出段中,即使是段的名字,输入段和输出段可以完全不同。

我们今天会讲的是section的一种用法。这种用法是,将一些函数或者自定义格式的变量放在自己指定的段中(section),然后在程序中获取出来使用。

        这种用法是实例有Linux内核驱动module_init一下就好了的原因就是把程序放在了指定的section里面,到指定的地方取出来用就行了;还有就是有些程序架构里的初始化话,也是将要初始化的函数放当指定的section里面,在初始化时逐一取出来调用就可以了。这样做就是当新添加和删除模块的初始化的时候,不用动main函数。把对应的函数新添加或取消添加进指定的section就行了。

    废话一堆,一句没听懂。不如实操一下。我是在这里学到的,谢谢博主

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

void want_money(void)
{
	printf ("i want a lots of money, but...\n");
}

void want_power(void)
{
	printf ("i want power to change the world, but...\n");
}

void want_woman(void)
{
	printf ("i want a lots of women,but...\n");
}


typedef void (* init_func_yp)(void);

#define _my_section     __attribute__((unused, section(".myinit")))

#define PUT_INTO_SECTION(func)   init_func_yp     _fn_##func    _my_section = func


/* 定义3个变量,然后放在myinit section中 */
PUT_INTO_SECTION(want_money);
PUT_INTO_SECTION(want_power);
PUT_INTO_SECTION(want_woman);

/* 在链接脚本中定义 */
extern init_func_yp __init_start;
extern init_func_yp __init_end;


int main(int argc, char** argv)
{
	init_func_yp* tmp = &__init_start;
	for ( ; tmp < &__init_end; tmp++){
		printf("init address: %p\n", tmp);
		(*tmp)();
	}
	return 0;
}


具体操作如下:

1)准备连接脚本xxxx.lds

ld --verbose > script.lds
vi script.lds

1)删除script.lds中下面内容,==============也需要删除
GNU ld (GNU Binutils for Ubuntu) 2.30
  Supported emulations:
   elf_x86_64
   elf32_x86_64
   elf_i386
   elf_iamcu
   i386linux
   elf_l1om
   elf_k1om
   i386pep
   i386pe
using internal linker script:
==================================================



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

2)增加script.lds里面的我们自定义的内容,加在__bss_start =.;上面。所以下面只需要添加前3行。
  __init_start = .;
  .myinit : {*(.myinit)}
  __init_end = .;
  __bss_start = .;

3)保存

2)编译开始

gcc -c example.c -o example.o

编译出来的example.o就有一个 myinit的段

3)连接一下

gcc -T script.lds example.o -o example

 4)运行一下

就这么愉快的成功了。

    师傅领进门,修为看个人,操作了一下后 可以重新理解一下输入段和输出段这个概念。

二)补充一个骚操作

    就是利用c++类的构造函数,再配合__attribute__((init_priority(_pri_)))一起来实现自动初始化的目的。骚的不行。

#define CYGBLD_ATTRIB_INIT_PRI( _pri_ ) __attribute__((init_priority(_pri_)))
#define CYGBLD_ATTRIB_INIT_AFTER( _pri_ )  CYGBLD_ATTRIB_INIT_PRI(_pri_+100)
#define NET_INIT CYGBLD_ATTRIB_INIT_AFTER(CYG_INIT_LIBC)
void
cyg_net_init(void)
{
    static int _init = false;
    cyg_netdevtab_entry_t *t;
    if (_init) return;
    cyg_do_net_init();  // Just forces linking in the initializer/constructor
    // Initialize interrupt "flags"
    cyg_flag_init(&netint_flags);
    // Done
    _init = true;
}

void cyg_net_init(void);

class net_init_class {
public:
    net_init_class(void) { 
        cyg_net_init();
    }
};
// And here's an instance of the class just to make the code run
static net_init_class _net_init NET_INIT;

    GNU C ++允许用户控制对象初始化的顺序 在命名空间范围中使用`init_priority'属性定义 指定相对PRIORITY,一个常数整数表达式目前约在101和65535之间。较低的数字表示较高的优先级。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值