本文译至:

http://gcc.gnu.org/onlinedocs/gccint/Initialization.html

如我们所知,在GCC通过给代码追加__attribute__((constructor))和__attribute__((destructor))的方式能够追加初始函数和终止函数,

这篇文章介绍了GCC内部是怎样实现上述处理的。

简单的说,就是在最常常的情况下,初始函数会被追加到.ctor section中,.init会调用相应的函数处理这些初始函数。终止情况类似。

----------------------------------------------------------

初始化函数是怎样被处理的?

某些语言被编译后的代码包含构造体(也被称为初始化例程)-- 该函数被用于程序启动时初始化程序数据。这些函数须要在程序“開始”前被调用 - 就是说,在main函数前被调用。

同一时候,编译一些语言时会生成析构体(也被称为终止例程),它应在程序结束时被调用。

为了支持初始函数和终止函数,编译器必须在汇编代码中生成一些东西来使这些函数在合适的时间点被调用。当你把编译器移植到一个新的系统时,你须要去指定怎么去做。

眼下GCC主要有两种方式支持初始函数和终止函数的运行,每种方式都有两个变体。对这四种变体而言,大部分结构是共通的。

链接器必须为这些函数建立两个列表 --  一个初始化函数的列表,称为 __CTOR_LIST__,和一个终止函数列表,称为 __DTOR_LIST__。

每一个列表总是从一个被忽略的函数指针開始(该函数指针在不同环境下,可能是0, -1 或是其后的函数指针的个数)。该函数指针后面尾随着一系列的0或是很多其它的构造体(析构体)函数指针,最后以一个包括0的函数指针结束。

根据不同OS和它的可运行文件格式,crtstuff.c 或 libgcc2.c 会在启动时和退出时遍历这些列表。构造体按列表的逆序被调用,析构体按顺序被调用。

处理静态构造体的最佳方式仅仅支持提供随意命名Section的目标文件格式。一个Section被用于构造体列表,还有一个用于析构体列表。它们习惯上被叫做‘.ctors’ 和 ‘.dtors’。每一个定义一个初始函数的目标文件在构造体的section里放置一个word来指向初始函数。链接器累积全部的word到一个连续的‘.ctors’ section中。终止函数也按类似的方式处理。

假设 TARGET_ASM_NAMED_SECTION 被定义,这样的方法会被 target-def.h 设为默认方式。假设一个目标板不支持随意命名的section,可是又支持特殊的可指定的构造体和析构体也能够通过定义 CTORS_SECTION_ASM_OP 和 DTORS_SECTION_ASM_OP 来达到相同的效果。

当支持随意命名的section时,依据crtstuff.c代码被调用的差别有两种变体。在支持.init section(在程序启动时运行)的系统上,crtstuff.c的部分内容会被编译到这个section里。程序像这样被链接:

     ld -o output_file crti.o crtbegin.o ... -lgcc crtend.o crtn.o

一个函数的prologue (__init) 出如今crti.o的 .init section 中 ;epilogue 出如今crtn.o中. 函数 __fini 在 .fini section的处理也一样. 正常情况下,这些文件由OS或GNU C库来提供,可是一些目标板是由GCC提供。

目标文件crtbegin.o 和crtend.o (大部分的情况下)是由crtstuff.c编译得到. 它们包括,除了别的以外,.init 和 .fini sections中的代码片段,用于跳转到 .text section中函数。链接器会将一个section的全部部分放在一起,来生成一个完整的__init函数来调用我们须要在启动阶段调用的函数。

为了使用这个变体,你必须正确的定义 INIT_SECTION_ASM_OP 宏。

假设init section不能使用,当GCC编译不论什么名为main的函数时(更精确点,不论什么被expand_main_function指定为程序入口点的函数),它在插入一个函数调用__main做为函数prologue后的第一段运行代码. __main 函数在 libgcc2.c 里被定义并运行全局的构造体。

不支持随意section的文件格式,相同也有两种变体。在最简单的变体里必须用到GNU 链接器(GNU ld)和'a.out' 格式。这样的情况下,TARGET_ASM_CONSTRUCTOR 被定义来生成一个类型为'N_SETT'的.stabs入口,參照__CTOR_LIST__, .stabs入口把指向初始化函数代码的void函数地址做为它的值。GNU链接器觉得这是一个把值加到集合的请求;这些值会累积,终于放在可运行文件中做为一个向量,格式如前所述,有一个前导(被忽略)的count和一个末尾的0元素。TARGET_ASM_DESTRUCTOR 处理也类似。既然没有init
section可用,缺省的 INIT_SECTION_ASM_OP 使 main 的编译过程会去调用上述的__main函数,開始初始化处理。

最后的变体既不使用随意section也不用GNU 链接器。这在你想要动态链接且文件格式不被 GNU 链接器支持(如 ECOFF )的情况下推荐使用。在这样的情况下,TARGET_HAVE_CTORS_DTORS 是错误的,初始和终止函数简单地通过它们的名称被识别。这个要求在链接阶段的使用一个叫 collect2 的额外程序。这个程序会假扮为链接器被 GCC 使用;它的工作是执行正常的链接器,也管理追加初始函数和终止函数的向量,这些函数通过上述的 __main
被调用。为了使用这种方法,必须在 config.gcc 里的 target 定义use_collect2。



GCC中初始化函数是怎样被处理的?的更多相关文章

  1. golang中的init初始化函数

    0.1.索引 https://waterflow.link/articles/1666090530880 1.概念 1.1.源文件里的代码执行顺序 init 函数是用于初始化应用程序状态的函数. 它不 ...

  2. ZeroMQ接口函数之 :zmq_msg_init_data - 从一个指定的存储空间中初始化一个ZMQ消息对象的数据

    ZeroMQ 官方地址 :http://api.zeromq.org/4-1:zmq_msg_init_data zmq_msg_init_data(3) ØMQ Manual - ØMQ/3.2.5 ...

  3. 在AE二次开发中出“正试图在 OS 加载程序锁内执行托管代码。不要尝试在 DllMain 或映像初始化函数内运行托管代码,这样做会导致应用程序挂起。”异常解决方案

    今天的一个项目总用到了AE的开发组件,也就是ESRI公司提供的一系列的开发包(组件)都是以dll(动态链接库的形式)然后今天在调试的时候却出现了“正试图在 OS 加载程序锁内执行托管代码.不要尝试在 ...

  4. pytorch系列 -- 9 pytorch nn.init 中实现的初始化函数 uniform, normal, const, Xavier, He initialization

    本文内容:1. Xavier 初始化2. nn.init 中各种初始化函数3. He 初始化 torch.init https://pytorch.org/docs/stable/nn.html#to ...

  5. GCC中,可以使用未声明过的函数

    今天代码中使用了一个函数,这个函数也是自定义的,但是还没来得及声明和定义,可以编译时竟然未报错,网上查了下果然,GCC中可以使用未声明的函数http://bbs.csdn.net/topics/390 ...

  6. java基础课程笔记 static 主函数 静态工具类 classpath java文档注释 静态代码块 对象初始化过程 设计模式 继承 子父类中的函数 继承中的构造函数 对象转型 多态 封装 抽象类 final 接口 包 jar包

    Static那些事儿 Static关键字 被static修饰的变量成为静态变量(类变量) 作用:是一个修饰符,用于修饰成员(成员变量,成员方法) 1.被static修饰后的成员变量只有一份 2.当成员 ...

  7. [php-src]理解Php内核中的函数与INI

    内容均以php-5.6.14为例. 一. 函数结构 内核中定义一个php函数使用 PHP_FUNCTION 宏 包装,扩展也不例外,该宏在 ./main/php.h:343 有着一系列类似以 PHP ...

  8. GNU C/C++ __attributes__ GCC中的弱符号与强符号

    最近在看一些源代码,遇到了一些使用__attribute__修饰函数和变量的属性方面的代码,不是太了解,很是汗颜,再此做个总结:   GCC使用__attribute__关键字来描述函数,变量和数据类 ...

  9. [转] GCC 中的编译器堆栈保护技术

    以堆栈溢出为代表的缓冲区溢出已成为最为普遍的安全漏洞.由此引发的安全问题比比皆是.早在 1988 年,美国康奈尔大学的计算机科学系研究生莫里斯 (Morris) 利用 UNIX fingered 程序 ...

随机推荐

  1. 登陆整合实现-QQ互联认证(ASP.NET版本)

    原文:登陆整合实现-QQ互联认证(ASP.NET版本) 首先 我们创建一个qq.ashx的页面,这个页面会跳转到QQ的请求界面 代码如下: QQSettingConfig qqSettingConfi ...

  2. CString 操作指南

    过阅读本文你可以学习如何有效地使用 CString. CString 是一种很有用的数据类型.它们很大程度上简化了MFC中的许多操作,使得MFC在做字符串操作的时候方便了很多.不管怎样,使用CStri ...

  3. MySQL教程及经常使用命令1.1

    在线教程 21分钟 MySQL 新手教程 w3school在线教程(MYSQL) 变量 查看系统变量 show global variables 查看详细变量 show global variable ...

  4. Android Activity Fragment 生命周期

    从开源项目中看到 这个,就情不自禁的收藏了~ https://github.com/xxv/android-lifecycle

  5. location.href使用方法总结

    javascript中的location.href有非常多种使用方法,主要例如以下. self.location.href="/url" 当前页面打开URL页面 location. ...

  6. uC/OS II 函数说明 之–OSTaskCreate()与OSTaskCreateExt()

    1. OSTaskCreate()    OSTaskCreate()建立一个新任务,能够在多任务环境启动之前,或者执行任务中建立任务.注意,ISR中禁止建立任务,一个任务必须为无限循环结构.    ...

  7. linux下的二进制文件的编辑和查看

    linux下的二进制文件的编辑和查看 http://blog.csdn.net/wangxiaoqin00007/article/details/6618003 一.在Linux下查看二进制文件的软件 ...

  8. win32内核程序中进程的pid,handle,eprocess之间相互转换的方法

    很有用,收下以后方便查询. 原贴地址:http://bbs.pediy.com/showthread.php?t=119193 在win32内核程序开发中,我们常常需要取得某进程的pid或句柄,或者需 ...

  9. c语言,指针与数组--指针与二维数组2

    指向一维数组的指针   char (*p)[10] ;指向一维数组的指针类型 typedef  char(*TYPE_P2ARRAY)[10]  ;   该指针可以指向数组 ,且使用起来效果节本相同, ...

  10. WCF技术剖析之五:利用ASP.NET兼容模式创建支持会话(Session)的WCF服务

    原文:WCF技术剖析之五:利用ASP.NET兼容模式创建支持会话(Session)的WCF服务 在<基于IIS的WCF服务寄宿(Hosting)实现揭秘>中,我们谈到在采用基于IIS(或者 ...