我有两个C源文件:
/* w1.c */
#include <stdio.h>
__attribute__((weak)) void fw(void) { printf("FW1\n"); }
int main(int argc, char **argv) {
(void)argc; (void)argv;
fw();
return 0;
}
/* w2.c */
#include <stdio.h>
void fw(void) { printf("FW2\n"); }
如果我使用gcc编译并运行它们,则会打印FW1或FW2,具体取决于是否使用w2.c:
$ gcc -s -O2 -o prog1 w1.c
$ ./prog1
FW1
$ gcc -s -O2 -o prog12 w1.c w2.c
$ ./prog12
FW2
这是这样工作的,因为在 w1.c 中,符号 fw 是弱的,所以如果另一个文件(即 w2.c)定义了一个同名的非弱符号。
因此,仅仅是 w2.c 的存在就可以通过 w1.c 中定义的弱符号来修改 w1.c 的行为。
OpenWatcom C编译器有类似的东西吗?__attribute__((weak))
的语法是什么?简单地省略__attribute__((weak))
是行不通的,因为重复的符号会导致链接失败。我希望上面的编译器命令和程序./prog1
和./prog12
)使用owcc
而不是gcc
,并可能添加一些标志。
我需要这个,因为我想实现一个清理机制(调用函数 fw),如果还使用了其他源(或对象)文件,它应该自动替换为更复杂的东西。因此,我需要两个清理机制的实现(简单的 fw 在 w1.c 中,复杂的 fw 在 w2.c 中)。
1条答案
按热度按时间rryofs0p1#
几种方法来获得一个弱符号,而不知道
owcc
...1.生成并修改
.s
文件1.使用实用程序修改ELF
.o
文件这样我们就能达成共识了我们需要一种方法来确定我们想要哪些符号是弱的。
我们可以扫描源文件,查找
owcc
将忽略的“指令”。特别的评论往往是好的:
或者,我们可以使用一个“假”宏:
或者,我们可以有一个列出弱符号的
weak.txt
文件。无论哪种方式,现在转换器知道要更改哪些符号……
修改生成的汇编器,添加
.weak
指令我从github repo中提取了watcom的源代码。当然,watcom汇编程序相对简单。
owcc
使用什么汇编程序?它可以使用gcc
et附带的GNUas
吗?al.?我猜它可以,因为弱符号[通常]是ELF的特征。我还假设
owcc
的本机汇编程序不支持它们。如果我们可以使用GNU
as
,那么就有一种方法。看看.s
,它来自gcc
下的w1.c
的构建。通常,我们得到:
但是,请注意,我们刚刚得到:
我们可以告诉
owcc
生成汇编器源代码。然后,编辑它并更改我们想要弱的任何符号的指令。然后,从.s
构建为了方便起见,这些步骤可以隐藏在脚本中。
使用实用程序更改ELF可重定位中的符号绑定
同样,我假设我们有一个ELF可重定位。
下面是来自您的源代码 * 的
readelf -s
,不带 *__attribute__((weak))
:请注意,
fw
的绑定为GLOBAL
这里是这里是
readelf -s
从您的源 * 与 * 的__attribute__((weak))
:请注意,
fw
的绑定是WEAK
有各种ELF实用程序允许操作
.o
文件。应该有一个可以改变符号属性的方法来改变WEAK
的绑定。或者,看看
man 5 elf
和libelf
。我们可以编写自己的实用程序。网上应该有很多例子可以[轻松]修改。这是源代码的修改版本(例如:
com.c
):下面是我运行的一些命令:
然后我对
st.o
和wk.o
的十六进制转储进行了比较:因此,
GLOBAL
和WEAK
之间的差异是单个位/字节。也就是说,global是0x 12,weak是0x 22。我们可以通过查看
/usr/include/elf.h
的一部分来理解这一点: