Fix: mark (again) section start/end symbols as hidden
Commit
1353b066072e ("Visibility hidden by default") broke the plugin
loading on RHEL 7 (and probably other Linux systems with an older
linker). The ld version on RHEL 7 is 2.27-44.base.el7_9.1.
The symptom is that plugins aren't loaded:
$ ./src/cli/babeltrace2 list-plugins
From the following plugin paths:
- /home/mjeanson/Git/babeltrace/src/plugins/ctf
- /home/mjeanson/Git/babeltrace/src/plugins/text
- /home/mjeanson/Git/babeltrace/src/plugins/utils
- /home/mjeanson/Git/babeltrace/src/plugins/lttng-utils
No plugins found.
While debugging, I found this strange behavior that I am unable to
explain:
(gdb) frame
#0 __bt_get_begin_section_plugin_descriptors () at /home/mjeanson/Git/babeltrace/src/plugins/ctf/plugin.cpp:16
16 BT_PLUGIN_MODULE();
(gdb) disassemble
Dump of assembler code for function __bt_get_begin_section_plugin_descriptors():
0x00007ffff57b0045 <+0>: push %rbp
0x00007ffff57b0046 <+1>: mov %rsp,%rbp
=> 0x00007ffff57b0049 <+4>: mov 0x2b8f68(%rip),%rax # 0x7ffff5a68fb8
0x00007ffff57b0050 <+11>: pop %rbp
0x00007ffff57b0051 <+12>: retq
End of assembler dump.
(gdb) si
0x00007ffff57b0050 16 BT_PLUGIN_MODULE();
(gdb) p/x $rax
$2 = 0x7ffff7bc6dd0
We are in the function that is supposed to return the beginning of the
__bt_plugin_descriptor section for the babeltrace-plugin-ctf.so shared
object (the address of the __start___bt_plugin_descriptor symbol). The
address displayed by the disassembler (0x7ffff5a68fb8) appears correct.
It is the sum of 0x2b8f68 and the (next instruction's) PC,
0x7ffff57b0050. However, after stepping, we see that rax contains a
different value, 0x7ffff7bc6dd0. I do not understand how it's possible
for this instruction to give that result. But this address
(0x7ffff7bc6dd0) is the beginning of the __bt_plugin_descriptor section
of libbabeltrace2.so. So, the symbol from libbabeltrace2.so seems to
hide the symbol of the same name in babeltrace-plugin-ctf.so. The
function that is supposed to return the start of the plugin descriptor
section in babeltrace-plugin-ctf.so actually returns the start of that
section but in libbabeltrace2.so.
I checked the properties of the special section start/end symbols, both
on RHEL7 and on a more recent system (Arch), for both before and after
1353b066072e. Here are the results:
RHEL7 before:
00000000002c9768 0 NOTYPE LOCAL DEFAULT 26 __start___bt_plugin_descriptors
RHEL7 after :
00000000002c86c8 0 NOTYPE GLOBAL DEFAULT 26 __start___bt_plugin_descriptors
Arch before:
0000000000236a00 0 NOTYPE GLOBAL HIDDEN 27 __start___bt_plugin_descriptors
Arch after :
00000000002326c0 0 NOTYPE GLOBAL PROTECTED 27 __start___bt_plugin_descriptors
On RHEL7 the symbols originally had LOCAL binding, meaning they weren't
used for relocation outside their object. The
__start___bt_plugin_descriptor symbol from libbabeltrace2.so therefore
didn't override the one in babeltrace-plugin-ctf.so. Similarly, on
Arch, the symbols had HIDDEN visibility, so they also didn't cross
shared object boundary.
After
1353b066072e, the symbols on RHEL7 were "GLOBAL DEFAULT", meaning
the symbols from libbabeltrace2.so would override the symbols with the
same names in plugin (which are necessarily loaded after the main
library). On Arch, things kept working because the symbols use the
PROTECTED visibility. ld started to use PROTECTED visibility at some
point for these special section start/end symbols, because it makes no
sense to make them overridable (which they are with the DEFAULT
visibility). The code in a given file always wants to refer to the
section start/end symbols of its own file.
Note that starting with ld 2.35, we can use the "-z
start-stop-visibility" option to control the visibility of those
symbols. In some way, it is the linker equivalent of
-fvisibility=hidden for the compiler (just for these start/stop
symbols). But it doesn't help us for these older systems.
Here are the relevant changes I found in the ld history:
* This commit (included in binutils 2.29) made the symbols hidden:
Always define referenced __start_SECNAME/__stop_SECNAME
https://inbox.sourceware.org/binutils/
20170610224649.GA12339@gmail.com/
https://gitlab.com/gnutools/binutils-gdb/-/commit/
cbd0eecf261c2447781f8c89b0d955ee66fae7e9
* This commit (included in binutils 2.29.1 and binutils 2.30) made the
symbols protected, after people complained they couldn't look them
up:
Make __start/__stop symbols protected visibility
https://inbox.sourceware.org/binutils/CAMe9rOq5vJzAw0-Quy-J_-UZH9tpoxa4jXWdks255nuFoph7zA@mail.gmail.com/
https://gitlab.com/gnutools/binutils-gdb/-/commit/
487b6440dad57440939fab7afdd84a218b612796
* This commit (included in binutils 2.35) added the option to control
the visibility:
gold, ld: Implement -z start-stop-visibility=... option.
https://inbox.sourceware.org/binutils/CAB=4xhqb63g_b8K_BJiKne8N+X9zRO_0sYZw+0UNTTFTbdV3OA@mail.gmail.com/
https://gitlab.com/gnutools/binutils-gdb/-/commit/
cae64165f47b64898c4f1982d294862cfae89a47
Fix all this by making these symbols explicitly hidden again, as they
were before
1353b066072e.
Change-Id: Iad6c07691bbfdcbd56948cdc7ccd241d3d8311e3
Signed-off-by: Simon Marchi <simon.marchi@efficios.com>
Reviewed-on: https://review.lttng.org/c/babeltrace/+/9726
Reviewed-by: Philippe Proulx <eeppeliteloop@gmail.com>