* libnlm.h (nlm_backend_data): Added nlm_mangle_relocs.
[external/binutils.git] / bfd / nlmcode.h
index 4c1679d..43ea019 100644 (file)
@@ -1337,7 +1337,14 @@ nlm_canonicalize_reloc (abfd, sec, relptr, symbols)
    no way to check this.
 
    This routine also sets the Size and Offset fields in the fixed
-   header.  */
+   header.
+
+   It also looks over the symbols and moves any common symbols into
+   the .bss section; NLM has no way to represent a common symbol.
+   This approach means that either the symbols must already have been
+   set at this point, or there must be no common symbols.  We need to
+   move the symbols at this point so that mangle_relocs can see the
+   final values.  */
 
 static boolean
 nlm_compute_section_file_positions (abfd)
@@ -1349,6 +1356,7 @@ nlm_compute_section_file_positions (abfd)
   bfd_vma text_low, data_low;
   int text_align, data_align, other_align;
   file_ptr text_ptr, data_ptr, other_ptr;
+  asymbol **sym_ptr_ptr;
 
   if (abfd->output_has_begun == true)
     return true;
@@ -1469,6 +1477,53 @@ nlm_compute_section_file_positions (abfd)
 
   nlm_fixed_header (abfd)->relocationFixupOffset = other_ptr;
 
+  /* Move all common symbols into the .bss section.  */
+
+  sym_ptr_ptr = bfd_get_outsymbols (abfd);
+  if (sym_ptr_ptr != NULL)
+    {
+      asymbol **sym_end;
+      asection *bss_sec;
+      bfd_vma add;
+
+      /* Make sure we have a section to hold uninitialized data.  */
+      bss_sec = bfd_get_section_by_name (abfd, NLM_UNINITIALIZED_DATA_NAME);
+      if (bss_sec == NULL)
+       {
+         if (! add_bfd_section (abfd, NLM_UNINITIALIZED_DATA_NAME,
+                                (file_ptr) 0, (bfd_size_type) 0,
+                                SEC_ALLOC))
+           return false;
+         bss_sec = bfd_get_section_by_name (abfd,
+                                            NLM_UNINITIALIZED_DATA_NAME);
+         bss_sec->vma = data_low + data;
+       }
+
+      sym_end = sym_ptr_ptr + bfd_get_symcount (abfd);
+      add = 0;
+      for (; sym_ptr_ptr < sym_end; sym_ptr_ptr++)
+       {
+         asymbol *sym;
+         bfd_vma size;
+
+         sym = *sym_ptr_ptr;
+
+         if (! bfd_is_com_section (bfd_get_section (sym)))
+           continue;
+
+         /* Put the common symbol in the .bss section, and increase
+            the size of the .bss section by the size of the common
+            symbol (which is the old value of the symbol).  */
+         sym->section = bss_sec;
+         size = sym->value;
+         sym->value = bss_sec->_raw_size + add;
+         add += size;
+         add = BFD_ALIGN (add, 1 << bss_sec->alignment_power);
+       }
+      nlm_fixed_header (abfd)->uninitializedDataSize += add;
+      bss_sec->_raw_size += add;
+    }
+
   return true;
 }
 
@@ -1492,6 +1547,25 @@ nlm_set_section_contents (abfd, section, location, offset, count)
   if (count == 0)
     return true;
 
+  /* i386 NetWare has a very restricted set of relocs.  In order for
+     objcopy to work, the NLM i386 backend needs a chance to rework
+     the section contents so that its set of relocs will work.  If all
+     the relocs are already acceptable, this will not do anything.  */
+  if (section->reloc_count != 0)
+    {
+      boolean (*mangle_relocs_func) PARAMS ((bfd *, asection *, PTR data,
+                                            bfd_vma offset,
+                                            bfd_size_type count));
+
+      mangle_relocs_func = nlm_mangle_relocs_func (abfd);
+      if (mangle_relocs_func != NULL)
+       {
+         if (! (*mangle_relocs_func) (abfd, section, location,
+                                      (bfd_vma) offset, count))
+           return false;
+       }
+    }
+
   if (bfd_seek (abfd, (file_ptr) (section->filepos + offset), SEEK_SET) != 0
       || bfd_write (location, 1, count, abfd) != count)
     {
@@ -1637,7 +1711,7 @@ nlm_write_object_contents (abfd)
          rel = *rel_ptr_ptr;
          sym = *rel->sym_ptr_ptr;
 
-         if ((sym->flags & BSF_SECTION_SYM) != 0)
+         if (bfd_get_section (sym) != &bfd_und_section)
            {
              ++internal_reloc_count;
              if ((*write_reloc_func) (abfd, sec, rel) == false)
@@ -1680,7 +1754,7 @@ nlm_write_object_contents (abfd)
          rel = *rel_ptr_ptr;
          sym = *rel->sym_ptr_ptr;
 
-         if ((sym->flags & BSF_SECTION_SYM) != 0)
+         if (bfd_get_section (sym) != &bfd_und_section)
            continue;
 
          external_relocs[i].rel = rel;
@@ -1704,7 +1778,7 @@ nlm_write_object_contents (abfd)
       arelent *rel;
       asymbol *sym;
       bfd_byte len;
-      bfd_size_type cnt;
+      bfd_size_type j, cnt;
       bfd_byte temp[NLM_TARGET_LONG_SIZE];
 
       ++c;
@@ -1722,8 +1796,10 @@ nlm_write_object_contents (abfd)
        }
 
       cnt = 0;
-      while (i < external_reloc_count
-            && *external_relocs[i].rel->sym_ptr_ptr == sym)
+      for (j = i;
+          (j < external_reloc_count
+           && *external_relocs[j].rel->sym_ptr_ptr == sym);
+          j++)
        ++cnt;
 
       put_word (abfd, (bfd_vma) cnt, temp);
@@ -1762,7 +1838,8 @@ nlm_write_object_contents (abfd)
 
          sym = *sym_ptr_ptr;
 
-         if ((sym->flags & (BSF_EXPORT | BSF_GLOBAL)) == 0)
+         if ((sym->flags & (BSF_EXPORT | BSF_GLOBAL)) == 0
+             || bfd_get_section (sym) == &bfd_und_section)
            continue;
 
          ++c;
@@ -1783,8 +1860,9 @@ nlm_write_object_contents (abfd)
              offset -= nlm_get_text_low (abfd);
              offset |= NLM_HIBIT;
            }
-         else if (sec->flags & SEC_DATA)
+         else if (sec->flags & (SEC_DATA | SEC_ALLOC))
            {
+             /* SEC_ALLOC is for the .bss section.  */
              offset -= nlm_get_data_low (abfd);
            }
          else
@@ -1806,6 +1884,7 @@ nlm_write_object_contents (abfd)
 
       nlm_fixed_header (abfd)->debugInfoOffset = bfd_tell (abfd);
       c = 0;
+      sym_ptr_ptr = bfd_get_outsymbols (abfd);
       sym_end = sym_ptr_ptr + bfd_get_symcount (abfd);
       for (; sym_ptr_ptr < sym_end; sym_ptr_ptr++)
        {
@@ -1817,6 +1896,14 @@ nlm_write_object_contents (abfd)
 
          sym = *sym_ptr_ptr;
 
+         /* The NLM notion of a debugging symbol is actually what BFD
+            calls a local or global symbol.  What BFD calls a
+            debugging symbol NLM does not understand at all.  */
+         if ((sym->flags & (BSF_LOCAL | BSF_GLOBAL | BSF_EXPORT)) == 0
+             || (sym->flags & BSF_DEBUGGING) != 0
+             || bfd_get_section (sym) == &bfd_und_section)
+           continue;
+
          ++c;
 
          offset = bfd_asymbol_value (sym);
@@ -1826,15 +1913,15 @@ nlm_write_object_contents (abfd)
              offset -= nlm_get_text_low (abfd);
              type = 1;
            }
-         else if (sec->flags & SEC_DATA)
+         else if (sec->flags & (SEC_DATA | SEC_ALLOC))
            {
              offset -= nlm_get_data_low (abfd);
              type = 0;
            }
          else
-           type = 3;
+           type = 2;
 
-         /* The type is 0 for data, 1 for code, 3 for absolute.  */
+         /* The type is 0 for data, 1 for code, 2 for absolute.  */
          if (bfd_write (&type, sizeof (bfd_byte), 1, abfd)
              != sizeof (bfd_byte))
            {
@@ -1905,12 +1992,8 @@ nlm_write_object_contents (abfd)
   /* We have no convenient way for the caller to pass in the exit
      procedure or the check unload procedure, so the caller must set
      the values in the header to the values of the symbols.  */
-  if (nlm_fixed_header (abfd)->exitProcedureOffset == 0)
-    {
-      bfd_error = invalid_operation;
-      return false;
-    }
-  nlm_fixed_header (abfd)->exitProcedureOffset -= nlm_get_text_low (abfd);
+  if (nlm_fixed_header (abfd)->exitProcedureOffset != 0)
+    nlm_fixed_header (abfd)->exitProcedureOffset -= nlm_get_text_low (abfd);
   if (nlm_fixed_header (abfd)->checkUnloadProcedureOffset != 0)
     nlm_fixed_header (abfd)->checkUnloadProcedureOffset -=
       nlm_get_text_low (abfd);