PR ld/10515
[binutils-gdb.git] / gold / target-reloc.h
index c5bb4f1dc7853443188dfec3e57bec3c927c01f5..d93e7552888bb71a432d7cc8324964e967354c45 100644 (file)
@@ -78,10 +78,12 @@ scan_relocs(
          gold_assert(plocal_syms != NULL);
          typename elfcpp::Sym<size, big_endian> lsym(plocal_syms
                                                      + r_sym * sym_size);
-         const unsigned int shndx = lsym.get_st_shndx();
-         if (shndx < elfcpp::SHN_LORESERVE
+         unsigned int shndx = lsym.get_st_shndx();
+         bool is_ordinary;
+         shndx = object->adjust_sym_shndx(r_sym, shndx, &is_ordinary);
+         if (is_ordinary
              && shndx != elfcpp::SHN_UNDEF
-             && !object->is_section_included(lsym.get_st_shndx()))
+             && !object->is_section_included(shndx))
            {
              // RELOC is a relocation against a local symbol in a
              // section we are discarding.  We can ignore this
@@ -117,6 +119,31 @@ scan_relocs(
     }
 }
 
+// Behavior for relocations to discarded comdat sections.
+
+enum Comdat_behavior
+{
+  CB_UNDETERMINED,   // Not yet determined -- need to look at section name.
+  CB_PRETEND,        // Attempt to map to the corresponding kept section.
+  CB_IGNORE,         // Ignore the relocation.
+  CB_WARNING         // Print a warning.
+};
+
+// Decide what the linker should do for relocations that refer to discarded
+// comdat sections.  This decision is based on the name of the section being
+// relocated.
+
+inline Comdat_behavior
+get_comdat_behavior(const char* name)
+{
+  if (Layout::is_debug_info_section(name))
+    return CB_PRETEND;
+  if (strcmp(name, ".eh_frame") == 0
+      || strcmp(name, ".gcc_except_table") == 0)
+    return CB_IGNORE;
+  return CB_WARNING;
+}
+
 // This function implements the generic part of relocation processing.
 // The template parameter Relocate must be a class type which provides
 // a single function, relocate(), which implements the machine
@@ -157,6 +184,8 @@ relocate_section(
   Sized_relobj<size, big_endian>* object = relinfo->object;
   unsigned int local_count = object->local_symbol_count();
 
+  Comdat_behavior comdat_behavior = CB_UNDETERMINED;
+
   for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size)
     {
       Reltype reloc(prelocs);
@@ -185,6 +214,45 @@ relocate_section(
        {
          sym = NULL;
          psymval = object->local_symbol(r_sym);
+
+          // If the local symbol belongs to a section we are discarding,
+          // and that section is a debug section, try to find the
+          // corresponding kept section and map this symbol to its
+          // counterpart in the kept section.  The symbol must not 
+          // correspond to a section we are folding.
+         bool is_ordinary;
+         unsigned int shndx = psymval->input_shndx(&is_ordinary);
+         if (is_ordinary
+             && shndx != elfcpp::SHN_UNDEF
+             && !object->is_section_included(shndx) 
+              && !(relinfo->symtab->is_section_folded(object, shndx)))
+           {
+             if (comdat_behavior == CB_UNDETERMINED)
+               {
+                 std::string name = object->section_name(relinfo->data_shndx);
+                 comdat_behavior = get_comdat_behavior(name.c_str());
+               }
+             if (comdat_behavior == CB_PRETEND)
+               {
+                  bool found;
+                 typename elfcpp::Elf_types<size>::Elf_Addr value =
+                   object->map_to_kept_section(shndx, &found);
+                 if (found)
+                   symval.set_output_value(value + psymval->input_value());
+                  else
+                    symval.set_output_value(0);
+               }
+             else
+               {
+                 if (comdat_behavior == CB_WARNING)
+                    gold_warning_at_location(relinfo, i, offset,
+                                             _("Relocation refers to discarded "
+                                               "comdat section"));
+                  symval.set_output_value(0);
+               }
+             symval.set_no_output_symtab_entry();
+             psymval = &symval;
+           }
        }
       else
        {
@@ -202,8 +270,9 @@ relocate_section(
          psymval = &symval;
        }
 
-      if (!relocate.relocate(relinfo, target, i, reloc, r_type, sym, psymval,
-                            view + offset, view_address + offset, view_size))
+      if (!relocate.relocate(relinfo, target, output_section, i, reloc,
+                            r_type, sym, psymval, view + offset,
+                            view_address + offset, view_size))
        continue;
 
       if (offset < 0 || static_cast<section_size_type>(offset) >= view_size)
@@ -217,8 +286,10 @@ relocate_section(
       if (sym != NULL
          && sym->is_undefined()
          && sym->binding() != elfcpp::STB_WEAK
-         && !parameters->options().shared())
-       gold_undefined_symbol(sym, relinfo, i, offset);
+          && !target->is_defined_by_abi(sym)
+         && (!parameters->options().shared()       // -shared
+              || parameters->options().defs()))     // -z defs
+       gold_undefined_symbol_at_location(sym, relinfo, i, offset);
 
       if (sym != NULL && sym->has_warning())
        relinfo->symtab->issue_warning(sym, relinfo, i, offset);
@@ -240,8 +311,14 @@ class Default_scan_relocatable_relocs
   // Return the strategy to use for a local symbol which is not a
   // section symbol, given the relocation type.
   inline Relocatable_relocs::Reloc_strategy
-  local_non_section_strategy(unsigned int, Relobj*)
-  { return Relocatable_relocs::RELOC_COPY; }
+  local_non_section_strategy(unsigned int r_type, Relobj*, unsigned int r_sym)
+  {
+    // We assume that relocation type 0 is NONE.  Targets which are
+    // different must override.
+    if (r_type == 0 && r_sym == 0)
+      return Relocatable_relocs::RELOC_DISCARD;
+    return Relocatable_relocs::RELOC_COPY;
+  }
 
   // Return the strategy to use for a local symbol which is a section
   // symbol, given the relocation type.
@@ -332,10 +409,12 @@ scan_relocatable_relocs(
              gold_assert(plocal_syms != NULL);
              typename elfcpp::Sym<size, big_endian> lsym(plocal_syms
                                                          + r_sym * sym_size);
-             const unsigned int shndx = lsym.get_st_shndx();
-             if (shndx < elfcpp::SHN_LORESERVE
+             unsigned int shndx = lsym.get_st_shndx();
+             bool is_ordinary;
+             shndx = object->adjust_sym_shndx(r_sym, shndx, &is_ordinary);
+             if (is_ordinary
                  && shndx != elfcpp::SHN_UNDEF
-                 && !object->is_section_included(lsym.get_st_shndx()))
+                 && !object->is_section_included(shndx))
                {
                  // RELOC is a relocation against a local symbol
                  // defined in a section we are discarding.  Discard
@@ -343,17 +422,13 @@ scan_relocatable_relocs(
                  strategy = Relocatable_relocs::RELOC_DISCARD;
                }
              else if (lsym.get_st_type() != elfcpp::STT_SECTION)
-               strategy = scan.local_non_section_strategy(r_type, object);
+               strategy = scan.local_non_section_strategy(r_type, object,
+                                                          r_sym);
              else
                {
                  strategy = scan.local_section_strategy(r_type, object);
                  if (strategy != Relocatable_relocs::RELOC_DISCARD)
-                   {
-                     section_offset_type dummy;
-                     Output_section* os = object->output_section(shndx,
-                                                                 &dummy);
-                     os->set_needs_symtab_index();
-                   }
+                    object->output_section(shndx)->set_needs_symtab_index();
                }
            }
        }
@@ -372,7 +447,7 @@ relocate_for_relocatable(
     const unsigned char* prelocs,
     size_t reloc_count,
     Output_section* output_section,
-    off_t offset_in_output_section,
+    typename elfcpp::Elf_types<size>::Elf_Addr offset_in_output_section,
     const Relocatable_relocs* rr,
     unsigned char* view,
     typename elfcpp::Elf_types<size>::Elf_Addr view_address,
@@ -380,10 +455,12 @@ relocate_for_relocatable(
     unsigned char* reloc_view,
     section_size_type reloc_view_size)
 {
+  typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
   typedef typename Reloc_types<sh_type, size, big_endian>::Reloc Reltype;
   typedef typename Reloc_types<sh_type, size, big_endian>::Reloc_write
     Reltype_write;
   const int reloc_size = Reloc_types<sh_type, size, big_endian>::reloc_size;
+  const Address invalid_address = static_cast<Address>(0) - 1;
 
   Sized_relobj<size, big_endian>* const object = relinfo->object;
   const unsigned int local_count = object->local_symbol_count();
@@ -427,9 +504,11 @@ relocate_for_relocatable(
                // the output section corresponding to input section
                // in which this symbol is defined.
                gold_assert(r_sym < local_count);
-               unsigned int shndx = object->local_symbol_input_shndx(r_sym);
-               section_offset_type dummy;
-               Output_section* os = object->output_section(shndx, &dummy);
+               bool is_ordinary;
+               unsigned int shndx =
+                 object->local_symbol_input_shndx(r_sym, &is_ordinary);
+               gold_assert(is_ordinary);
+               Output_section* os = object->output_section(shndx);
                gold_assert(os != NULL);
                gold_assert(os->needs_symtab_index());
                new_symndx = os->symtab_index();
@@ -454,23 +533,30 @@ relocate_for_relocatable(
       // Get the new offset--the location in the output section where
       // this relocation should be applied.
 
-      off_t offset = reloc.get_r_offset();
-      off_t new_offset;
-      if (offset_in_output_section != -1)
+      Address offset = reloc.get_r_offset();
+      Address new_offset;
+      if (offset_in_output_section != invalid_address)
        new_offset = offset + offset_in_output_section;
       else
        {
-         new_offset = output_section->output_offset(object,
-                                                    relinfo->data_shndx,
-                                                    offset);
-         gold_assert(new_offset != -1);
+          section_offset_type sot_offset =
+              convert_types<section_offset_type, Address>(offset);
+         section_offset_type new_sot_offset =
+              output_section->output_offset(object, relinfo->data_shndx,
+                                            sot_offset);
+         gold_assert(new_sot_offset != -1);
+          new_offset = new_sot_offset;
        }
 
       // In an object file, r_offset is an offset within the section.
       // In an executable or dynamic object, generated by
       // --emit-relocs, r_offset is an absolute address.
       if (!parameters->options().relocatable())
-       new_offset += view_address;
+       {
+         new_offset += view_address;
+         if (offset_in_output_section != invalid_address)
+           new_offset -= offset_in_output_section;
+       }
 
       reloc_write.put_r_offset(new_offset);
       reloc_write.put_r_info(elfcpp::elf_r_info<size>(new_symndx, r_type));