| /* Emulation code used by all ELF targets. | 
 |    Copyright (C) 1991-2025 Free Software Foundation, Inc. | 
 |  | 
 |    This file is part of the GNU Binutils. | 
 |  | 
 |    This program is free software; you can redistribute it and/or modify | 
 |    it under the terms of the GNU General Public License as published by | 
 |    the Free Software Foundation; either version 3 of the License, or | 
 |    (at your option) any later version. | 
 |  | 
 |    This program is distributed in the hope that it will be useful, | 
 |    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 |    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
 |    GNU General Public License for more details. | 
 |  | 
 |    You should have received a copy of the GNU General Public License | 
 |    along with this program; if not, write to the Free Software | 
 |    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, | 
 |    MA 02110-1301, USA.  */ | 
 |  | 
 | #include "sysdep.h" | 
 | #include "libiberty.h" | 
 | #include "bfd.h" | 
 | #include "bfdlink.h" | 
 | #include "ctf-api.h" | 
 | #include "ld.h" | 
 | #include "ldmain.h" | 
 | #include "ldmisc.h" | 
 | #include "ldexp.h" | 
 | #include "ldlang.h" | 
 | #include "ldctor.h" | 
 | #include "elf-bfd.h" | 
 | #include "elf/internal.h" | 
 | #include "ldelfgen.h" | 
 |  | 
 | /* Info attached to an output_section_statement about input sections, | 
 |    used when sorting SHF_LINK_ORDER sections.  */ | 
 |  | 
 | struct os_sections | 
 | { | 
 |   /* Size allocated for isec.  */ | 
 |   unsigned int alloc; | 
 |   /* Used entries in isec.  */ | 
 |   unsigned int count; | 
 |   /* How many are SHF_LINK_ORDER.  */ | 
 |   unsigned int ordered; | 
 |   /* Input sections attached to this output section.  */ | 
 |   struct os_sections_input { | 
 |     lang_input_section_type *is; | 
 |     unsigned int idx; | 
 |   } isec[1]; | 
 | }; | 
 |  | 
 | /* Add IS to data kept for OS.  */ | 
 |  | 
 | static bool | 
 | add_link_order_input_section (lang_input_section_type *is, | 
 | 			      lang_output_section_statement_type *os) | 
 | { | 
 |   struct os_sections *os_info = os->data; | 
 |   asection *s; | 
 |  | 
 |   if (os_info == NULL) | 
 |     { | 
 |       os_info = xmalloc (sizeof (*os_info) + 63 * sizeof (*os_info->isec)); | 
 |       os_info->alloc = 64; | 
 |       os_info->count = 0; | 
 |       os_info->ordered = 0; | 
 |       os->data = os_info; | 
 |     } | 
 |   if (os_info->count == os_info->alloc) | 
 |     { | 
 |       size_t want; | 
 |       os_info->alloc *= 2; | 
 |       want = sizeof (*os_info) + (os_info->alloc - 1) * sizeof (*os_info->isec); | 
 |       os_info = xrealloc (os_info, want); | 
 |       os->data = os_info; | 
 |     } | 
 |   os_info->isec[os_info->count].is = is; | 
 |   os_info->isec[os_info->count].idx = os_info->count; | 
 |   os_info->count++; | 
 |   s = is->section; | 
 |   if (bfd_get_flavour (s->owner) == bfd_target_elf_flavour | 
 |       && (s->flags & SEC_LINKER_CREATED) == 0 | 
 |       && elf_linked_to_section (s) != NULL) | 
 |     os_info->ordered++; | 
 |   return false; | 
 | } | 
 |  | 
 | /* Run over the linker's statement list, extracting info about input | 
 |    sections attached to each output section.  */ | 
 |  | 
 | static bool | 
 | link_order_scan (lang_statement_union_type *u, | 
 | 		 lang_output_section_statement_type *os) | 
 | { | 
 |   asection *s; | 
 |   bool ret = false; | 
 |  | 
 |   for (; u != NULL; u = u->header.next) | 
 |     { | 
 |       switch (u->header.type) | 
 | 	{ | 
 | 	case lang_wild_statement_enum: | 
 | 	  if (link_order_scan (u->wild_statement.children.head, os)) | 
 | 	    ret = true; | 
 | 	  break; | 
 | 	case lang_constructors_statement_enum: | 
 | 	  if (link_order_scan (constructor_list.head, os)) | 
 | 	    ret = true; | 
 | 	  break; | 
 | 	case lang_output_section_statement_enum: | 
 | 	  if (u->output_section_statement.constraint != -1 | 
 | 	      && link_order_scan (u->output_section_statement.children.head, | 
 | 				  &u->output_section_statement)) | 
 | 	    ret = true; | 
 | 	  break; | 
 | 	case lang_group_statement_enum: | 
 | 	  if (link_order_scan (u->group_statement.children.head, os)) | 
 | 	    ret = true; | 
 | 	  break; | 
 | 	case lang_input_section_enum: | 
 | 	  s = u->input_section.section; | 
 | 	  if (s->output_section != NULL | 
 | 	      && s->output_section->owner == link_info.output_bfd | 
 | 	      && (s->output_section->flags & SEC_EXCLUDE) == 0 | 
 | 	      && ((s->output_section->flags & SEC_HAS_CONTENTS) != 0 | 
 | 		  || ((s->output_section->flags & (SEC_LOAD | SEC_THREAD_LOCAL)) | 
 | 		      == (SEC_LOAD | SEC_THREAD_LOCAL)))) | 
 | 	    if (add_link_order_input_section (&u->input_section, os)) | 
 | 	      ret = true; | 
 | 	  break; | 
 | 	default: | 
 | 	  break; | 
 | 	} | 
 |     } | 
 |   return ret; | 
 | } | 
 |  | 
 | /* Compare two sections based on the locations of the sections they are | 
 |    linked to.  Used by fixup_link_order.  */ | 
 |  | 
 | static int | 
 | compare_link_order (const void *a, const void *b) | 
 | { | 
 |   const struct os_sections_input *ai = a; | 
 |   const struct os_sections_input *bi = b; | 
 |   asection *asec = NULL; | 
 |   asection *bsec = NULL; | 
 |   bfd_vma apos, bpos; | 
 |  | 
 |   if (bfd_get_flavour (ai->is->section->owner) == bfd_target_elf_flavour) | 
 |     asec = elf_linked_to_section (ai->is->section); | 
 |   if (bfd_get_flavour (bi->is->section->owner) == bfd_target_elf_flavour) | 
 |     bsec = elf_linked_to_section (bi->is->section); | 
 |  | 
 |   /* Place unordered sections before ordered sections.  */ | 
 |   if (asec == NULL || bsec == NULL) | 
 |     { | 
 |       if (bsec != NULL) | 
 | 	return -1; | 
 |       else if (asec != NULL) | 
 | 	return 1; | 
 |       return ai->idx - bi->idx; | 
 |     } | 
 |  | 
 |   apos = asec->output_section->lma + asec->output_offset; | 
 |   bpos = bsec->output_section->lma + bsec->output_offset; | 
 |  | 
 |   if (apos < bpos) | 
 |     return -1; | 
 |   else if (apos > bpos) | 
 |     return 1; | 
 |  | 
 |   if (! bfd_link_relocatable (&link_info)) | 
 |     { | 
 |       /* The only way we should get matching LMAs is when the first of | 
 | 	 the two sections has zero size, or asec and bsec are the | 
 | 	 same section.  */ | 
 |       if (asec->size < bsec->size) | 
 | 	return -1; | 
 |       else if (asec->size > bsec->size) | 
 | 	return 1; | 
 |     } | 
 |  | 
 |   /* If they are both zero size then they almost certainly have the same | 
 |      VMA and thus are not ordered with respect to each other.  Test VMA | 
 |      anyway, and fall back to idx to make the result reproducible across | 
 |      qsort implementations.  */ | 
 |   apos = asec->output_section->vma + asec->output_offset; | 
 |   bpos = bsec->output_section->vma + bsec->output_offset; | 
 |   if (apos < bpos) | 
 |     return -1; | 
 |   else if (apos > bpos) | 
 |     return 1; | 
 |   else | 
 |     return ai->idx - bi->idx; | 
 | } | 
 |  | 
 | /* Rearrange sections with SHF_LINK_ORDER into the same order as their | 
 |    linked sections.  */ | 
 |  | 
 | static bool | 
 | fixup_link_order (lang_output_section_statement_type *os) | 
 | { | 
 |   struct os_sections *os_info = os->data; | 
 |   unsigned int i, j; | 
 |   lang_input_section_type **orig_is; | 
 |   asection **save_s; | 
 |  | 
 |   for (i = 0; i < os_info->count; i = j) | 
 |     { | 
 |       /* Normally a linker script will select SHF_LINK_ORDER sections | 
 | 	 with an input section wildcard something like the following: | 
 | 	 *(.IA_64.unwind* .gnu.linkonce.ia64unw.*) | 
 | 	 However if some other random sections are smashed into an | 
 | 	 output section, or if SHF_LINK_ORDER are split up by the | 
 | 	 linker script, then we only want to sort sections matching a | 
 | 	 given wildcard.  That's the purpose of the pattern test.  */ | 
 |       for (j = i + 1; j < os_info->count; j++) | 
 | 	if (os_info->isec[j].is->pattern != os_info->isec[i].is->pattern) | 
 | 	  break; | 
 |       if (j - i > 1) | 
 | 	qsort (&os_info->isec[i], j - i, sizeof (*os_info->isec), | 
 | 	       compare_link_order); | 
 |     } | 
 |   for (i = 0; i < os_info->count; i++) | 
 |     if (os_info->isec[i].idx != i) | 
 |       break; | 
 |   if (i == os_info->count) | 
 |     return false; | 
 |  | 
 |   /* Now reorder the linker input section statements to reflect the | 
 |      proper sorting.  The is done by rewriting the existing statements | 
 |      rather than fiddling with lists, since the only thing we need to | 
 |      change is the bfd section pointer.  */ | 
 |   orig_is = xmalloc (os_info->count * sizeof (*orig_is)); | 
 |   save_s = xmalloc (os_info->count * sizeof (*save_s)); | 
 |   for (i = 0; i < os_info->count; i++) | 
 |     { | 
 |       orig_is[os_info->isec[i].idx] = os_info->isec[i].is; | 
 |       save_s[i] = os_info->isec[i].is->section; | 
 |     } | 
 |   for (i = 0; i < os_info->count; i++) | 
 |     if (os_info->isec[i].idx != i) | 
 |       { | 
 | 	orig_is[i]->section = save_s[i]; | 
 | 	/* Restore os_info to pristine state before the qsort, for the | 
 | 	   next pass over sections.  */ | 
 | 	os_info->isec[i].is = orig_is[i]; | 
 | 	os_info->isec[i].idx = i; | 
 |       } | 
 |   free (save_s); | 
 |   free (orig_is); | 
 |   return true; | 
 | } | 
 |  | 
 | void | 
 | ldelf_map_segments (bool need_layout) | 
 | { | 
 |   int tries = 10; | 
 |   static bool done_link_order_scan = false; | 
 |  | 
 |   do | 
 |     { | 
 |       lang_relax_sections (need_layout); | 
 |       need_layout = false; | 
 |  | 
 |       if (bfd_get_flavour (link_info.output_bfd) == bfd_target_elf_flavour) | 
 | 	{ | 
 | 	  lang_output_section_statement_type *os; | 
 | 	  if (!done_link_order_scan) | 
 | 	    { | 
 | 	      link_order_scan (statement_list.head, NULL); | 
 | 	      done_link_order_scan = true; | 
 | 	    } | 
 | 	  for (os = (void *) lang_os_list.head; os != NULL; os = os->next) | 
 | 	    { | 
 | 	      struct os_sections *os_info = os->data; | 
 | 	      if (os_info != NULL && os_info->ordered != 0) | 
 | 		{ | 
 | 		  if (os_info->ordered != os_info->count | 
 | 		      && bfd_link_relocatable (&link_info)) | 
 | 		    { | 
 | 		      fatal (_("%P: " | 
 | 			       "%pA has both ordered and unordered sections\n"), | 
 | 			     os->bfd_section); | 
 | 		      return; | 
 | 		    } | 
 | 		  if (os_info->count > 1 | 
 | 		      && fixup_link_order (os)) | 
 | 		    need_layout = true; | 
 | 		} | 
 | 	    } | 
 | 	} | 
 |  | 
 |       if (bfd_get_flavour (link_info.output_bfd) == bfd_target_elf_flavour | 
 | 	  && !bfd_link_relocatable (&link_info)) | 
 | 	{ | 
 | 	  bfd_size_type phdr_size; | 
 |  | 
 | 	  phdr_size = elf_program_header_size (link_info.output_bfd); | 
 | 	  /* If we don't have user supplied phdrs, throw away any | 
 | 	     previous linker generated program headers.  */ | 
 | 	  if (lang_phdr_list == NULL) | 
 | 	    elf_seg_map (link_info.output_bfd) = NULL; | 
 | 	  if (!_bfd_elf_map_sections_to_segments (link_info.output_bfd, | 
 | 						  &link_info, | 
 | 						  &need_layout)) | 
 | 	    fatal (_("%P: map sections to segments failed: %E\n")); | 
 |  | 
 | 	  if (phdr_size != elf_program_header_size (link_info.output_bfd)) | 
 | 	    { | 
 | 	      if (tries > 6) | 
 | 		/* The first few times we allow any change to | 
 | 		   phdr_size .  */ | 
 | 		need_layout = true; | 
 | 	      else if (phdr_size | 
 | 		       < elf_program_header_size (link_info.output_bfd)) | 
 | 		/* After that we only allow the size to grow.  */ | 
 | 		need_layout = true; | 
 | 	      else | 
 | 		elf_program_header_size (link_info.output_bfd) = phdr_size; | 
 | 	    } | 
 | 	} | 
 |     } | 
 |   while (need_layout && --tries); | 
 |  | 
 |   if (tries == 0) | 
 |     fatal (_("%P: looping in map_segments\n")); | 
 |  | 
 |   if (bfd_get_flavour (link_info.output_bfd) == bfd_target_elf_flavour | 
 |       && lang_phdr_list == NULL) | 
 |     { | 
 |       /* If we don't have user supplied phdrs, strip zero-sized dynamic | 
 | 	 sections and regenerate program headers.  */ | 
 |       const struct elf_backend_data *bed | 
 | 	= get_elf_backend_data (link_info.output_bfd); | 
 |       if (bed->elf_backend_strip_zero_sized_dynamic_sections | 
 | 	  && !bed->elf_backend_strip_zero_sized_dynamic_sections (&link_info)) | 
 | 	fatal (_("%P: failed to strip zero-sized dynamic sections\n")); | 
 |     } | 
 | } | 
 |  | 
 | #ifdef ENABLE_LIBCTF | 
 | /* We want to emit CTF early if and only if we are not targetting ELF with this | 
 |    invocation.  */ | 
 |  | 
 | int | 
 | ldelf_emit_ctf_early (void) | 
 | { | 
 |   if (bfd_get_flavour (link_info.output_bfd) == bfd_target_elf_flavour) | 
 |     return 0; | 
 |   return 1; | 
 | } | 
 |  | 
 | /* Callbacks used to map from bfd types to libctf types, under libctf's | 
 |    control.  */ | 
 |  | 
 | struct ctf_strtab_iter_cb_arg | 
 | { | 
 |   struct elf_strtab_hash *strtab; | 
 |   size_t next_i; | 
 |   size_t next_idx; | 
 | }; | 
 |  | 
 | /* Return strings from the strtab to libctf, one by one.  Returns NULL when | 
 |    iteration is complete.  */ | 
 |  | 
 | static const char * | 
 | ldelf_ctf_strtab_iter_cb (uint32_t *offset, void *arg_) | 
 | { | 
 |   bfd_size_type off; | 
 |   const char *ret; | 
 |  | 
 |   struct ctf_strtab_iter_cb_arg *arg = | 
 |     (struct ctf_strtab_iter_cb_arg *) arg_; | 
 |  | 
 |   /* There is no zeroth string.  */ | 
 |   if (arg->next_i == 0) | 
 |     arg->next_i = 1; | 
 |  | 
 |   /* Hunt through strings until we fall off the end or find one with | 
 |      a nonzero refcount.  */ | 
 |   do | 
 |     { | 
 |       if (arg->next_i >= _bfd_elf_strtab_len (arg->strtab)) | 
 | 	{ | 
 | 	  arg->next_i = 0; | 
 | 	  return NULL; | 
 | 	} | 
 |  | 
 |       ret = _bfd_elf_strtab_str (arg->strtab, arg->next_i++, &off); | 
 |     } | 
 |   while (ret == NULL); | 
 |  | 
 |   *offset = off; | 
 |  | 
 |   /* If we've overflowed, we cannot share any further strings: the CTF | 
 |      format cannot encode strings with such high offsets.  */ | 
 |   if (*offset != off) | 
 |     return NULL; | 
 |  | 
 |   return ret; | 
 | } | 
 |  | 
 | void | 
 | ldelf_acquire_strings_for_ctf | 
 |   (struct ctf_dict *ctf_output, struct elf_strtab_hash *strtab) | 
 | { | 
 |   struct ctf_strtab_iter_cb_arg args = { strtab, 0, 0 }; | 
 |   if (!ctf_output) | 
 |     return; | 
 |  | 
 |   if (bfd_get_flavour (link_info.output_bfd) == bfd_target_elf_flavour) | 
 |     { | 
 |       if (ctf_link_add_strtab (ctf_output, ldelf_ctf_strtab_iter_cb, | 
 | 			       &args) < 0) | 
 | 	fatal (_("%P: warning: CTF strtab association failed; strings will " | 
 | 		 "not be shared: %s\n"), | 
 | 	       ctf_errmsg (ctf_errno (ctf_output))); | 
 |     } | 
 | } | 
 |  | 
 | void | 
 | ldelf_new_dynsym_for_ctf (struct ctf_dict *ctf_output, int symidx, | 
 | 			  struct elf_internal_sym *sym) | 
 | { | 
 |   ctf_link_sym_t lsym; | 
 |  | 
 |   if (!ctf_output) | 
 |      return; | 
 |  | 
 |   /* New symbol.  */ | 
 |   if (sym != NULL) | 
 |     { | 
 |       lsym.st_name = NULL; | 
 |       lsym.st_nameidx = sym->st_name; | 
 |       lsym.st_nameidx_set = 1; | 
 |       lsym.st_symidx = symidx; | 
 |       lsym.st_shndx = sym->st_shndx; | 
 |       lsym.st_type = ELF_ST_TYPE (sym->st_info); | 
 |       lsym.st_value = sym->st_value; | 
 |       if (ctf_link_add_linker_symbol (ctf_output, &lsym) < 0) | 
 | 	{ | 
 | 	  fatal (_("%P: warning: CTF symbol addition failed; CTF will " | 
 | 		   "not be tied to symbols: %s\n"), | 
 | 		 ctf_errmsg (ctf_errno (ctf_output))); | 
 | 	} | 
 |     } | 
 |   else | 
 |     { | 
 |       /* Shuffle all the symbols.  */ | 
 |  | 
 |       if (ctf_link_shuffle_syms (ctf_output) < 0) | 
 | 	fatal (_("%P: warning: CTF symbol shuffling failed; CTF will " | 
 | 		 "not be tied to symbols: %s\n"), | 
 | 	       ctf_errmsg (ctf_errno (ctf_output))); | 
 |     } | 
 | } | 
 | #else | 
 | int | 
 | ldelf_emit_ctf_early (void) | 
 | { | 
 |   return 0; | 
 | } | 
 |  | 
 | void | 
 | ldelf_acquire_strings_for_ctf (struct ctf_dict *ctf_output ATTRIBUTE_UNUSED, | 
 | 			       struct elf_strtab_hash *strtab ATTRIBUTE_UNUSED) | 
 | {} | 
 | void | 
 | ldelf_new_dynsym_for_ctf (struct ctf_dict *ctf_output ATTRIBUTE_UNUSED, | 
 | 			  int symidx ATTRIBUTE_UNUSED, | 
 | 			  struct elf_internal_sym *sym ATTRIBUTE_UNUSED) | 
 | {} | 
 | #endif |