[PATCH] ld: Add -z start-stop-gc to let __start_/__stop_ not retain C identifier name sections
Fangrui Song
i@maskray.me
Mon Mar 1 07:03:19 GMT 2021
On 2021-03-01, Alan Modra wrote:
>On Sat, Feb 27, 2021 at 09:03:19PM -0800, Fangrui Song wrote:
>> Unfortunately if there is an undefined weak "__start_xx" and no xx is retained =>
>> undefined symbol error due to ldlang.c:undef_start_stop .
>>
>> I don't know how to distinguish undefined strong and undefined weak in undef_start_stop.
>
>OK, so let's fix that first.
>
>If a weak reference to a __start_foo or __stop_foo symbol ends up
>having no definition due to all the foo sections being removed for
>some reason, undef_start_stop currently makes the symbol strong
>undefined. That risks a linker undefined symbol error. Fix that by
>making the symbol undefweak and also undo some dynamic symbol state.
>
>Note that saving the state of the symbol type at the time
>lang_init_start_stop runs is not sufficient. The linker may have
>merged in a shared library reference by that point and made what was
>an undefweak in regular objects, a strong undefined. So it is
>necessary to look at the ELF symbol flags to decide whether an
>undefweak is the proper resolution.
>
>Something probably should be done for COFF/PE too, but I'm unsure how
>to do go about that.
>
> * ldlang.c (undef_start_stop): For ELF make undefined start/stop
> symbols undefweak if that was how they were referenced. Undo
> dynamic state too.
>
>diff --git a/ld/ldlang.c b/ld/ldlang.c
>index 5ffc8444c7..a77e8fabef 100644
>--- a/ld/ldlang.c
>+++ b/ld/ldlang.c
>@@ -6808,6 +6808,19 @@ undef_start_stop (struct bfd_link_hash_entry *h)
> }
> h->type = bfd_link_hash_undefined;
> h->u.undef.abfd = NULL;
>+ if (bfd_get_flavour (link_info.output_bfd) == bfd_target_elf_flavour)
>+ {
>+ const struct elf_backend_data *bed;
>+ struct elf_link_hash_entry *eh = (struct elf_link_hash_entry *) h;
>+ unsigned int was_forced = eh->forced_local;
>+
>+ bed = get_elf_backend_data (link_info.output_bfd);
>+ (*bed->elf_backend_hide_symbol) (&link_info, eh, TRUE);
>+ if (!eh->ref_regular_nonweak)
>+ h->type = bfd_link_hash_undefweak;
>+ eh->def_regular = 0;
>+ eh->forced_local = was_forced;
>+ }
> }
> }
Thanks for taking care of the feature:)
Here is another interesting test.
.weak __start_xx
.weak __stop_xx
.global _start
_start:
movq __start_xx@gotpcrel(%rip), %rdi
movq __stop_xx@gotpcrel(%rip), %rsi
.section xx,"a",unique,0
.byte 0
.section xx,"a",unique,1
.byte 1
.section xx,"a",unique,2
.byte 2
ld-new a.o --gc-sections --print-gc-sections -pie -z start-stop-gc can discard 3 sections.
ld-new a.o --gc-sections --print-gc-sections -shared -z start-stop-gc can only discard 2 - there may be a lurking bug somewhere.
More information about the Binutils
mailing list