到底如何

这似乎很清楚,它应该设置的东西。

  • 它何时运行?
  • 为什么有两个括号?
  • __attribute__是一个函数吗? 宏? 句法?
  • 这在C中工作吗? C ++?
  • 它与它一起工作的功能需要是静态的吗?
  • 什么时候__attribute__((destructor))运行?
  • 目标C中的示例:

    __attribute__((constructor))
    static void initialize_navigationBarImages() {
      navigationBarImages = [[NSMutableDictionary alloc] init];
    }
    
    __attribute__((destructor))
    static void destroy_navigationBarImages() {
      [navigationBarImages release];
    }
    

  • 它在加载共享库时运行,通常在程序启动过程中运行。
  • 这就是GCC的所有属性。 大概是为了将它们与函数调用区分开来。
  • GCC特定的语法。
  • 是的,这也适用于C和C ++。
  • 不,该功能不需要是静态的。
  • 卸载共享库时通常在程序退出时运行析构函数。
  • 因此,构造函数和析构函数的工作方式是共享目标文件包含特殊部分(ELF上的.ctors和.dtors),它们分别包含对构造函数和析构函数属性标记的函数的引用。 当库被加载/卸载时,动态加载程序(ld.so或somesuch)会检查这些段是否存在,如果存在,则调用其中引用的函数。

    想想看,在普通静态链接器中可能存在一些相似的魔术,因此无论用户选择静态链接还是动态链接,都可以在启动/关闭时运行相同的代码。


    .init / .fini不被弃用。 它仍然是ELF标准的一部分,我敢说这将是永恒的。 当代码被加载/卸载时, .init / .fini代码由加载器/运行时链接器运行。 即在每一个ELF负载(例如一个共享库)代码在.init将运行。 仍然有可能使用该机制来实现与__attribute__((constructor))/((destructor))相同的事情。 这是老派,但它有一些好处。

    .ctors / .dtors机制例如需要system-rtl / loader / linker-script的支持。 这在所有系统上都不可用,例如代码在裸机上执行的深度嵌入式系统。 即使__attribute__((constructor))/((destructor))被GCC支持,也不能确定它会运行,因为它要由链接器来组织它和加载器(或在某些情况下,启动代码)运行。 要使用.init / .fini代替,最简单的方法是使用链接器标志:-init&-fini(即,来自GCC命令行,语法将是-Wl -init my_init -fini my_fini )。

    在系统支持这两种方法,一个可能的好处是在代码.init之前运行.ctors和代码在.fini.dtors 。 如果订单是相关的,那么至少有一个原始但简单的方法可以区分init / exit函数。

    其主要缺点是,你不能轻易地拥有多个_init和一个_fini每每个可加载模块功能,并可能会在更多的分段代码.so不是动机。 另一个原因是,当使用上述链接器方法时,将替换原始的_init和_fini默认函数(由crti.o提供)。 这是通常发生各种初始化的地方(在Linux上,这是全局变量赋值初始化的地方)。 这里介绍一种解决方法

    注意在上面的链接中,不需要级联到原始_init() ,因为它仍然存在。 然而,内联程序集中的call是x86助记符,并且从程序集调用函数对于许多其他体系结构(例如ARM)看起来完全不同。 即代码不透明。

    .init / .fini.ctors / .detors机制类似,但并不完全。 .init / .fini代码按“原样”运行。 也就是说,你可以在.init / .fini有几个函数,但是AFAIK在语法上很难将它们完全透明地放在纯C中,而不会破坏很多小的.so文件中的代码。

    .ctors / .dtors.init / .fini.ctors / .dtors部分都是指向函数指针的表格,“调用者”是系统提供的循环,间接调用每个函数。 也就是说,循环调用者可以是架构特定的,但由于它是系统的一部分(如果它全部存在),它并不重要。

    下面的片段为.ctors函数数组添加了新的函数指针,主要与__attribute__((constructor)) (方法可以和__attribute__((constructor)))共存__attribute__((constructor)))

    #define SECTION( S ) __attribute__ ((section ( S )))
    void test(void) {
       printf("Hellon");
    }
    void (*funcptr)(void) SECTION(".ctors") =test;
    void (*funcptr2)(void) SECTION(".ctors") =test;
    void (*funcptr3)(void) SECTION(".dtors") =test;
    

    人们还可以将函数指针添加到完全不同的自创部分。 在这种情况下,需要修改链接器脚本和模拟加载器.ctors / .dtors循环的附加函数。 但是通过它,人们可以更好地控制执行顺序,添加参数并返回代码处理eta(例如,在C ++项目中,如果需要在全局构造函数之前或之后运行的东西,这将非常有用)。

    我更喜欢__attribute__((constructor))/((destructor)) ,这是一个简单而优雅的解决方案,即使它看起来像是作弊。 对于像我这样的裸机编码器来说,这并不总是一种选择。

    在书籍链接器和装载机书中的一些很好的参考。


    本页提供了对constructordestructor属性实现以及ELF内允许它们工作的部分的深入理解。 在消化了这里提供的信息之后,我汇编了一些额外的信息(借用上面的Michael Ambrus的部分示例)创建了一个示例来说明概念并帮助我学习。 下面结合示例源提供这些结果。

    如此线程中所述, constructordestructor属性在对象文件的.ctors.dtors部分中创建条目。 您可以通过以下三种方法之一在任一部分中放置对函数的引用。 (1)使用section属性; (2) constructordestructor属性,或(3)内联程序集调用(参考Ambrus'答案中的链接)。

    constructordestructor的使用允许您在调用main()之前或返回之后,为构造函数/析构函数额外分配一个优先级来控制其执行顺序。 给定的优先级值越低,执行优先级越高(较低优先级在main()之前的较高优先级之前执行 - 并且在main()之后的较高优先级之后执行)。 您给出的优先级值必须大于100因为编译器会保留0-100之间的优先级值以供实施。 一个constructordestructor优先指定之前执行constructordestructor没有优先指定。

    通过'section'属性或inline-assembly,您还可以将函数引用放置在.init.fini ELF代码部分中,分别在任何构造函数之前和任何析构函数之后执行。 放置在.init节中的函数引用调用的任何函数将在函数引用自身之前执行(像往常一样)。

    我试图说明下面的例子中的每一个:

    #include <stdio.h>
    #include <stdlib.h>
    
    /*  test function utilizing attribute 'section' ".ctors"/".dtors"
        to create constuctors/destructors without assigned priority.
        (provided by Michael Ambrus in earlier answer)
    */
    
    #define SECTION( S ) __attribute__ ((section ( S )))
    
    void test (void) {
    printf("nttest() utilizing -- (.section .ctors/.dtors) w/o priorityn");
    }
    
    void (*funcptr1)(void) SECTION(".ctors") =test;
    void (*funcptr2)(void) SECTION(".ctors") =test;
    void (*funcptr3)(void) SECTION(".dtors") =test;
    
    /*  functions constructX, destructX use attributes 'constructor' and
        'destructor' to create prioritized entries in the .ctors, .dtors
        ELF sections, respectively.
    
        NOTE: priorities 0-100 are reserved
    */
    void construct1 () __attribute__ ((constructor (101)));
    void construct2 () __attribute__ ((constructor (102)));
    void destruct1 () __attribute__ ((destructor (101)));
    void destruct2 () __attribute__ ((destructor (102)));
    
    /*  init_some_function() - called by elf_init()
    */
    int init_some_function () {
        printf ("n  init_some_function() called by elf_init()n");
        return 1;
    }
    
    /*  elf_init uses inline-assembly to place itself in the ELF .init section.
    */
    int elf_init (void)
    {
        __asm__ (".section .init n call elf_init n .section .textn");
    
        if(!init_some_function ())
        {
            exit (1);
        }
    
        printf ("n    elf_init() -- (.section .init)n");
    
        return 1;
    }
    
    /*
        function definitions for constructX and destructX
    */
    void construct1 () {
        printf ("n      construct1() constructor -- (.section .ctors) priority 101n");
    }
    
    void construct2 () {
        printf ("n      construct2() constructor -- (.section .ctors) priority 102n");
    }
    
    void destruct1 () {
        printf ("n      destruct1() destructor -- (.section .dtors) priority 101nn");
    }
    
    void destruct2 () {
        printf ("n      destruct2() destructor -- (.section .dtors) priority 102n");
    }
    
    /* main makes no function call to any of the functions declared above
    */
    int
    main (int argc, char *argv[]) {
    
        printf ("nt  [ main body of program ]n");
    
        return 0;
    }
    

    输出:

    init_some_function() called by elf_init()
    
        elf_init() -- (.section .init)
    
        construct1() constructor -- (.section .ctors) priority 101
    
        construct2() constructor -- (.section .ctors) priority 102
    
            test() utilizing -- (.section .ctors/.dtors) w/o priority
    
            test() utilizing -- (.section .ctors/.dtors) w/o priority
    
            [ main body of program ]
    
            test() utilizing -- (.section .ctors/.dtors) w/o priority
    
        destruct2() destructor -- (.section .dtors) priority 102
    
        destruct1() destructor -- (.section .dtors) priority 101
    

    这个例子帮助巩固了构造器/析构器的行为,希望对其他人也有用。

    链接地址: http://www.djcxy.com/p/15221.html

    上一篇: How exactly does

    下一篇: How do you use gcc to generate assembly code in Intel syntax?