]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
bfd, ld: allow the disabling of CTF deduplication; BTF linking
authorNick Alcock <nick.alcock@oracle.com>
Fri, 25 Apr 2025 20:28:25 +0000 (21:28 +0100)
committerNick Alcock <nick.alcock@oracle.com>
Tue, 9 Dec 2025 13:02:28 +0000 (13:02 +0000)
This first half of ld support for BTF deduplication adds a facility to GNU
ld and BFD to entirely disable CTF or BTF deduplication via the new
--disable-ctf-dedup linker option, and (slightly entangled with it) modifies
the existing BFD CTF support so that it can also deduplicate BTF.
Determining whether deduplication is disabled when all you have is a section
requires a bit of digging around and the proxying of of _bfd_get_link_info
into bfd-elf.h via a new _bfd_elf_get_link_info, to dodge include ordering
problems.

(Note that BTF deduplication support is not yet complete: in particular,
relocs into BTF sections don't get handled at all yet.)

bfd/elf-bfd.h
bfd/elf.c
bfd/elflink.c
include/bfdlink.h
ld/ld.texi
ld/ldlang.c
ld/ldlex.h
ld/lexsup.c

index 372203dd33cbd7296261326b771ac84ee8052b88..d9c6428a622893221f65da8604bd9b2b512bb7f7 100644 (file)
 extern "C" {
 #endif
 
+#ifndef ATTRIBUTE_HIDDEN
+#if HAVE_HIDDEN
+#define ATTRIBUTE_HIDDEN __attribute__ ((__visibility__ ("hidden")))
+#else
+#define ATTRIBUTE_HIDDEN
+#endif
+#endif
+
 /* The number of entries in a section is its size divided by the size
    of a single entry.  This is normally only applicable to reloc and
    symbol table sections.
@@ -3178,6 +3186,9 @@ extern struct elf_link_hash_entry * _bfd_elf_get_link_hash_entry
 extern asection *_bfd_get_local_sym_section
   (struct elf_reloc_cookie *, unsigned int);
 
+extern struct bfd_link_info *_bfd_elf_get_link_info (bfd *)
+  ATTRIBUTE_HIDDEN;
+
 /* Large common section.  */
 extern asection _bfd_elf_large_com_section;
 
@@ -3324,12 +3335,21 @@ extern asection _bfd_elf_large_com_section;
         || (H)->start_stop \
         || ((INFO)->dynamic && !(H)->dynamic)))
 
-/* Determine if a section contains CTF data, using its name.  */
+/* Determine if a section contains data deduplicable using the libctf
+   deduplicator, using its name.  */
 static inline bool
-bfd_section_is_ctf (const asection *sec)
+bfd_section_is_libctf_deduppable (const asection *sec)
 {
   const char *name = bfd_section_name (sec);
-  return startswith (name, ".ctf") && (name[4] == 0 || name[4] == '.');
+  struct bfd_link_info *info;
+
+  info = _bfd_elf_get_link_info (sec->owner);
+
+  if (!info || info->ctf_disabled)
+    return false;
+
+  return (startswith (name, ".ctf") || startswith (name, ".BTF"))
+    && (name[4] == 0 || name[4] == '.');
 }
 
 #ifdef __cplusplus
index 56a5857e29edbeb741a9dec5e83ba9c88dbbb304..01986632ec9a7a1b14ad88d71933e229b406b99f 100644 (file)
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -3061,6 +3061,7 @@ bfd_section_from_elf_index (bfd *abfd, unsigned int sec_index)
 
 static const struct bfd_elf_special_section special_sections_b[] =
 {
+  { STRING_COMMA_LEN (".BTF"), 0, SHT_PROGBITS,    0 },
   { STRING_COMMA_LEN (".bss"), -2, SHT_NOBITS,   SHF_ALLOC + SHF_WRITE },
   { NULL,                  0,  0, 0,            0 }
 };
@@ -6660,7 +6661,7 @@ assign_file_positions_for_non_load_sections (bfd *abfd,
               || (abfd->is_linker_output
                   && hdr->bfd_section != NULL
                   && (hdr->sh_name == -1u
-                      || bfd_section_is_ctf (hdr->bfd_section)))
+                      || bfd_section_is_libctf_deduppable (hdr->bfd_section)))
               || hdr == i_shdrpp[elf_onesymtab (abfd)]
               || (elf_symtab_shndx_list (abfd) != NULL
                   && hdr == i_shdrpp[elf_symtab_shndx_list (abfd)->ndx])
@@ -6849,13 +6850,16 @@ find_section_in_list (unsigned int i, elf_section_list * list)
    VMAs must be known before this is called.
 
    Reloc sections come in two flavours: Those processed specially as
-   "side-channel" data attached to a section to which they apply, and
-   those that bfd doesn't process as relocations.  The latter sort are
-   stored in a normal bfd section by bfd_section_from_shdr.  We don't
-   consider the former sort here, unless they form part of the loadable
-   image.  Reloc sections not assigned here (and compressed debugging
-   sections and CTF sections which nothing else in the file can rely
-   upon) will be handled later by assign_file_positions_for_relocs.
+   "side-channel" data attached to a section to which they apply, and those
+   that bfd doesn't process as relocations.  The latter sort are stored in a
+   normal bfd section by bfd_section_from_shdr.  We don't consider the
+   former sort here, unless they form part of the loadable image.  Reloc
+   sections not assigned here (and compressed debugging sections and CTF or
+   BTF sections which nothing else in the file can rely upon) will be
+   handled later by assign_file_positions_for_relocs.
+
+   XXX UPTODO BTF sections can be depended upon by other sections: what to do
+   about them?
 
    We also don't set the positions of the .symtab and .strtab here.  */
 
@@ -6895,7 +6899,7 @@ assign_file_positions_except_relocs (bfd *abfd,
              || (abfd->is_linker_output
                  && hdr->bfd_section != NULL
                  && (hdr->sh_name == -1u
-                     || bfd_section_is_ctf (hdr->bfd_section)))
+                     || bfd_section_is_libctf_deduppable (hdr->bfd_section)))
              || i == elf_onesymtab (abfd)
              || (elf_symtab_shndx_list (abfd) != NULL
                  && hdr == i_shdrpp[elf_symtab_shndx_list (abfd)->ndx])
@@ -7145,7 +7149,7 @@ _bfd_elf_assign_file_positions_for_non_load (bfd *abfd)
              || shdrp->sh_type == SHT_REL
              || shdrp->sh_type == SHT_RELA)
            ;
-         else if (bfd_section_is_ctf (sec))
+         else if (bfd_section_is_libctf_deduppable (sec))
            {
              /* Update section size and contents.      */
              shdrp->sh_size = sec->size;
@@ -9069,7 +9073,7 @@ Unable to handle section index %x in ELF symbol.  Using ABS instead."),
       if (elfsym->sym.st_name != 0)
        elfsym->sym.st_name = _bfd_elf_strtab_offset (stt,
                                                      elfsym->sym.st_name);
-      if (info && info->callbacks->ctf_new_symbol)
+      if (info && info->callbacks->ctf_new_symbol && !info->ctf_disabled)
        info->callbacks->ctf_new_symbol (elfsym->dest_index,
                                         &elfsym->sym);
 
@@ -10067,7 +10071,7 @@ _bfd_elf_set_section_contents (bfd *abfd,
     {
       unsigned char *contents;
 
-      if (bfd_section_is_ctf (section))
+      if (bfd_section_is_libctf_deduppable (section))
        /* Nothing to do with this section: the contents are generated
           later.  */
        return true;
index 0ea974d45ce5e62b4eb41570b2b6611e25b8195f..b7bc6bb79fedb18a6dea1fb8054576d9c76ac028 100644 (file)
@@ -118,6 +118,12 @@ _bfd_elf_get_link_hash_entry (struct elf_link_hash_entry **sym_hashes,
   return h;
 }
 
+struct bfd_link_info *
+_bfd_elf_get_link_info (bfd *abfd)
+{
+  return _bfd_get_link_info (abfd);
+}
+
 static struct elf_link_hash_entry *
 get_ext_sym_hash_from_cookie (struct elf_reloc_cookie *cookie,
                              unsigned int symndx)
@@ -10478,7 +10484,8 @@ elf_link_swap_symbols_out (struct elf_final_link_info *flinfo)
 
       /* Inform the linker of the addition of this symbol.  */
 
-      if (flinfo->info->callbacks->ctf_new_symbol)
+      if (flinfo->info->callbacks->ctf_new_symbol
+         && !flinfo->info->ctf_disabled)
        flinfo->info->callbacks->ctf_new_symbol (elfsym->dest_index,
                                                 &elfsym->sym);
 
@@ -11107,7 +11114,8 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data)
 
       /* Inform the linker of the addition of this symbol.  */
 
-      if (flinfo->info->callbacks->ctf_new_dynsym)
+      if (flinfo->info->callbacks->ctf_new_dynsym
+         && !flinfo->info->ctf_disabled)
        flinfo->info->callbacks->ctf_new_dynsym (h->dynindx, &sym);
 
       bed->s->swap_symbol_out (flinfo->output_bfd, &sym, esym, 0);
@@ -12932,7 +12940,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
       esdo->rela.count = 0;
 
       if ((esdo->this_hdr.sh_offset == (file_ptr) -1)
-         && !bfd_section_is_ctf (o))
+         && !bfd_section_is_libctf_deduppable (o))
        {
          /* Cache the section contents so that they can be compressed
             later.  Use bfd_malloc since it will be freed by
@@ -13305,7 +13313,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
 
              /* Inform the linker of the addition of this symbol.  */
 
-             if (info->callbacks->ctf_new_dynsym)
+             if (info->callbacks->ctf_new_dynsym && !info->ctf_disabled)
                info->callbacks->ctf_new_dynsym (dynindx, &sym);
 
              bed->s->swap_symbol_out (abfd, &sym, dest, 0);
@@ -13345,7 +13353,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
 
              /* Inform the linker of the addition of this symbol.  */
 
-             if (info->callbacks->ctf_new_dynsym)
+             if (info->callbacks->ctf_new_dynsym && !info->ctf_disabled)
                info->callbacks->ctf_new_dynsym (e->dynindx, &sym);
 
              dest = dynsym + e->dynindx * bed->s->sizeof_sym;
@@ -13815,7 +13823,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
   if (! _bfd_elf_write_section_build_attributes (abfd, info))
     goto error_ret2;
 
-  if (info->callbacks->emit_ctf)
+  if (info->callbacks->emit_ctf && !info->ctf_disabled)
       info->callbacks->emit_ctf ();
 
   elf_final_link_free (abfd, &flinfo);
index 00fe0f8c7c831c840a9e37c149b0a835e816d957..1dde5be81e33daf657abf3b99c25116dbc37401c 100644 (file)
@@ -593,6 +593,9 @@ struct bfd_link_info
   /* TRUE if commonpagesize is set on command-line.  */
   unsigned int commonpagesize_is_set : 1;
 
+  /* TRUE if BTF and CTF linking are disabled.  */
+  unsigned int ctf_disabled : 1;
+
   /* Char that may appear as the first char of a symbol, but should be
      skipped (like symbol_leading_char) when looking up symbols in
      wrap_hash.  Used by PowerPC Linux for 'dot' symbols.  */
index f76887f1b1dd4b26feb49aede3157eb03b559b83..6c79c431a041fe0783a6f23d9e4883a9622ff997 100644 (file)
@@ -2012,6 +2012,16 @@ large projects this may speed up opening the CTF and save memory in the CTF
 consumer at runtime.
 @end table
 
+@kindex --disable-ctf-dedup
+@kindex --disable-ctf-dedup
+@item --disable-ctf-dedup
+Disable CTF and BTF deduplication entirely.  The input sections are concatenated
+just like any other section.  Note that concatenated CTF and BTF sections are
+not in general useful: libctf and other consumers will typically read the first
+portion and ignore any subsequent portions.  Nonetheless, this is sometimes
+useful in special circumstances, such as when the section's format is not
+actually that of a CTF or BTF section but merely shares the same name.
+
 @cindex common allocation
 @kindex --no-define-common
 @item --no-define-common
index 3c57bf7541cfaacff7eeec6d1ea6f6b0cd2280f4..45729be88a1c5bae81eb551d9e04a407be9fa47e 100644 (file)
@@ -3821,6 +3821,9 @@ ldlang_open_ctf (void)
   int any_ctf = 0;
   int err;
 
+  if (link_info.ctf_disabled)
+    return;
+
   ld_start_phase (PHASE_CTF);
 
   LANG_FOR_EACH_INPUT_STATEMENT (file)
@@ -3923,6 +3926,7 @@ lang_merge_ctf (void)
                 file->the_bfd, ctf_errmsg (ctf_errno (ctf_output)));
          ctf_close (file->the_ctf);
          file->the_ctf = NULL;
+         ld_stop_phase (PHASE_CTF);
          continue;
        }
     }
@@ -3961,7 +3965,8 @@ void
 ldlang_ctf_acquire_strings (struct elf_strtab_hash *dynstrtab)
 {
   ld_start_phase (PHASE_CTF);
-  ldemul_acquire_strings_for_ctf (ctf_output, dynstrtab);
+  if (!link_info.ctf_disabled)
+    ldemul_acquire_strings_for_ctf (ctf_output, dynstrtab);
   ld_stop_phase (PHASE_CTF);
 }
 
@@ -3969,7 +3974,8 @@ ldlang_ctf_acquire_strings (struct elf_strtab_hash *dynstrtab)
    internal format.  */
 void ldlang_ctf_new_dynsym (int symidx, struct elf_internal_sym *sym)
 {
-  ldemul_new_dynsym_for_ctf (ctf_output, symidx, sym);
+  if (!link_info.ctf_disabled)
+    ldemul_new_dynsym_for_ctf (ctf_output, symidx, sym);
 }
 
 /* Write out the CTF section.  Called early, if the emulation isn't going to
@@ -4053,6 +4059,9 @@ ldlang_write_ctf_late (void)
 static void
 ldlang_open_ctf (void)
 {
+  if (link_info.ctf_disabled)
+    return;
+
   LANG_FOR_EACH_INPUT_STATEMENT (file)
     {
       asection *sect;
index 24cac1cdfc0f4f5d19f2dc0f3bcab907537c631e..f5db75118167b395695a41c93917564ecc8d63a2 100644 (file)
@@ -170,6 +170,8 @@ enum option_values
   OPTION_CTF_VARIABLES,
   OPTION_NO_CTF_VARIABLES,
   OPTION_CTF_SHARE_TYPES,
+  OPTION_DISABLE_CTF_DEDUP,
+  OPTION_ENABLE_CTF_DEDUP,
   OPTION_ERROR_EXECSTACK,
   OPTION_NO_ERROR_EXECSTACK,
   OPTION_WARN_EXECSTACK_OBJECTS,
index 5cb77992733a1a2fd241ae3f52cabda881f220f2..166d96cf3adc6d58c0163d1178c1c40e16e54085 100644 (file)
@@ -643,6 +643,11 @@ static const struct ld_option ld_options[] =
                   "                                <method> is: share-unconflicted (default),\n"
                   "                                             share-duplicated"),
     TWO_DASHES },
+  { {"disable-ctf-dedup", no_argument, NULL, OPTION_DISABLE_CTF_DEDUP},
+    '\0', NULL, N_("Disable CTF and BTF deduplication: just concatenate\n"),
+    TWO_DASHES },
+  { {"enable-ctf-dedup", no_argument, NULL, OPTION_ENABLE_CTF_DEDUP},
+    '\0', NULL, NULL, NO_HELP }
 };
 
 #define OPTION_COUNT ARRAY_SIZE (ld_options)
@@ -1860,6 +1865,14 @@ parse_args (unsigned argc, char **argv)
          else
            fatal (_("%P: bad --ctf-share-types option: %s\n"), optarg);
          break;
+
+       case OPTION_DISABLE_CTF_DEDUP:
+         link_info.ctf_disabled = true;
+         break;
+
+       case OPTION_ENABLE_CTF_DEDUP:
+         link_info.ctf_disabled = false;
+         break;
        }
     }