attribute的section属性

官方文档

Normally, the compiler places the objects it generates in sectionslike data and bss. Sometimes, however, you need additional sections,or you need certain particular variables to appear in specialsections, for example to map to special hardware. The section attribute specifies that a variable (or function) lives in a particular section.

通常,编译器将它生成的对象放在像.data和.bss段中。但是有时需要自己定义的部分,或者需要某些特定的变量出现在特殊的部分中,例如映射到特殊的硬件。section属性指定一个变量(或函数)位于特定的section段中。

语法

_attribute_((section(name)))

作用

常用于初始化模块中,添加新的模块不需要修改之前的代码。

传统做法:

如果我需要在主函数的初始化中添加新功能C的初始化,那么我必然需要修改主函数。
在这里插入图片描述

使用__attribute__((section()))构建初始化函数表后的做法:

在这里插入图片描述

那么我们只需要完成功能C的初始化,然后添加到对应的初始化表中。main函数中初始化函数表的时候,就会自动完成模块的初始化。
那么可能有人问了,第一种明显简单易懂为啥需要使用__attribute__呢?
如果程序比较简单全部是自己写的自然可以使用传统方法,但是如果需要去耦合或者接触到linux编程时会发现有很多__attribute__ section的用法。

举个栗子

练习一下使用__attribute__ section来初始化函数。
环境:ubuntu18.04
gcc:gcc version 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04)
代码来源:
廖威雄 Linux阅码场

例子源码

#include <unistd.h>
#include <stdint.h>
#include <stdio.h>
typedef void (*init_call)(void);
/*
 * These two variables are defined in link script.
 */
extern init_call _init_start;//使用外部变量这个变量会在连接脚本中被定义
extern init_call _init_end;  //使用外部变量这个变量会在连接脚本中被定义
#define _init __attribute__((unused, section(".myinit")))
#define DECLARE_INIT(func) init_call _fn_##func _init = func
static void A_init(void)
{
    write(1, "A_init\n", sizeof("A_init\n"));
}
DECLARE_INIT(A_init);
static void B_init(void)
{
    printf("B_init\n");
}
DECLARE_INIT(B_init);
static void C_init(void)
{
    printf("C_init\n");
}
DECLARE_INIT(C_init);
/*
 * DECLARE_INIT like below:
 *  static init_call _fn_A_init __attribute__((unused, section(".myinit"))) = A_init;
 *  static init_call _fn_C_init __attribute__((unused, section(".myinit"))) = C_init;
 *  static init_call _fn_B_init __attribute__((unused, section(".myinit"))) = B_init;
 */
void do_initcalls(void)

{
    init_call *init_ptr = &_init_start;
    for (; init_ptr < &_init_end; init_ptr++) {
        printf("init address: %p\n", init_ptr);
        (*init_ptr)();//初始化_init_start到_init_end段之间所有函数
    }
}

int main(void)
{
    do_initcalls();
    return 0;
}

命名程序为section.c
实现的功能:

  1. 定义DECLARE_INIT(func)宏,使用gcc编译器的__attribute__((section()))将初始化代码定义到myinit段
  2. 使用DECLARE_INIT(func)初始化A_init/B_init/C_init三个函数
  3. 集成外部变量extern init_call _init_start;extern init_call _init_end;,这两个变量会在编译脚本中定义,
  4. 在main函数中

修改连接脚本

  • 获取默认连接脚本ld --verbose
    可以得到如下所示代码和图片:
    在这里插入图片描述
 - GNU ld (GNU Binutils for Ubuntu) 2.30
  支持的仿真:
   elf_x86_64
   elf32_x86_64
   elf_i386
   elf_iamcu
   i386linux
   elf_l1om
   elf_k1om
   i386pep
   i386pe
使用内部链接脚本:
==================================================
.......(需要复制的内容)
==================================================

复制“==================================================”之间的内容,然后使用
vim ldscript.lds自己创建一个连接脚本,粘贴刚刚复制的内容

在.bss段之前添加

_init_start = .;

.myinit : { *(.myinit) }

_init_end = .;

如下图所示
在这里插入图片描述

编译

使用命令:gcc -c section.c -o section.o便于.c文件
查看短信息:readelf -S section.o

在这里插入图片描述

链接

执行:gcc -T ldscript.lds section.o -o section使用刚刚编辑过的链接脚本,生成可执行文件
执行:readelf -S section查看可执行文件段分布
在这里插入图片描述

执行结果

使用命令./section执行可执行文件
在这里插入图片描述

参考

廖威雄 Linux阅码场

  • 4
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
GCC的attribute section是一种扩展机制,用于将函数或数据放入指定的段中。使用方式是在函数或数据的声明或定义前加上__attribute__((section("section_name"))),其中section_name是指定的段的名称。\[1\] 例如,可以使用attribute section将特定的变量存放在自定义的段中。可以通过以下步骤来验证这些部分: 1. 在代码中声明或定义变量,并使用attribute section将其放置在指定的段中。 2. 编译代码时,使用链接器脚本来指定段的布局。可以使用-Wl,-T选项来指定链接器脚本,例如gcc s.c -Wl,-Ts.lds。 3. 执行编译后的程序,并使用objdump命令来验证段的位置和初始值的保存。注意objdump命令的参数和自定义段中变量的位置和初始值的保存。\[2\]\[3\] 通过使用GCC的attribute section,可以更灵活地管理代码和数据的布局,以满足特定的需求。 #### 引用[.reference_title] - *1* *2* [利用gcc的__attribute__编译属性section子项构建初始化函数表](https://blog.csdn.net/rdstwww/article/details/54784699)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [gcc的__attribute__((section(“”)))属性含义](https://blog.csdn.net/guanhuhousheng/article/details/76301829)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

柒妖71

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值