为什么内部链接名称出现在我的目标文件的符号 table 中?
Why do internally linked names appear in my object file's symbol table?
为什么内部链接的名称出现在我的目标文件的符号中 table?
这个问题不重要。我只是好奇。
示例代码如下:
namespace {
static int foo() {return 10;}
}
static int bar() {return 20;}
使用 GNU 的 readelf -s foobar.o | c++filt -t
,可以在目标文件的符号 table:
中找到这两个条目
Value Size Type Bind Vis Ndx Name
00000000 11 FUNC LOCAL DEFAULT 1 (anonymous namespace)::foo()
0000000b 11 FUNC LOCAL DEFAULT 1 bar()
没有要求编译器发出调试符号。
我偶然注意到,如果我将 static
更改为 static inline
,符号就会消失。
另请参阅 this answer,,它回答了不同的问题,解释了如何读取 readelf
的输出。然而,我的问题并没有考虑 Readelf 工具本身,而是为什么编译器会导出符号,而据我所知没有其他文件需要。
打开优化器,它们就会被优化掉。
带有 -O0
的编译器资源管理器:https://godbolt.org/z/xyOBgN
-O2
的编译器资源管理器:https://godbolt.org/z/OlPQu3
请注意,打开优化后如何没有生成程序集。
如果那些 link 不适合你,或者你不想打开它们,它们都将问题中的代码编译为 g++ 汇编。第一个 link 禁用了优化器,生成以下程序集:
(anonymous namespace)::foo():
push rbp
mov rbp, rsp
mov eax, 10
pop rbp
ret
bar():
push rbp
mov rbp, rsp
mov eax, 20
pop rbp
ret
启用优化器的程序集输出如下:
<No assembly generated>
My question however does not regard the Readelf tool as such, but rather why the compiler would export symbols no other file as far as I know needs.
编译器不导出这些符号(它们具有LOCAL
绑定)。
编译器只是为它们创建符号 table 条目,以简化调试。
The compiler has not been asked to emit debugging symbols.
即使没有调试符号,符号 table 中的(非调试)符号也可用于调试。考虑:
#include <stdlib.h>
namespace {
static int foo() {abort();}
}
static int bar() {return 20 + foo();}
int main() { return bar(); }
g++ t.cc && gdb -q ./a.out
(gdb) run
Starting program: /tmp/a.out
Program received signal SIGABRT, Aborted.
__GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
51 ../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
(gdb) bt
#0 __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
#1 0x00007ffff7a6e3fa in __GI_abort () at abort.c:89
#2 0x0000555555554653 in (anonymous namespace)::foo() ()
#3 0x000055555555465c in bar() ()
#4 0x000055555555466a in main ()
请注意第 2 帧和第 3 帧是多么有用。如果您不希望这种情况发生,您可以随时删除符号:
gcc t.cc -Wl,--strip-all && gdb -q ./a.out
(gdb) run
Starting program: /tmp/a.out
Program received signal SIGABRT, Aborted.
__GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
51 ../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
(gdb) bt
#0 __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
#1 0x00007ffff7a6e3fa in __GI_abort () at abort.c:89
#2 0x0000555555554653 in ?? ()
#3 0x000055555555465c in ?? ()
#4 0x000055555555466a in ?? ()
#5 0x00007ffff7a5a2b1 in __libc_start_main (main=0x555555554661, argc=1, argv=0x7fffffffde08, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffddf8)
at ../csu/libc-start.c:291
#6 0x000055555555456a in ?? ()
为什么内部链接的名称出现在我的目标文件的符号中 table?
这个问题不重要。我只是好奇。
示例代码如下:
namespace {
static int foo() {return 10;}
}
static int bar() {return 20;}
使用 GNU 的 readelf -s foobar.o | c++filt -t
,可以在目标文件的符号 table:
Value Size Type Bind Vis Ndx Name
00000000 11 FUNC LOCAL DEFAULT 1 (anonymous namespace)::foo()
0000000b 11 FUNC LOCAL DEFAULT 1 bar()
没有要求编译器发出调试符号。
我偶然注意到,如果我将 static
更改为 static inline
,符号就会消失。
另请参阅 this answer,,它回答了不同的问题,解释了如何读取 readelf
的输出。然而,我的问题并没有考虑 Readelf 工具本身,而是为什么编译器会导出符号,而据我所知没有其他文件需要。
打开优化器,它们就会被优化掉。
带有 -O0
的编译器资源管理器:https://godbolt.org/z/xyOBgN
-O2
的编译器资源管理器:https://godbolt.org/z/OlPQu3
请注意,打开优化后如何没有生成程序集。
如果那些 link 不适合你,或者你不想打开它们,它们都将问题中的代码编译为 g++ 汇编。第一个 link 禁用了优化器,生成以下程序集:
(anonymous namespace)::foo():
push rbp
mov rbp, rsp
mov eax, 10
pop rbp
ret
bar():
push rbp
mov rbp, rsp
mov eax, 20
pop rbp
ret
启用优化器的程序集输出如下:
<No assembly generated>
My question however does not regard the Readelf tool as such, but rather why the compiler would export symbols no other file as far as I know needs.
编译器不导出这些符号(它们具有LOCAL
绑定)。
编译器只是为它们创建符号 table 条目,以简化调试。
The compiler has not been asked to emit debugging symbols.
即使没有调试符号,符号 table 中的(非调试)符号也可用于调试。考虑:
#include <stdlib.h>
namespace {
static int foo() {abort();}
}
static int bar() {return 20 + foo();}
int main() { return bar(); }
g++ t.cc && gdb -q ./a.out
(gdb) run
Starting program: /tmp/a.out
Program received signal SIGABRT, Aborted.
__GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
51 ../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
(gdb) bt
#0 __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
#1 0x00007ffff7a6e3fa in __GI_abort () at abort.c:89
#2 0x0000555555554653 in (anonymous namespace)::foo() ()
#3 0x000055555555465c in bar() ()
#4 0x000055555555466a in main ()
请注意第 2 帧和第 3 帧是多么有用。如果您不希望这种情况发生,您可以随时删除符号:
gcc t.cc -Wl,--strip-all && gdb -q ./a.out
(gdb) run
Starting program: /tmp/a.out
Program received signal SIGABRT, Aborted.
__GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
51 ../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
(gdb) bt
#0 __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
#1 0x00007ffff7a6e3fa in __GI_abort () at abort.c:89
#2 0x0000555555554653 in ?? ()
#3 0x000055555555465c in ?? ()
#4 0x000055555555466a in ?? ()
#5 0x00007ffff7a5a2b1 in __libc_start_main (main=0x555555554661, argc=1, argv=0x7fffffffde08, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffddf8)
at ../csu/libc-start.c:291
#6 0x000055555555456a in ?? ()