gcc: 链接时替换

3

我目前正在尝试理解gcc编译器和链接器的工作原理。我接触到了一种称为“链接时替换”的技术,我觉得非常有趣。其目的是在多个文件中具有一个函数的多个定义,并在链接时决定哪个定义进入最终可执行文件。

以下是一个简单的例子:

main.c:

#include "header.h"

int main(void)
{
    hello("everyone");
    return 0;
}

header.h:

#ifndef _HEADER_H
#define _HEADER_H

void hello(const char * name);

#endif

file1.c:

#include "header.h"
#include <stdio.h>

void hello(const char * name)
{
    printf("File1: Hello, %s!\n", name);
}

file2.c:

#include "header.h"
#include <stdio.h>

void hello(const char * name)
{
    printf("File2: Hello, %s!\n", name);
}

现在我有两个问题:
  • 如果链接器的参数列表中出现所有三个文件,是否可能通过使用适当的链接顺序来选择函数?
  • 假设file2.c实现了许多main.c所需的函数。是否可能通过使用链接器将file1.c中的单个函数或一些函数替换为不同的实现(名称相同)? 链接器应首先使用file1.c中的函数定义,然后对于剩余的未解析函数使用file2.c。
希望我的问题是可以理解的 ;)
谢谢!

1
你能编辑file2吗?如果可以的话,我会选择更明确地使用函数。例如,利用预处理器开关将其封装在条件部分中。 - Yunnosch
不管与你的问题和提问无关,但以下划线开头并后跟大写字母的符号(例如 _HEADER_H)在所有作用域中都被“保留”给“实现”(编译器和标准库)。 - Some programmer dude
是的,我可以编辑file2。预处理器开关肯定是解决这个问题的一种方法,但我想知道是否有更优雅的方式,也许通过聪明地使用链接器(我尤其想了解参数顺序在链接期间起到的作用)可以实现。 - Athazo
@Some programmer dude:谢谢你的解释,我之前不知道这个!;) - Athazo
你可以将一个函数标记为弱符号 - KamilCuk
1个回答

2
如果您说的“所有三个文件”是指目标文件(并且假设没有弱符号),那么不行:所有3个文件都会被链接,并且您会收到重复符号定义错误。但是,如果将file1.o放入lib1.a中,将file2.o放入lib2.a中,那么可以:
gcc main.c -l1 -l2  # uses file1.o:hello
gcc main.c -l2 -l1  # uses file2.o:hello

更多细节在这里在这里

假设file2.c实现了许多主函数需要的函数。是否可以使用链接器将file1.c中的单个函数或某些函数替换为不同的实现(名称相同)?

是的,但仅适用于支持弱符号的平台(例如ELF平台,请参见__attribute__((weak))在这里)。

如果file2.o中的所有符号都被弱定义,并且file1.o中的所有符号都没有被弱定义,则链接file1.o和file2.o将实现所需的结果:强符号胜出。

我相信(但未经测试)如果同时将file1.o和file2.o中的相同符号弱定义,则顺序将很重要:

gcc main.c file1.o file2.o  # file1.o definitions override file2.o
gcc main.c file2.o file1.o  # file2.o definitions override file1.o

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接