- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我想在代码中引入一个弱符号,但是,当使用* .a文件时,我无法理解它的行为。
这是我的最小示例:
文件a.h:
void foo() __attribute__((weak));
#include "a.h"
#include <stdio.h>
void foo() { printf("%s\n", __FILE__); }
#include <stdio.h>
void foo() { printf("%s\n", __FILE__); }
#include "a.h"
#include <stdio.h>
int main() { if (foo) foo(); else printf("no foo\n"); }
make -c a.c
和
make -c b.c
)还是* .a文件(
ar cr a.o
和
ar cr b.o
),输出有所不同:
g++ main.cpp a.o b.o
打印b.c
g++ main.cpp b.o a.o
打印b.c
g++ main.cpp a.a b.a
不打印foo
g++ main.cpp b.a a.a
不打印foo
void foo();
#include "a.h"
#include <stdio.h>
void __attribute__((weak)) foo() { printf("%s\n", __FILE__); }
g++ main.cpp a.a b.a
打印a.c
g++ main.cpp b.a a.a
打印b.c
nm a.a
后显示
W _Z3foov
,因此不会违反ODR。但是,我不知道这是否是弱属性的正确用法。根据gcc文档:
The weak attribute causes the declaration to be emitted as a weak symbol rather than a global. This is primarily useful in defining library functions which can be overridden in user code, though it can also be used with non-function declarations. Weak symbols are supported for ELF targets, and also for a.out targets when using the GNU assembler and linker.
g++ main.cpp a.a b.a
打印a.c
g++ main.cpp b.a a.a
打印b.c
nm a.a
显示发出了一个弱符号,它似乎也不影响静态链接。
最佳答案
为了解释这里发生的事情,让我们先谈谈您的原始源文件,
a.h(1):
void foo() __attribute__((weak));
#include "a.h"
#include <stdio.h>
void foo() { printf("%s\n", __FILE__); }
.c
和
.cpp
文件的混合与
main.cpp
是
main.c
和
gcc
完成所有编译和链接:
$ gcc -Wall -c main.c a.c b.c
ar rcs a.a a.o
ar rcs b.a b.o
void foo() __attribute__((weak));
void foo();
foo
的弱引用(即对弱声明的foo
的引用)时,foo
的定义:它可以保留foo
的强烈引用,foo
的定义。 foo
的一个强定义(即一个定义foo
的代码)。否则会导致多定义错误。foo
的多个弱定义而没有错误。 foo
的弱定义以及一个强foo
的一个弱定义而没有强定义foo
的多个弱定义且不包含强ar
存档
gcc main.c a.o b.o
gcc
在后台将其按需分解为一个编译步骤和链接
gcc -c main.c # compile
gcc main.o a.o b.o # link
./a.out
中。
a.o
包含一个
foo
的弱定义:
$ nm --defined a.o
0000000000000000 W foo
b.o
包含一个强定义:
$ nm --defined b.o
0000000000000000 T foo
b.o
中选择一个强定义,我们可以
$ gcc main.o a.o b.o -Wl,-trace-symbol=foo
main.o: reference to foo
a.o: definition of foo
b.o: definition of foo
$ ./a.out
b.c
a.o
和
b.o
的链接顺序没有什么区别:
foo
的一个强定义,即
b.o
中的一个强定义。
gcc main.cpp a.a b.a
gcc -c main.cpp # compile
gcc main.o a.a b.a # link
main.o
是无条件链接的。这带来了不确定的弱引用
foo
放入链接中:
$ nm --undefined main.o
w foo
U _GLOBAL_OFFSET_TABLE_
U puts
foo
的弱引用不需要定义。因此链接器将
a.a
或
b.a
中的任何目标文件中找到解决该问题的定义,并且
$ gcc main.o a.a b.a -Wl,-trace-symbol=foo
main.o: reference to foo
$ nm --undefined a.out
w __cxa_finalize@@GLIBC_2.2.5
w foo
w __gmon_start__
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
U __libc_start_main@@GLIBC_2.2.5
U puts@@GLIBC_2.2.5
$ ./a.out
no foo
a.a
和
b.a
的链接顺序也没关系,
a.h
和
a.c
发现的不同行为
void foo();
#include "a.h"
#include <stdio.h>
void __attribute__((weak)) foo() { printf("%s\n", __FILE__); }
$ gcc -Wall -c main.c a.c b.c
main.c: In function ‘main’:
main.c:4:18: warning: the address of ‘foo’ will always evaluate as ‘true’ [-Waddress]
int main() { if (foo) foo(); else printf("no foo\n"); }
main.o
包含一个对
foo
的强烈声明的引用:
$ nm --undefined main.o
U foo
U _GLOBAL_OFFSET_TABLE_
foo
的非空地址。进行中:
$ ar rcs a.a a.o
$ ar rcs b.a b.o
$ gcc main.o a.o b.o
$ ./a.out
b.c
$ gcc main.o b.o a.o
$ ./a.out
b.c
b.o
提供
foo
的强定义,
a.o
提供的弱定义,因此
b.o
胜出。
$ gcc main.o a.a b.a
$ ./a.out
a.c
$ gcc main.o b.a a.a
$ ./a.out
b.c
$ gcc main.o a.a b.a -Wl,-trace,-trace-symbol=foo
/usr/bin/x86_64-linux-gnu-ld: mode elf_x86_64
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/Scrt1.o
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crti.o
/usr/lib/gcc/x86_64-linux-gnu/7/crtbeginS.o
main.o
(a.a)a.o
libgcc_s.so.1 (/usr/lib/gcc/x86_64-linux-gnu/7/libgcc_s.so.1)
/lib/x86_64-linux-gnu/libc.so.6
(/usr/lib/x86_64-linux-gnu/libc_nonshared.a)elf-init.oS
/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
libgcc_s.so.1 (/usr/lib/gcc/x86_64-linux-gnu/7/libgcc_s.so.1)
/usr/lib/gcc/x86_64-linux-gnu/7/crtendS.o
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crtn.o
main.o: reference to foo
a.a(a.o): definition of foo
main.o
(a.a)a.o
foo
的定义来自
a.o
的存档成员
a.a
:
a.a(a.o): definition of foo
$ gcc main.o b.a a.a -Wl,-trace,-trace-symbol=foo
/usr/bin/x86_64-linux-gnu-ld: mode elf_x86_64
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/Scrt1.o
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crti.o
/usr/lib/gcc/x86_64-linux-gnu/7/crtbeginS.o
main.o
(b.a)b.o
libgcc_s.so.1 (/usr/lib/gcc/x86_64-linux-gnu/7/libgcc_s.so.1)
/lib/x86_64-linux-gnu/libc.so.6
(/usr/lib/x86_64-linux-gnu/libc_nonshared.a)elf-init.oS
/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
libgcc_s.so.1 (/usr/lib/gcc/x86_64-linux-gnu/7/libgcc_s.so.1)
/usr/lib/gcc/x86_64-linux-gnu/7/crtendS.o
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crtn.o
main.o: reference to foo
b.a(b.o): definition of foo
main.o
(b.a)b.o
foo
的定义来自
b.o
中的
b.a
:
b.a(b.o): definition of foo
foo
时需要为其定义的
a.a
。所以
a.o
。这个定义是一个很弱的定义,但是没关系。没有
a.o
中提取了
a.a
并进行了链接,
foo
的引用。到达下一个
b.a
,在哪里
foo
的强定义,它将在
b.o
中找到
gcc main.o a.a b.a
gcc main.o a.o
$ gcc main.o b.a a.a
$ gcc main.o b.o
I want to override [the] original function implementation when linking with a testing framework.
lib1.a
的程序
file1.o
的成员
foo
,并且您想删除
foo
的定义,并链接其他对象中定义的另一个
file2.o
。
__attribute__((weak))
不适用于该问题。解决方案更多
file2.o
lib1.a
(并且在提供
foo
定义的任何其他输入之前)。
foo
中提供的定义来解析对
file2.o
的引用,并且不会尝试查找任何其他引用
lib1.a
时的定义。链接器完全不会使用
lib1.a(file1.o)
。它可能不存在。
file2.o
放在另一个静态库
lib2.a
中怎么办?然后输入
lib2.a
之前的
lib1.a
将完成链接
lib2.a(file2.o)
之前的工作
lib1.a
并将
foo
解析为
file2.o
中的定义。
lib2.a
成员提供的每个定义都将链接到
lib1.a
中提供的相同符号的定义的首选项。如果不是那样的话
lib2.a
:链接
file2.o
本身。
Is it possible to use [the] weak attribute with static linking at all?
#ifndef FOO_H
#define FOO_H
int __attribute__((weak)) foo(int i)
{
return i != 0;
}
#endif
#include "foo.h"
int a(void)
{
return foo(0);
}
#include "foo.h"
int b(void)
{
return foo(42);
}
#include <stdio.h>
extern int a(void);
extern int b(void);
int main(void)
{
puts(a() ? "true" : "false");
puts(b() ? "true" : "false");
return 0;
}
$ gcc -Wall -ffunction-sections -c prog.c aa.c bb.c
foo
的弱定义是通过
foo.h
编译成两个
aa.o
和
bb.o
,我们可以看到:
$ nm --defined aa.o
0000000000000000 T a
0000000000000000 W foo
$ nm --defined bb.o
0000000000000000 T b
0000000000000000 W foo
$ gcc prog.o aa.o bb.o -Wl,--gc-sections,-Map=mapfile,-trace,-trace-symbol=foo
/usr/bin/x86_64-linux-gnu-ld: mode elf_x86_64
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/Scrt1.o
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crti.o
/usr/lib/gcc/x86_64-linux-gnu/7/crtbeginS.o
prog.o
aa.o
bb.o
libgcc_s.so.1 (/usr/lib/gcc/x86_64-linux-gnu/7/libgcc_s.so.1)
/lib/x86_64-linux-gnu/libc.so.6
(/usr/lib/x86_64-linux-gnu/libc_nonshared.a)elf-init.oS
/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
libgcc_s.so.1 (/usr/lib/gcc/x86_64-linux-gnu/7/libgcc_s.so.1)
/usr/lib/gcc/x86_64-linux-gnu/7/crtendS.o
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crtn.o
aa.o: definition of foo
$ ar rcs libaabb.a aa.o bb.o
$ gcc prog.o libaabb.a
aa.o
和
bb.o
都已加载,并且每个都包含
foo
的定义,没有多定义错误结果,因为每个定义
aa.o
之前加载了
bb.o
,并且从
foo
链接了
aa.o
的定义。
foo
中
bb.o
的定义发生了什么?映射文件向我们显示:
...
...
Discarded input sections
...
...
.text.foo 0x0000000000000000 0x13 bb.o
...
...
bb.o
aa.o
和
bb.o
的链接顺序:
$ gcc prog.o bb.o aa.o -Wl,--gc-sections,-Map=mapfile,-trace,-trace-symbol=foo
...
prog.o
bb.o
aa.o
...
bb.o: definition of foo
bb.o
在
aa.o
之前加载。的
foo
的定义从
bb.o
和以下链接:
...
...
Discarded input sections
...
...
.text.foo 0x0000000000000000 0x13 aa.o
...
...
aa.o
中的定义被删除。
#ifndef FOO_H
#define FOO_H
inline int foo(int i)
{
return i != 0;
}
#endif
*.c
->
*.cpp
;编译链接:
$ g++ -Wall -c prog.cpp aa.cpp bb.cpp
foo
和
aa.o
中的每个对
bb.o
(C++错位)的定义都很弱:
$ nm --defined aa.o bb.o
aa.o:
0000000000000000 T _Z1av
0000000000000000 W _Z3fooi
bb.o:
0000000000000000 T _Z1bv
0000000000000000 W _Z3fooi
$ g++ prog.o aa.o bb.o -Wl,-Map=mapfile,-trace,-trace-symbol=_Z3fooi
...
prog.o
aa.o
bb.o
...
aa.o: definition of _Z3fooi
bb.o: reference to _Z3fooi
...
...
Discarded input sections
...
...
.text._Z3fooi 0x0000000000000000 0x13 bb.o
...
...
#ifndef FOO_H
#define FOO_H
template<typename T>
T foo(T i)
{
return i != 0;
}
#endif
$ g++ -Wall -c prog.cpp aa.cpp bb.cpp
$ nm --defined aa.o bb.o
aa.o:
0000000000000000 T _Z1av
0000000000000000 W _Z3fooIiET_S0_
bb.o:
0000000000000000 T _Z1bv
0000000000000000 W _Z3fooIiET_S0_
aa.o
和
bb.o
中的每一个都具有以下弱定义:
$ c++filt _Z3fooIiET_S0_
int foo<int>(int)
$ g++ prog.o aa.o bb.o -Wl,-Map=mapfile,-trace,-trace-symbol=_Z3fooIiET_S0_
...
prog.o
aa.o
bb.o
...
aa.o: definition of _Z3fooIiET_S0_
bb.o: reference to _Z3fooIiET_S0_
$ g++ prog.o bb.o aa.o -Wl,-Map=mapfile,-trace,-trace-symbol=_Z3fooIiET_S0_
...
prog.o
bb.o
aa.o
...
bb.o: definition of _Z3fooIiET_S0_
aa.o: reference to _Z3fooIiET_S0_
$ ./a.out
false
true
关于c++ - __attribute __((weak))和静态库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51656838/
是否有 Swift 等同于 __attribute((objc_requires_super)) 如果一个方法没有调用它的 super 方法,它会发出警告? 基本上,如果被覆盖的方法没有调用它的 su
我想在代码中引入一个弱符号,但是,当使用* .a文件时,我无法理解它的行为。 这是我的最小示例: 文件a.h: void foo() __attribute__((weak)); 归档交流: #inc
我想知道是否可以在VC中使用C构造函数,就像在GCC中使用它们一样。 使用__attribute__关键字的gcc方法非常简单,不幸的是VC似乎甚至都不知道该关键字,因为我不是Win32程序员,所以我
我正在使用几个在线编译器来测试一个示例程序(供引用,ideone 中的一个和 tutorialspoint 中的那个)程序是: #include #include uint8_t Array[5]
出于学习目的,我一直在汇编中编写东西。目前,我正在尝试在汇编中实现C的__attribute__((constructor))的等效功能,但是我不确定如何执行此操作。 所以我的问题是,属性要编译成什么
我在 gcc 中遇到了一个关于用 __attribute((const)) 标记的运算符和函数的非常奇怪的行为。逻辑和算术运算符导致不同的优化,我不明白为什么。 这并不是真正的错误,因为 __attr
我认为在 tsocks 上做一些工作将是一个有趣的副项目,因为它已经 8 年没有看到任何更新了。它的托管here在 GitHub 上。 到目前为止,我只对代码进行了外观更改,但现在遇到了编译器错误。根
我正在使用 a library在编译时注册一些结构。在本例中,它注册了一个表示我想要公开的 JSON-RPC 方法的结构。该库使用 __attribute(section("xautodata_""s
我正在将可以在Linux上完美运行的代码移植到Windows visual c++。 我在Linux中有以下代码: struct exif_desc { uint16_t tag;
我有一些代码使用类型双关来避免必须调用成员“对象”的构造函数和析构函数,除非/直到它确实需要使用该对象。 它工作正常,但在 g++ 4.4.3 下,我收到了这个可怕的编译器警告: jaf@jeremy
我是一名优秀的程序员,十分优秀!