]> 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>
Fri, 25 Apr 2025 20:32:35 +0000 (21:32 +0100)
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 d2bf8e5cbaef9809df98256ef856d469111381e6..0dde5dd2d8e27d695d935f6ca1a50edff088902b 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.
@@ -3156,6 +3164,9 @@ extern void _bfd_elf_link_munmap_section_contents
 extern struct elf_link_hash_entry * _bfd_elf_get_link_hash_entry
   (struct elf_link_hash_entry **, unsigned int, Elf_Internal_Shdr *);
 
+extern struct bfd_link_info *_bfd_elf_get_link_info (bfd *)
+  ATTRIBUTE_HIDDEN;
+
 /* Large common section.  */
 extern asection _bfd_elf_large_com_section;
 
@@ -3305,12 +3316,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 3f8bc838bfb34b367c500b916046a090b4015143..768de17c67809243c8806908cdfc653699b41626 100644 (file)
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -2969,6 +2969,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 }
 };
@@ -6561,7 +6562,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])
@@ -6750,13 +6751,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.  */
 
@@ -6796,7 +6800,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])
@@ -7046,7 +7050,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;
@@ -8972,7 +8976,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);
 
@@ -9970,7 +9974,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 0df19769483620a3190064a3997303c12bb4748f..516a9e02d78027d25a9d8e3375304539d51b798b 100644 (file)
@@ -130,6 +130,12 @@ _bfd_elf_get_link_hash_entry (struct elf_link_hash_entry **  sym_hashes,
   return get_link_hash_entry (sym_hashes, symndx, symtab_hdr->sh_info);
 }
 
+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 long r_symndx)
 {
@@ -10467,7 +10473,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);
 
@@ -11096,7 +11103,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);
@@ -12918,7 +12926,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
@@ -13291,7 +13299,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);
@@ -13331,7 +13339,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;
@@ -13798,7 +13806,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
   if (! _bfd_elf_write_section_sframe (abfd, info))
     goto error_return;
 
-  if (info->callbacks->emit_ctf)
+  if (info->callbacks->emit_ctf && !info->ctf_disabled)
       info->callbacks->emit_ctf ();
 
   elf_final_link_free (abfd, &flinfo);
index 3d4d71b3347474f39394cff81b6b9860060859c4..bb1c651aa259b652048556234e9ff79642626f65 100644 (file)
@@ -589,6 +589,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 6d51ccbe57223a8d4d22f5deaabc80fa1189e7a0..bc2155caacf3707ca72cd6eea039d42400e3d9cf 100644 (file)
@@ -1982,6 +1982,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 011c5262f870565283b059cd7a7d7dd31f8039b2..a714be79d8e890a2985f0bd1862c658ba65aec9e 100644 (file)
@@ -3805,6 +3805,9 @@ ldlang_open_ctf (void)
   int any_ctf = 0;
   int err;
 
+  if (link_info.ctf_disabled)
+    return;
+
   LANG_FOR_EACH_INPUT_STATEMENT (file)
     {
       asection *sect;
@@ -3930,14 +3933,16 @@ lang_merge_ctf (void)
 void
 ldlang_ctf_acquire_strings (struct elf_strtab_hash *dynstrtab)
 {
-  ldemul_acquire_strings_for_ctf (ctf_output, dynstrtab);
+  if (!link_info.ctf_disabled)
+    ldemul_acquire_strings_for_ctf (ctf_output, dynstrtab);
 }
 
 /* Inform the emulation about the addition of a new dynamic symbol, in BFD
    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
@@ -4011,6 +4016,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 999d0defc6151a3408a86064f0898d14bcb40085..1e20abbe122062f85577c57906a10c4f1e269d83 100644 (file)
@@ -171,6 +171,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 7de6e257ad0cd1958ee458a2a8001504926a0181..112cc8e7c3591f0744db770a0f11bd40aead3f39 100644 (file)
@@ -650,6 +650,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)
@@ -1858,6 +1863,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;
        }
     }