zoukankan      html  css  js  c++  java
  • 利用gcc的__attribute__编译属性section子项构建初始化函数表

    gcc的__attribute__编译属性有很多子项,用于改变作用对象的特性。这里讨论section子项的作用。
    
    __attribute__的section子项使用方式为:
    
    __attribute__((section("section_name")))
    
    其作用是将作用的函数或数据放入指定名为"section_name"的段。
    
    看以下程序片段:
    
    #include <unistd.h>
    #include <stdint.h>
    #include <stdio.h>
    
    typedef void (*myown_call)(void);
    
    extern myown_call _myown_start;
    extern myown_call _myown_end;
    
    #define _init __attribute__((unused, section(".myown")))
    #define func_init(func) myown_call _fn_##func _init = func
    
    static void mspec1(void)
    {
            write(1, "aha!
    ", 5);
    }
    
    static void mspec2(void)
    {
            write(1, "aloha!
    ", 7);
    }
    
    static void mspec3(void)
    {
            write(1, "hello!
    ", 7);
    }
    
    func_init(mspec1);
    func_init(mspec2);
    func_init(mspec3);
    
    /* exactly like below:
    static myown_call mc1  __attribute__((unused, section(".myown"))) = mspec1;
    static myown_call mc2  __attribute__((unused, section(".myown"))) = mspec2;
    static myown_call mc3  __attribute__((unused, section(".myown"))) = mspec3;
    */
    
    void do_initcalls(void)
    {
            myown_call *call_ptr = &_myown_start;
            do {
                    fprintf (stderr, "call_ptr: %p
    ", call_ptr);
                    (*call_ptr)();
                    ++call_ptr;
            } while (call_ptr < &_myown_end);
    
    }
    
    int main(void)
    {
            do_initcalls();
            return 0;
    }
    
    在自定义的.myown段依次填入mspec1/mspec2/mspec3的函数指针,并在do_initcalls中依次调用,从而达到构造并调用初始化函数列表的目的。
    
    两个extern变量:
    
    extern myown_call _myown_start;
    extern myown_call _myown_end;
    
    来自ld的链接脚本,可以使用:
    
    ld --verbose
    
    获取内置lds脚本,并在:
    
    __bss_start = .;
    
    之前添加以下内容:
    
    _myown_start = .;
      .myown           : { *(.myown) } = 0x90000000
      _myown_end = .;
      code_segment    : { *(code_segment) }
    
    即定义了.myown段及_myown_start/_myown_end变量(0x90000000这个数值可能需要调整)。
    
    保存修改后的链接器脚本,假设程序为s.c,链接器脚本保存为s.lds,使用以下命令编译:
    
    gcc s.c -Wl,-Ts.lds
    
    执行结果:
    
    [root@localhost ]# ./a.out 
    call_ptr: 0x8049768
    aha!
    call_ptr: 0x804976c
    aloha!
    call_ptr: 0x8049770
    hello!
    
  • 相关阅读:
    2018 ACM 网络选拔赛 徐州赛区
    2018 ACM 网络选拔赛 焦作赛区
    2018 ACM 网络选拔赛 沈阳赛区
    poj 2289 网络流 and 二分查找
    poj 2446 二分图最大匹配
    poj 1469 二分图最大匹配
    poj 3249 拓扑排序 and 动态规划
    poj 3687 拓扑排序
    poj 2585 拓扑排序
    poj 1094 拓扑排序
  • 原文地址:https://www.cnblogs.com/cyyljw/p/10729704.html
Copyright © 2011-2022 走看看