C语言中的弱符号与强符号介绍

        弱符号(Weak symbol)是链接器(ld)在生成ELF(Executable and Linkable Format,缩写为ELF,可执行和可链接格式,是一种用于可执行文件、目标文件、共享库和核心转储的标准文件格式。ELF文件有两种索引:程序标头中记载了运行时所需的段,而段首地址表记载了二进制文件中段的首地址。)文件的过程中使用的一种特殊属性符号。默认情况下,如果没有特别声明,目标文件里面的符号都是强符号(Strong symbol)。在链接过程中,一个强符号会优先于一个同名的弱符号。相比之下,两个同名强符号一起链接会出现链接错误即重复定义错误。当链接一个可执行文件,弱符号可以不定义。但对于强符号,如果没有定义,连接器会产生一个“符号未定义”错误 (undefined symbol)。使用弱符号的目的是,当不确定这个符号是否被定义的情况下,链接器也可以成功链接出ELF文件,适用于某些模块还未实现的情况下,其他模块的先行调试。弱符号在C和C++的规范里面没有被提及,所以使用弱符号的代码,移植性不是非常好,这个跟编译器相关。

        弱符号通常来源于未初始化的全局变量。而默认情况下,编译器将函数和初始化了全局变量作为强符号 。可以通过GCC的__attribute__((weak))来定义任何一个强符号为弱符号。不同的目标文件中不能有同名的强符号,否则不能链接在一起。如果一个符号在某个目标文件中是强符号,在其它文件中都是弱符号,那么该名称在链接时选择强符号。如果一个符号在所有的目标文件中都是弱符号,则选择占用空间(字节数)最大的一个,如果占用空间相同,则按照链接顺序选择第一个。

        以下是测试代码:

        main.c:

#include 

int __attribute__((weak)) x = 1; // weak symbol
int y = 2; // strong symbol
int z; // weak symbol, COM
extern int a; // neither weak symbol nor strong symbol
extern int __attribute__((weak)) b; // weak symbol
static int c; // neither weak symbol nor strong symbol

void __attribute__((weak)) fun1()  // weak symbol
{
    fprintf(stdout, "fun1 Line: %d\n", __LINE__);
}

void __attribute__((weak)) fun2(); // weak symbol

void fun3() // strong symbol
{
    fprintf(stdout, "fun3 Line: %d\n", __LINE__);
}

int main()
{

    fun1();
    fun3();
    if (fun2) {
        fprintf(stdout, "run fun2\n");
        fun2();
    }

    fprintf(stdout, "x = %d, y = %d, z = %d\n", x, y, z);
    fprintf(stdout, "c = %d\n", c);

    return 0;
}

        build.sh:

#! /bin/bash

if [[ -e build  ]]; then
    echo "##### rm build dir"
    rm -rf build
fi

mkdir build
cd build

echo -e "\n##### start build and link:"
gcc -c ../main.c
gcc -o main main.o

echo -e "\n##### read elf:"
readelf --syms main.o

echo -e "\n##### run:"
./main

        执行结果如下:$ ./build.sh

C语言中的弱符号与强符号介绍_第1张图片

        GitHub: https://github.com/fengbingchun/Linux_Code_Test  

你可能感兴趣的:(C/C++/C++11,GCC/Clang/LLVM,Linux)