bfd/
authorRichard Sandiford <rdsandiford@googlemail.com>
Sat, 14 Mar 2009 09:18:22 +0000 (09:18 +0000)
committerRichard Sandiford <rdsandiford@googlemail.com>
Sat, 14 Mar 2009 09:18:22 +0000 (09:18 +0000)
* xcofflink.c: (xcoff_mark_symbol): Mark the TOC section when
creating a descriptor.
(xcoff_sweep): Don't mark toc_section unless it's needed.
(bfd_xcoff_size_dynamic_sections): Skip the toc_section
when marking every bfd.
(xcoff_link_input_bfd): Skip all TOC anchors.
(xcoff_toc_section_p, xcoff_find_tc0): New functions.
(_bfd_xcoff_bfd_final_link): Don't set the output bfd's TOC anchor
to -1; call xcoff_find_tc0 instead.

ld/testsuite/
* ld-powerpc/aix-toc-1.ex, ld-powerpc/aix-toc-1a.s,
ld-powerpc/aix-toc-1b.s, ld-powerpc/aix-toc-1-32.dd,
ld-powerpc/aix-toc-1-64.dd: New tests.
* ld-powerpc/aix52.exp: Run them.

bfd/ChangeLog
bfd/xcofflink.c
ld/testsuite/ChangeLog
ld/testsuite/ld-powerpc/aix-toc-1-32.dd [new file with mode: 0644]
ld/testsuite/ld-powerpc/aix-toc-1-64.dd [new file with mode: 0644]
ld/testsuite/ld-powerpc/aix-toc-1.ex [new file with mode: 0644]
ld/testsuite/ld-powerpc/aix-toc-1a.s [new file with mode: 0644]
ld/testsuite/ld-powerpc/aix-toc-1b.s [new file with mode: 0644]
ld/testsuite/ld-powerpc/aix52.exp

index 3a8c0e646e6705914cbeba44c8291aecab0b850f..0bd0d16500c94c46614fd4cd4d350cd149139279 100644 (file)
@@ -1,3 +1,15 @@
+2009-03-14  Richard Sandiford  <r.sandiford@uk.ibm.com>
+
+       * xcofflink.c: (xcoff_mark_symbol): Mark the TOC section when
+       creating a descriptor.
+       (xcoff_sweep): Don't mark toc_section unless it's needed.
+       (bfd_xcoff_size_dynamic_sections): Skip the toc_section
+       when marking every bfd.
+       (xcoff_link_input_bfd): Skip all TOC anchors.
+       (xcoff_toc_section_p, xcoff_find_tc0): New functions.
+       (_bfd_xcoff_bfd_final_link): Don't set the output bfd's TOC anchor
+       to -1; call xcoff_find_tc0 instead.
+
 2009-03-14  Richard Sandiford  <r.sandiford@uk.ibm.com>
 
        * libcoff-in.h (xcoff_section_tdata): Update commentary.
index d12ed51a9887dc76ec6913a3334c6c82f96d7c1f..c6bdc9fe2c1062b626a3e9931ea5be907be26a7d 100644 (file)
@@ -2331,6 +2331,11 @@ xcoff_mark_symbol (struct bfd_link_info *info, struct xcoff_link_hash_entry *h)
          if (!xcoff_mark_symbol (info, h->descriptor))
            return FALSE;
 
+         /* Mark the TOC section, so that we get an anchor
+            to relocate against.  */
+         if (!xcoff_mark (info, xcoff_hash_table (info)->toc_section))
+           return FALSE;
+
          /* We handle writing out the contents of the descriptor in
             xcoff_write_global_symbol.  */
        }
@@ -2590,7 +2595,6 @@ xcoff_sweep (struct bfd_link_info *info)
                  || o == xcoff_hash_table (info)->debug_section
                  || o == xcoff_hash_table (info)->loader_section
                  || o == xcoff_hash_table (info)->linkage_section
-                 || o == xcoff_hash_table (info)->toc_section
                  || o == xcoff_hash_table (info)->descriptor_section
                  || strcmp (o->name, ".debug") == 0)
                o->flags |= SEC_MARK;
@@ -3126,7 +3130,12 @@ bfd_xcoff_size_dynamic_sections (bfd *output_bfd,
 
          for (o = sub->sections; o != NULL; o = o->next)
            {
-             if ((o->flags & SEC_MARK) == 0)
+             /* We shouldn't unconditionaly mark the TOC section.
+                The output file should only have a TOC if either
+                (a) one of the input files did or (b) we end up
+                creating TOC references as part of the link process.  */
+             if (o != xcoff_hash_table (info)->toc_section
+                 && (o->flags & SEC_MARK) == 0)
                {
                  if (! xcoff_mark (info, o))
                    goto error_return;
@@ -3504,7 +3513,6 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo,
       union internal_auxent aux;
       int smtyp = 0;
       bfd_boolean skip;
-      bfd_boolean require;
       int add;
 
       bfd_coff_swap_sym_in (input_bfd, (void *) esym, (void *) isymp);
@@ -3623,7 +3631,6 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo,
       *indexp = -1;
 
       skip = FALSE;
-      require = FALSE;
       add = 1 + isym.n_numaux;
 
       /* If we are skipping this csect, we want to skip this symbol.  */
@@ -3644,75 +3651,11 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo,
          && isymp->n_sclass == C_STAT)
        skip = TRUE;
 
-      /* We skip all but the first TOC anchor.  */
+      /* We generate the TOC anchor separately.  */
       if (! skip
          && isymp->n_sclass == C_HIDEXT
          && aux.x_csect.x_smclas == XMC_TC0)
-       {
-         if (finfo->toc_symindx != -1)
-           skip = TRUE;
-         else
-           {
-             bfd_vma tocval, tocend;
-             bfd *inp;
-
-             tocval = ((*csectpp)->output_section->vma
-                       + (*csectpp)->output_offset
-                       + isym.n_value
-                       - (*csectpp)->vma);
-
-             /* We want to find out if tocval is a good value to use
-                as the TOC anchor--that is, whether we can access all
-                of the TOC using a 16 bit offset from tocval.  This
-                test assumes that the TOC comes at the end of the
-                output section, as it does in the default linker
-                script.  */
-             tocend = ((*csectpp)->output_section->vma
-                       + (*csectpp)->output_section->size);
-             for (inp = finfo->info->input_bfds;
-                  inp != NULL;
-                  inp = inp->link_next)
-               {
-
-                 for (o = inp->sections; o != NULL; o = o->next)
-                   if (strcmp (o->name, ".tocbss") == 0)
-                     {
-                       bfd_vma new_toc_end;
-                       new_toc_end = (o->output_section->vma
-                                      + o->output_offset
-                                      + o->size);
-                       if (new_toc_end > tocend)
-                         tocend = new_toc_end;
-                     }
-
-               }
-
-             if (tocval + 0x10000 < tocend)
-               {
-                 (*_bfd_error_handler)
-                   (_("TOC overflow: 0x%lx > 0x10000; try -mminimal-toc when compiling"),
-                    (unsigned long) (tocend - tocval));
-                 bfd_set_error (bfd_error_file_too_big);
-                 return FALSE;
-               }
-
-             if (tocval + 0x8000 < tocend)
-               {
-                 bfd_vma tocadd;
-
-                 tocadd = tocend - (tocval + 0x8000);
-                 tocval += tocadd;
-                 isym.n_value += tocadd;
-               }
-
-             finfo->toc_symindx = output_index;
-             xcoff_data (finfo->output_bfd)->toc = tocval;
-             xcoff_data (finfo->output_bfd)->sntoc =
-               (*csectpp)->output_section->target_index;
-             require = TRUE;
-
-           }
-       }
+       skip = TRUE;
 
       /* If we are stripping all symbols, we want to skip this one.  */
       if (! skip
@@ -3781,12 +3724,6 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo,
            skip = TRUE;
        }
 
-      /* We can not skip the first TOC anchor.  */
-      if (skip
-         && require
-         && finfo->info->strip != strip_all)
-       skip = FALSE;
-
       /* We now know whether we are to skip this symbol or not.  */
       if (! skip)
        {
@@ -4616,6 +4553,144 @@ xcoff_sort_relocs (const void * p1, const void * p2)
     return 0;
 }
 
+/* Return true if section SEC is a TOC section.  */
+
+static inline bfd_boolean
+xcoff_toc_section_p (asection *sec)
+{
+  const char *name;
+
+  name = sec->name;
+  if (name[0] == '.' && name[1] == 't')
+    {
+      if (name[2] == 'c')
+       {
+         if (name[3] == '0' && name[4] == 0)
+           return TRUE;
+         if (name[3] == 0)
+           return TRUE;
+       }
+      if (name[2] == 'd' && name[3] == 0)
+       return TRUE;
+    }
+  return FALSE;
+}
+
+/* See if the link requires a TOC (it usually does!).  If so, find a
+   good place to put the TOC anchor csect, and write out the associated
+   symbol.  */
+
+static bfd_boolean
+xcoff_find_tc0 (bfd *output_bfd, struct xcoff_final_link_info *finfo)
+{
+  bfd_vma toc_start, toc_end, start, end, best_address;
+  asection *sec;
+  bfd *input_bfd;
+  int section_index;
+  struct internal_syment irsym;
+  union internal_auxent iraux;
+  file_ptr pos;
+  size_t size;
+
+  /* Set [TOC_START, TOC_END) to the range of the TOC.  Record the
+     index of a csect at the beginning of the TOC.  */
+  toc_start = ~(bfd_vma) 0;
+  toc_end = 0;
+  section_index = -1;
+  for (input_bfd = finfo->info->input_bfds;
+       input_bfd != NULL;
+       input_bfd = input_bfd->link_next)
+    for (sec = input_bfd->sections; sec != NULL; sec = sec->next)
+      if ((sec->flags & SEC_MARK) != 0 && xcoff_toc_section_p (sec))
+       {
+         start = sec->output_section->vma + sec->output_offset;
+         if (toc_start > start)
+           {
+             toc_start = start;
+             section_index = sec->output_section->target_index;
+           }
+
+         end = start + sec->size;
+         if (toc_end < end)
+           toc_end = end;
+       }
+
+  /* There's no need for a TC0 symbol if we don't have a TOC.  */
+  if (toc_end < toc_start)
+    {
+      xcoff_data (output_bfd)->toc = toc_start;
+      return TRUE;
+    }
+
+  if (toc_end - toc_start < 0x8000)
+    /* Every TOC csect can be accessed from TOC_START.  */
+    best_address = toc_start;
+  else
+    {
+      /* Find the lowest TOC csect that is still within range of TOC_END.  */
+      best_address = toc_end;
+      for (input_bfd = finfo->info->input_bfds;
+          input_bfd != NULL;
+          input_bfd = input_bfd->link_next)
+       for (sec = input_bfd->sections; sec != NULL; sec = sec->next)
+         if ((sec->flags & SEC_MARK) != 0 && xcoff_toc_section_p (sec))
+           {
+             start = sec->output_section->vma + sec->output_offset;
+             if (start < best_address
+                 && start + 0x8000 >= toc_end)
+               {
+                 best_address = start;
+                 section_index = sec->output_section->target_index;
+               }
+           }
+
+      /* Make sure that the start of the TOC is also within range.  */
+      if (best_address > toc_start + 0x8000)
+       {
+         (*_bfd_error_handler)
+           (_("TOC overflow: 0x%lx > 0x10000; try -mminimal-toc "
+              "when compiling"),
+            (unsigned long) (toc_end - toc_start));
+         bfd_set_error (bfd_error_file_too_big);
+         return FALSE;
+       }
+    }
+
+  /* Record the chosen TOC value.  */
+  finfo->toc_symindx = obj_raw_syment_count (output_bfd);
+  xcoff_data (output_bfd)->toc = best_address;
+  xcoff_data (output_bfd)->sntoc = section_index;
+
+  /* Fill out the TC0 symbol.  */
+  if (!bfd_xcoff_put_symbol_name (output_bfd, finfo->strtab, &irsym, "TOC"))
+    return FALSE;
+  irsym.n_value = best_address;
+  irsym.n_scnum = section_index;
+  irsym.n_sclass = C_HIDEXT;
+  irsym.n_type = T_NULL;
+  irsym.n_numaux = 1;
+  bfd_coff_swap_sym_out (output_bfd, &irsym, finfo->outsyms);
+
+  /* Fill out the auxillary csect information.  */
+  memset (&iraux, 0, sizeof iraux);
+  iraux.x_csect.x_smtyp = XTY_SD;
+  iraux.x_csect.x_smclas = XMC_TC0;
+  iraux.x_csect.x_scnlen.l = 0;
+  bfd_coff_swap_aux_out (output_bfd, &iraux, T_NULL, C_HIDEXT, 0, 1,
+                        finfo->outsyms + bfd_coff_symesz (output_bfd));
+
+  /* Write the contents to the file.  */
+  pos = obj_sym_filepos (output_bfd);
+  pos += obj_raw_syment_count (output_bfd) * bfd_coff_symesz (output_bfd);
+  size = 2 * bfd_coff_symesz (output_bfd);
+  if (bfd_seek (output_bfd, pos, SEEK_SET) != 0
+      || bfd_bwrite (finfo->outsyms, size, output_bfd) != size)
+    return FALSE;
+  obj_raw_syment_count (output_bfd) += 2;
+
+  return TRUE;
+}
+
 /* Write out a non-XCOFF global symbol.  */
 
 static bfd_boolean
@@ -5692,7 +5767,10 @@ _bfd_xcoff_bfd_final_link (bfd *abfd, struct bfd_link_info *info)
     goto error_return;
 
   obj_raw_syment_count (abfd) = 0;
-  xcoff_data (abfd)->toc = (bfd_vma) -1;
+
+  /* Find a TOC symbol, if we need one.  */
+  if (!xcoff_find_tc0 (abfd, &finfo))
+    goto error_return;
 
   /* We now know the position of everything in the file, except that
      we don't know the size of the symbol table and therefore we don't
index bc20d02ce43eaa2e7dc986746171498b0ea5b77c..cb7c24ea565aa5731a8cb79a2ac7dbd0f5a63eeb 100644 (file)
@@ -1,3 +1,10 @@
+2009-03-14  Richard Sandiford  <r.sandiford@uk.ibm.com>
+
+       * ld-powerpc/aix-toc-1.ex, ld-powerpc/aix-toc-1a.s,
+       ld-powerpc/aix-toc-1b.s, ld-powerpc/aix-toc-1-32.dd,
+       ld-powerpc/aix-toc-1-64.dd: New tests.
+       * ld-powerpc/aix52.exp: Run them.
+
 2009-03-14  Richard Sandiford  <r.sandiford@uk.ibm.com>
 
        * ld-powerpc/aix-glink-1.ex, ld-powerpc/aix-glink-1.s,
diff --git a/ld/testsuite/ld-powerpc/aix-toc-1-32.dd b/ld/testsuite/ld-powerpc/aix-toc-1-32.dd
new file mode 100644 (file)
index 0000000..e129d34
--- /dev/null
@@ -0,0 +1,12 @@
+
+.*
+
+
+Disassembly of section \.text:
+
+10000000 <\.f1>:
+10000000:      80 22 80 08     l       r1,-32760\(r2\)
+                       10000002: R_TOC sym0.*
+#...
+1000fff4:      80 22 7f fc     l       r1,32764\(r2\)
+                       1000fff6: R_TOC asym8190.*
diff --git a/ld/testsuite/ld-powerpc/aix-toc-1-64.dd b/ld/testsuite/ld-powerpc/aix-toc-1-64.dd
new file mode 100644 (file)
index 0000000..c169ff6
--- /dev/null
@@ -0,0 +1,12 @@
+
+.*
+
+
+Disassembly of section \.text:
+
+0000000010000000 <.f1>:
+    10000000:  e8 22 80 10     ld      r1,-32752\(r2\)
+                       10000002: R_TOC sym0.*
+#...
+    10007ff4:  e8 22 7f f8     ld      r1,32760\(r2\)
+                       10007ff6: R_TOC asym4094.*
diff --git a/ld/testsuite/ld-powerpc/aix-toc-1.ex b/ld/testsuite/ld-powerpc/aix-toc-1.ex
new file mode 100644 (file)
index 0000000..13a2943
--- /dev/null
@@ -0,0 +1,2 @@
+f1
+f2
diff --git a/ld/testsuite/ld-powerpc/aix-toc-1a.s b/ld/testsuite/ld-powerpc/aix-toc-1a.s
new file mode 100644 (file)
index 0000000..e67d5d3
--- /dev/null
@@ -0,0 +1,23 @@
+       .macro  loadtoc
+       .toc
+       .tc     sym\@[TC], \@
+
+       .csect  .f1[PR]
+       .if     size == 32
+       lwz     1,sym\@[TC](2)
+       .else
+       ld      1,sym\@[TC](2)
+       .endif
+       .endm
+
+       .globl  .f1
+       .csect  .f1[PR]
+.f1:
+       .rept   0x7ffc * 8 / size
+       loadtoc
+       .endr
+
+       .globl  f1
+       .csect  f1[DS]
+f1:
+       .long   .f1[PR],TOC[TC0],0
diff --git a/ld/testsuite/ld-powerpc/aix-toc-1b.s b/ld/testsuite/ld-powerpc/aix-toc-1b.s
new file mode 100644 (file)
index 0000000..d4cee8a
--- /dev/null
@@ -0,0 +1,23 @@
+       .macro  loadtoc
+       .toc
+       .tc     asym\@[TC], \@ | 0x10000
+
+       .csect  .f2[PR]
+       .if     size == 32
+       lwz     1,asym\@[TC](2)
+       .else
+       ld      1,asym\@[TC](2)
+       .endif
+       .endm
+
+       .globl  .f2
+       .csect  .f2[PR]
+.f2:
+       .rept   0x7ffc * 8 / size
+       loadtoc
+       .endr
+
+       .globl  f2
+       .csect  f2[DS]
+f2:
+       .long   .f2[PR],TOC[TC0],0
index 41a204564c48604b3b80fb99d90a554354faf00d..247b2d1ae4a2374abaf3cc041999b1961f274cae 100644 (file)
@@ -97,6 +97,11 @@ set aix52tests {
      "" {aix-glink-1.s}
      {{objdump {-D -j.text -j.data} aix-glink-1-SIZE.dd}}
      "aix-glink-1.so"}
+
+    {"TOC test 1" "-shared -bE:aix-toc-1.ex"
+     "" {aix-toc-1a.s aix-toc-1b.s}
+     {{objdump -dr aix-toc-1-SIZE.dd}}
+     "aix-toc-1.so"}
 }
 
 foreach test $aix52tests {