From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-pl1-x62c.google.com (mail-pl1-x62c.google.com [IPv6:2607:f8b0:4864:20::62c]) by sourceware.org (Postfix) with ESMTPS id CCA9F385829C for ; Thu, 14 Mar 2024 23:19:20 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org CCA9F385829C Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gmail.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org CCA9F385829C Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2607:f8b0:4864:20::62c ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1710458363; cv=none; b=m8EtJVsJs+IjDIbphTc6Ets+7o/IU9tq34vxcTI2tetRPKdYnP8dRYI9U5B6Mc1Qvl31R0onVabeeGVKU+GnAIyU/jeULeWRfUReDyxlmxDrux1TuSjPHoQC//RpFAnKttKa4MKpjdbtBVWrD7wVkJGxeFLczC7dj4Pm2E0D02A= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1710458363; c=relaxed/simple; bh=kP0wP/m6+hyVzTPbgiqsn9b80W8bMtJfKaJI3JtSU6k=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=UCIe8B7lLByPjEI9MZ+Iv6yNkmFQjDIzqHpiqQ7YUXMXp/9AQsUu7PXVutyCPP8UMguF9FbRKOzUyUvPvEtSOEvGic9Upv0cK9mxI8e2N/uO12m33qVwvlAaIuucLNNVvby3GqNKIEMhsmvFC6aOTs4VCLyizNieRqKzKaM+lVs= ARC-Authentication-Results: i=1; server2.sourceware.org Received: by mail-pl1-x62c.google.com with SMTP id d9443c01a7336-1dd916ad172so11690265ad.2 for ; Thu, 14 Mar 2024 16:19:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1710458359; x=1711063159; darn=sourceware.org; h=content-transfer-encoding:mime-version:message-id:date:subject:to :from:from:to:cc:subject:date:message-id:reply-to; bh=4NX/A+Z79COGxj2tdY+4UQjEq06azJ7BkrIOazjlDuY=; b=S0NlaaXsEMDo7Ptw8zmqTo2v9gFeEMPIPgSOYvJNzrmOrZa22oVtLlMrOyQIOAlfQx 77wX0u54efLQqVmeaek33VFkJ2gSM/pgcP174D1MUbQ5W5sR+dJmBfyYiItloaqER+GK IvZWMvx13GvK9Xfn9+eMcAmLCHpwZ+8l8zrFhhedaZSq/4hDYS+/eLqgzeIZJdiZ7Gfo wBcqVqE7+rB67kK+6bl5P8ARyaNmAMAdQo9QW7VZed4RNYfr60pTxRzJDEtAteceoGdo pqCe5q2+l5VUxgInA8HAkfIku8ePrdU4RlRsb5DOECuULXA5zbdklmRN2crEcpiAArBi SKmg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1710458359; x=1711063159; h=content-transfer-encoding:mime-version:message-id:date:subject:to :from:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=4NX/A+Z79COGxj2tdY+4UQjEq06azJ7BkrIOazjlDuY=; b=CQGOo8VYExUh6/be7mw2NHgB6bVBILHDZHcV6ZaEgIdc6tnZ5s8qUacveN86VXi2pw UCdNvgN37hF007wsfId0uELet9OQCKlp3pxf/JoIKdQD7AskcB+vlhykg3R90/LUBGxY 243m5bughFUx/8CMNfalTwLldFheW/PgWB6HFn0osbbqmy0YaoBSu/aFUqdlBnUmXvPx 2NAnihCSQA4EtLb8PYInkuXQQJI8Ls5ARYCcLlTR2T6SHoeXc/uKt50jtzHOrD7Bkyba r3QpAmYn4lJXEA1P6dJW/IieP3QCsyU3r5ZXMp3QjeXww+KZBUDsClCRtA6VCRVwhTGn qBzQ== X-Gm-Message-State: AOJu0Yz7MzyuD6QXU5ToSMVXRYf3kUr4+0m3QC9XMc8joYvmUjFXHG1a QANpZHSlvmtzXDJHzZyYEcM9tBXckkznZ7w6+Z/Iwbt5s4qdy5iVvoC+EY5f X-Google-Smtp-Source: AGHT+IHA01zQiCBm/niYQK+fv6CLEqTpvWZSZQSWgVgWTjUc5Bd7ke6SEQYXmpbay+0V0wa7Zgs1lg== X-Received: by 2002:a17:902:da8c:b0:1dd:a310:aa74 with SMTP id j12-20020a170902da8c00b001dda310aa74mr4113990plx.67.1710458359018; Thu, 14 Mar 2024 16:19:19 -0700 (PDT) Received: from gnu-cfl-3.localdomain ([172.58.89.72]) by smtp.gmail.com with ESMTPSA id q13-20020a170902dacd00b001dbcfa0f1acsm2314170plx.83.2024.03.14.16.19.17 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 14 Mar 2024 16:19:18 -0700 (PDT) Received: from gnu-cfl-3.. (localhost [IPv6:::1]) by gnu-cfl-3.localdomain (Postfix) with ESMTP id BF7BF74005D for ; Thu, 14 Mar 2024 16:19:16 -0700 (PDT) From: "H.J. Lu" To: binutils@sourceware.org Subject: [PATCH] elf: Always honor the first definition in shared object and archive Date: Thu, 14 Mar 2024 16:19:16 -0700 Message-ID: <20240314231916.1071837-1-hjl.tools@gmail.com> X-Mailer: git-send-email 2.44.0 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-3019.4 required=5.0 tests=BAYES_00,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,FREEMAIL_FROM,GIT_PATCH_0,RCVD_IN_ABUSEAT,RCVD_IN_DNSWL_NONE,RCVD_IN_SBL_CSS,SPF_HELO_NONE,SPF_PASS,TXREP,T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: GCC doesn't put builtin function symbol references, which are defined in the shared C library, in the IR symbol table. When linker rescans shared objects and archives for newly added symbol references generated from the IR inputs, it skips definitions of the builtin functions in shared objects and archives. Add first_hash to bfd_link_info to track unreferenced definitions defined first in shared objects and archives. Always use them to resolve any references. bfd/ PR ld/31482 PR ld/31489 * elflink.c (elf_link_add_object_symbols): Initialize first_hash for an IR input. Always use the first definition in shared object. Add the first unreferenced dynamic definition to first_hash. (_bfd_elf_archive_symbol_lookup): Add the first unreferenced definition to first_hash.. (elf_link_add_archive_symbols): Use the symbol definition in archive if symbol is defined first in this archive. include/ PR ld/31482 PR ld/31489 * bfdlink.h (bfd_link_info): Add first_hash. ld/ PR ld/31482 PR ld/31489 * ldlang.c (lang_process): Free first_hash when it is done. * testsuite/ld-plugin/lto.exp: Add PR ld/31482 and PR ld/31489 tests. * testsuite/ld-plugin/pass1.out: New file. * testsuite/ld-plugin/pr31482a.c: Likewise. * testsuite/ld-plugin/pr31482b.c: Likewise. * testsuite/ld-plugin/pr31482c.c: Likewise. --- bfd/elflink.c | 166 +++++++++++++++++++++++------- include/bfdlink.h | 4 + ld/ldlang.c | 6 ++ ld/testsuite/ld-plugin/lto.exp | 32 ++++++ ld/testsuite/ld-plugin/pass1.out | 1 + ld/testsuite/ld-plugin/pr31482a.c | 8 ++ ld/testsuite/ld-plugin/pr31482b.c | 9 ++ ld/testsuite/ld-plugin/pr31482c.c | 9 ++ 8 files changed, 198 insertions(+), 37 deletions(-) create mode 100644 ld/testsuite/ld-plugin/pass1.out create mode 100644 ld/testsuite/ld-plugin/pr31482a.c create mode 100644 ld/testsuite/ld-plugin/pr31482b.c create mode 100644 ld/testsuite/ld-plugin/pr31482c.c diff --git a/bfd/elflink.c b/bfd/elflink.c index 5a6cb07b2ce..efcd25530f2 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -4265,7 +4265,21 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) } if ((abfd->flags & DYNAMIC) == 0) - dynamic = false; + { + dynamic = false; + if ((abfd->flags & BFD_PLUGIN) != 0 + && info->first_hash == NULL) + { + /* Initialize first_hash for an IR input. */ + info->first_hash = (struct bfd_link_hash_table *) + xmalloc (sizeof (struct bfd_link_hash_table)); + if (!bfd_hash_table_init (&info->first_hash->table, + _bfd_link_hash_newfunc, + sizeof (struct bfd_link_hash_entry))) + info->callbacks->einfo + (_("%F%P: first_hash failed to initialize: %E\n")); + } + } else { dynamic = true; @@ -5118,16 +5132,33 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) if (skip) continue; - /* Override a definition only if the new symbol matches the - existing one. */ - if (override && matched) - definition = false; - h = *sym_hash; while (h->root.type == bfd_link_hash_indirect || h->root.type == bfd_link_hash_warning) h = (struct elf_link_hash_entry *) h->root.u.i.link; + /* Override a definition only if the new symbol matches the + existing one. */ + if (override && matched) + { + definition = false; + if (info->first_hash != NULL + && (elf_dyn_lib_class (abfd) & DYN_AS_NEEDED) != 0 + && h->root.non_ir_ref_regular) + { + /* When reloading --as-needed shared objects for new + symbols added from IR inputs, if this shared object + has the first definition, use it. */ + struct bfd_link_hash_entry *e + = bfd_link_hash_lookup (info->first_hash, name, + false, false, true); + if (e != NULL + && e->type == bfd_link_hash_defined + && e->u.undef.abfd == abfd) + definition = true; + } + } + if (h->versioned != unversioned && elf_tdata (abfd)->verdef != NULL && vernum > 1 @@ -5477,8 +5508,9 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) if (!add_needed && matched && definition - && h->root.type != bfd_link_hash_indirect - && ((dynsym + && h->root.type != bfd_link_hash_indirect) + { + if ((dynsym && h->ref_regular_nonweak) || (old_bfd != NULL && (old_bfd->flags & BFD_PLUGIN) != 0 @@ -5487,37 +5519,60 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) || (h->ref_dynamic_nonweak && (elf_dyn_lib_class (abfd) & DYN_AS_NEEDED) != 0 && !on_needed_list (elf_dt_name (abfd), - htab->needed, NULL)))) - { - const char *soname = elf_dt_name (abfd); + htab->needed, NULL))) + { + const char *soname = elf_dt_name (abfd); + + info->callbacks->minfo ("%!", soname, old_bfd, + h->root.root.string); + + /* A symbol from a library loaded via DT_NEEDED of some + other library is referenced by a regular object. + Add a DT_NEEDED entry for it. Issue an error if + --no-add-needed is used and the reference was not + a weak one. */ + if (old_bfd != NULL + && (elf_dyn_lib_class (abfd) & DYN_NO_NEEDED) != 0) + { + _bfd_error_handler + /* xgettext:c-format */ + (_("%pB: undefined reference to symbol '%s'"), + old_bfd, name); + bfd_set_error (bfd_error_missing_dso); + goto error_free_vers; + } - info->callbacks->minfo ("%!", soname, old_bfd, - h->root.root.string); + elf_dyn_lib_class (abfd) = (enum dynamic_lib_link_class) + (elf_dyn_lib_class (abfd) & ~DYN_AS_NEEDED); - /* A symbol from a library loaded via DT_NEEDED of some - other library is referenced by a regular object. - Add a DT_NEEDED entry for it. Issue an error if - --no-add-needed is used and the reference was not - a weak one. */ - if (old_bfd != NULL - && (elf_dyn_lib_class (abfd) & DYN_NO_NEEDED) != 0) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%pB: undefined reference to symbol '%s'"), - old_bfd, name); - bfd_set_error (bfd_error_missing_dso); - goto error_free_vers; + /* Create dynamic sections for backends that require + that be done before setup_gnu_properties. */ + if (!_bfd_elf_link_create_dynamic_sections (abfd, info)) + return false; + add_needed = true; } + else if (dynamic + && info->first_hash != NULL + && h->root.u.def.section->owner == abfd) + { + /* Add this symbol to first hash if this shared + object has the first definition. */ + struct bfd_link_hash_entry *e + = bfd_link_hash_lookup (info->first_hash, name, true, + false, true); + if (e == NULL) + info->callbacks->einfo + (_("%F%P: %pB: failed to add %s to first hash\n"), + abfd, name); - elf_dyn_lib_class (abfd) = (enum dynamic_lib_link_class) - (elf_dyn_lib_class (abfd) & ~DYN_AS_NEEDED); - - /* Create dynamic sections for backends that require - that be done before setup_gnu_properties. */ - if (!_bfd_elf_link_create_dynamic_sections (abfd, info)) - return false; - add_needed = true; + if (e->type == bfd_link_hash_new) + { + /* Change the type to bfd_link_hash_defined and + store ABFD in u.undef->abfd. */ + e->type = bfd_link_hash_defined; + e->u.undef.abfd = abfd; + } + } } } } @@ -5963,7 +6018,29 @@ _bfd_elf_archive_symbol_lookup (bfd *abfd, p = strchr (name, ELF_VER_CHR); if (p == NULL || p[1] != ELF_VER_CHR) - return h; + { + if (info->first_hash != NULL) + { + /* Add this symbol to first hash if this archive has the + first definition. */ + struct bfd_link_hash_entry *e + = bfd_link_hash_lookup (info->first_hash, name, true, + false, true); + if (e == NULL) + info->callbacks->einfo + (_("%F%P: %pB: failed to add %s to first hash\n"), + abfd, name); + + if (e->type == bfd_link_hash_new) + { + /* Change the type to bfd_link_hash_defined and store + ABFD in u.undef->abfd. */ + e->type = bfd_link_hash_defined; + e->u.undef.abfd = abfd; + } + } + return h; + } /* First check with only one `@'. */ len = strlen (name); @@ -6102,7 +6179,22 @@ elf_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info) if (h->type != bfd_link_hash_undefweak) /* Symbol must be defined. Don't check it again. */ included[i] = true; - continue; + + /* Ignore the archive if the symbol isn't defined in a + shared object. */ + if (!((struct elf_link_hash_entry *) h)->def_dynamic) + continue; + /* Ignore the dynamic definition if symbol is first + defined in this archive. */ + if (info->first_hash != NULL) + { + struct bfd_link_hash_entry *e + = bfd_link_hash_lookup (info->first_hash, + symdef->name, false, false, + true); + if (e == NULL || e->u.undef.abfd != abfd) + continue; + } } /* We need to include this archive member. */ diff --git a/include/bfdlink.h b/include/bfdlink.h index eac07d78364..0b71c2de79d 100644 --- a/include/bfdlink.h +++ b/include/bfdlink.h @@ -616,6 +616,10 @@ struct bfd_link_info /* Hash table handled by BFD. */ struct bfd_link_hash_table *hash; + /* Hash table of symbols which are first defined in archives or shared + objects when there are any IR inputs. */ + struct bfd_link_hash_table *first_hash; + /* Hash table of symbols to keep. This is NULL unless strip is strip_some. */ struct bfd_hash_table *keep_hash; diff --git a/ld/ldlang.c b/ld/ldlang.c index 54d1af62ebe..19fb26a695d 100644 --- a/ld/ldlang.c +++ b/ld/ldlang.c @@ -8466,6 +8466,12 @@ lang_process (void) /* Check any required symbols are known. */ ldlang_check_require_defined_symbols (); + if (link_info.first_hash != NULL) + { + bfd_hash_table_free (&link_info.first_hash->table); + free (link_info.first_hash); + } + lang_end (); } diff --git a/ld/testsuite/ld-plugin/lto.exp b/ld/testsuite/ld-plugin/lto.exp index cf1691fec6d..9e53e2d3cec 100644 --- a/ld/testsuite/ld-plugin/lto.exp +++ b/ld/testsuite/ld-plugin/lto.exp @@ -539,6 +539,22 @@ set lto_link_elf_tests [list \ "" \ "pr30281.so" \ ] \ + [list \ + "Build pr31482b.a" \ + "" \ + "" \ + {pr31482b.c} \ + "" \ + "pr31482b.a" \ + ] \ + [list \ + "Build pr31482c.so" \ + "-shared" \ + "-fPIC" \ + {pr31482c.c} \ + "" \ + "pr31482c.so" \ + ] \ ] # PR 14918 checks that libgcc is not spuriously included in a shared link of @@ -722,6 +738,22 @@ set lto_run_elf_shared_tests [list \ {-Wl,--as-needed,-R,tmpdir} {} \ {lto-19c.c} {lto-19.exe} {pass.out} {-flto -O2} {c} {} \ {tmpdir/liblto-19.so tmpdir/liblto-19.a}] \ + [list {pr31482a} \ + {-Wl,--no-as-needed,-R,tmpdir} {} \ + {pr31482a.c} {pr31482a.exe} {pass.out} {-flto} {c} {} \ + {tmpdir/pr31482b.a tmpdir/pr31482c.so}] \ + [list {pr31482b} \ + {-Wl,--no-as-needed,-R,tmpdir} {} \ + {pr31482a.c} {pr31482b.exe} {pass1.out} {-flto} {c} {} \ + {tmpdir/pr31482c.so tmpdir/pr31482b.a}] \ + [list {pr31489a} \ + {-Wl,--as-needed,-R,tmpdir} {} \ + {pr31482a.c} {pr31489a.exe} {pass.out} {-flto} {c} {} \ + {tmpdir/pr31482b.a tmpdir/pr31482c.so}] \ + [list {pr31489b} \ + {-Wl,--as-needed,-R,tmpdir} {} \ + {pr31482a.c} {pr31489b.exe} {pass1.out} {-flto} {c} {} \ + {tmpdir/pr31482c.so tmpdir/pr31482b.a}] \ ] # LTO run-time tests for ELF diff --git a/ld/testsuite/ld-plugin/pass1.out b/ld/testsuite/ld-plugin/pass1.out new file mode 100644 index 00000000000..8e5c818f1a6 --- /dev/null +++ b/ld/testsuite/ld-plugin/pass1.out @@ -0,0 +1 @@ +PASS1 diff --git a/ld/testsuite/ld-plugin/pr31482a.c b/ld/testsuite/ld-plugin/pr31482a.c new file mode 100644 index 00000000000..0693e471123 --- /dev/null +++ b/ld/testsuite/ld-plugin/pr31482a.c @@ -0,0 +1,8 @@ +#include + +int +main() +{ + abort (); + return 0; +} diff --git a/ld/testsuite/ld-plugin/pr31482b.c b/ld/testsuite/ld-plugin/pr31482b.c new file mode 100644 index 00000000000..3c241735c16 --- /dev/null +++ b/ld/testsuite/ld-plugin/pr31482b.c @@ -0,0 +1,9 @@ +#include +#include + +void +abort (void) +{ + printf ("PASS\n"); + exit (0); +} diff --git a/ld/testsuite/ld-plugin/pr31482c.c b/ld/testsuite/ld-plugin/pr31482c.c new file mode 100644 index 00000000000..5c3b5099b52 --- /dev/null +++ b/ld/testsuite/ld-plugin/pr31482c.c @@ -0,0 +1,9 @@ +#include +#include + +void +abort (void) +{ + printf ("PASS1\n"); + exit (0); +} -- 2.44.0