binutils221: Bring in some more files on the vendor branch.
authorSascha Wildner <saw@online.de>
Wed, 23 Mar 2011 20:13:13 +0000 (21:13 +0100)
committerSascha Wildner <saw@online.de>
Wed, 23 Mar 2011 20:13:13 +0000 (21:13 +0100)
12 files changed:
contrib/binutils-2.21/binutils/cxxfilt.c [new file with mode: 0644]
contrib/binutils-2.21/elfcpp/arm.h [new file with mode: 0644]
contrib/binutils-2.21/elfcpp/powerpc.h [new file with mode: 0644]
contrib/binutils-2.21/elfcpp/sparc.h [new file with mode: 0644]
contrib/binutils-2.21/gold/arm-reloc-property.cc [new file with mode: 0644]
contrib/binutils-2.21/gold/arm-reloc-property.h [new file with mode: 0644]
contrib/binutils-2.21/gold/arm-reloc.def [new file with mode: 0644]
contrib/binutils-2.21/gold/freebsd.h [new file with mode: 0644]
contrib/binutils-2.21/gold/powerpc.cc [new file with mode: 0644]
contrib/binutils-2.21/gold/sparc.cc [new file with mode: 0644]
contrib/binutils-2.21/include/plugin-api.h [new file with mode: 0644]
contrib/binutils-2.21/libiberty/crc32.c [new file with mode: 0644]

diff --git a/contrib/binutils-2.21/binutils/cxxfilt.c b/contrib/binutils-2.21/binutils/cxxfilt.c
new file mode 100644 (file)
index 0000000..770df9b
--- /dev/null
@@ -0,0 +1,289 @@
+/* Demangler for GNU C++ - main program
+   Copyright 1989, 1991, 1994, 1995, 1996, 1997, 1998, 1999,
+   2000, 2001, 2002, 2003, 2005, 2007 Free Software Foundation, Inc.
+   Written by James Clark (jjc@jclark.uucp)
+   Rewritten by Fred Fish (fnf@cygnus.com) for ARM and Lucid demangling
+   Modified by Satish Pai (pai@apollo.hp.com) for HP demangling
+
+   This file is part of 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 GCC; see the file COPYING.  If not, write to the Free
+   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
+   02110-1301, USA.  */
+
+#include "sysdep.h"
+#include "bfd.h"
+#include "libiberty.h"
+#include "demangle.h"
+#include "getopt.h"
+#include "safe-ctype.h"
+#include "bucomm.h"
+
+static int flags = DMGL_PARAMS | DMGL_ANSI | DMGL_VERBOSE;
+static int strip_underscore = TARGET_PREPENDS_UNDERSCORE;
+
+static const struct option long_options[] =
+{
+  {"strip-underscore", no_argument, NULL, '_'},
+  {"format", required_argument, NULL, 's'},
+  {"help", no_argument, NULL, 'h'},
+  {"no-params", no_argument, NULL, 'p'},
+  {"no-strip-underscores", no_argument, NULL, 'n'},
+  {"no-verbose", no_argument, NULL, 'i'},
+  {"types", no_argument, NULL, 't'},
+  {"version", no_argument, NULL, 'v'},
+  {NULL, no_argument, NULL, 0}
+};
+
+static void
+demangle_it (char *mangled_name)
+{
+  char *result;
+  unsigned int skip_first = 0;
+
+  /* _ and $ are sometimes found at the start of function names
+     in assembler sources in order to distinguish them from other
+     names (eg register names).  So skip them here.  */
+  if (mangled_name[0] == '.' || mangled_name[0] == '$')
+    ++skip_first;
+  if (strip_underscore && mangled_name[skip_first] == '_')
+    ++skip_first;
+
+  result = cplus_demangle (mangled_name + skip_first, flags);
+
+  if (result == NULL)
+    printf ("%s", mangled_name);
+  else
+    {
+      if (mangled_name[0] == '.')
+       putchar ('.');
+      printf ("%s", result);
+      free (result);
+    }
+}
+
+static void
+print_demangler_list (FILE *stream)
+{
+  const struct demangler_engine *demangler;
+
+  fprintf (stream, "{%s", libiberty_demanglers->demangling_style_name);
+
+  for (demangler = libiberty_demanglers + 1;
+       demangler->demangling_style != unknown_demangling;
+       ++demangler)
+    fprintf (stream, ",%s", demangler->demangling_style_name);
+
+  fprintf (stream, "}");
+}
+
+static void
+usage (FILE *stream, int status)
+{
+  fprintf (stream, "\
+Usage: %s [options] [mangled names]\n", program_name);
+  fprintf (stream, "\
+Options are:\n\
+  [-_|--strip-underscore]     Ignore first leading underscore%s\n",
+          TARGET_PREPENDS_UNDERSCORE ? " (default)" : "");
+  fprintf (stream, "\
+  [-n|--no-strip-underscore]  Do not ignore a leading underscore%s\n",
+          TARGET_PREPENDS_UNDERSCORE ? "" : " (default)");
+  fprintf (stream, "\
+  [-p|--no-params]            Do not display function arguments\n\
+  [-i|--no-verbose]           Do not show implementation details (if any)\n\
+  [-t|--types]                Also attempt to demangle type encodings\n\
+  [-s|--format ");
+  print_demangler_list (stream);
+  fprintf (stream, "]\n");
+
+  fprintf (stream, "\
+  [@<file>]                   Read extra options from <file>\n\
+  [-h|--help]                 Display this information\n\
+  [-v|--version]              Show the version information\n\
+Demangled names are displayed to stdout.\n\
+If a name cannot be demangled it is just echoed to stdout.\n\
+If no names are provided on the command line, stdin is read.\n");
+  if (REPORT_BUGS_TO[0] && status == 0)
+    fprintf (stream, _("Report bugs to %s.\n"), REPORT_BUGS_TO);
+  exit (status);
+}
+
+/* Return the string of non-alnum characters that may occur
+   as a valid symbol component, in the standard assembler symbol
+   syntax.  */
+
+static const char *
+standard_symbol_characters (void)
+{
+  return "_$.";
+}
+
+/* Return the string of non-alnum characters that may occur
+   as a valid symbol name component in an HP object file.
+
+   Note that, since HP's compiler generates object code straight from
+   C++ source, without going through an assembler, its mangled
+   identifiers can use all sorts of characters that no assembler would
+   tolerate, so the alphabet this function creates is a little odd.
+   Here are some sample mangled identifiers offered by HP:
+
+       typeid*__XT24AddressIndExpClassMember_
+       [Vftptr]key:__dt__32OrdinaryCompareIndExpClassMemberFv
+       __ct__Q2_9Elf64_Dyn18{unnamed.union.#1}Fv
+
+   This still seems really weird to me, since nowhere else in this
+   file is there anything to recognize curly brackets, parens, etc.
+   I've talked with Srikanth <srikanth@cup.hp.com>, and he assures me
+   this is right, but I still strongly suspect that there's a
+   misunderstanding here.
+
+   If we decide it's better for c++filt to use HP's assembler syntax
+   to scrape identifiers out of its input, here's the definition of
+   the symbol name syntax from the HP assembler manual:
+
+       Symbols are composed of uppercase and lowercase letters, decimal
+       digits, dollar symbol, period (.), ampersand (&), pound sign(#) and
+       underscore (_). A symbol can begin with a letter, digit underscore or
+       dollar sign. If a symbol begins with a digit, it must contain a
+       non-digit character.
+
+   So have fun.  */
+static const char *
+hp_symbol_characters (void)
+{
+  return "_$.<>#,*&[]:(){}";
+}
+
+extern int main (int, char **);
+
+int
+main (int argc, char **argv)
+{
+  int c;
+  const char *valid_symbols;
+  enum demangling_styles style = auto_demangling;
+
+  program_name = argv[0];
+  xmalloc_set_program_name (program_name);
+
+  expandargv (&argc, &argv);
+
+  while ((c = getopt_long (argc, argv, "_hinps:tv", long_options, (int *) 0)) != EOF)
+    {
+      switch (c)
+       {
+       case '?':
+         usage (stderr, 1);
+         break;
+       case 'h':
+         usage (stdout, 0);
+       case 'n':
+         strip_underscore = 0;
+         break;
+       case 'p':
+         flags &= ~ DMGL_PARAMS;
+         break;
+       case 't':
+         flags |= DMGL_TYPES;
+         break;
+       case 'i':
+         flags &= ~ DMGL_VERBOSE;
+         break;
+       case 'v':
+         print_version ("c++filt");
+         return 0;
+       case '_':
+         strip_underscore = 1;
+         break;
+       case 's':
+         style = cplus_demangle_name_to_style (optarg);
+         if (style == unknown_demangling)
+           {
+             fprintf (stderr, "%s: unknown demangling style `%s'\n",
+                      program_name, optarg);
+             return 1;
+           }
+         cplus_demangle_set_style (style);
+         break;
+       }
+    }
+
+  if (optind < argc)
+    {
+      for ( ; optind < argc; optind++)
+       {
+         demangle_it (argv[optind]);
+         putchar ('\n');
+       }
+
+      return 0;
+    }
+
+  switch (current_demangling_style)
+    {
+    case gnu_demangling:
+    case lucid_demangling:
+    case arm_demangling:
+    case java_demangling:
+    case edg_demangling:
+    case gnat_demangling:
+    case gnu_v3_demangling:
+    case auto_demangling:
+      valid_symbols = standard_symbol_characters ();
+      break;
+    case hp_demangling:
+      valid_symbols = hp_symbol_characters ();
+      break;
+    default:
+      /* Folks should explicitly indicate the appropriate alphabet for
+        each demangling.  Providing a default would allow the
+        question to go unconsidered.  */
+      fatal ("Internal error: no symbol alphabet for current style");
+    }
+
+  for (;;)
+    {
+      static char mbuffer[32767];
+      unsigned i = 0;
+
+      c = getchar ();
+      /* Try to read a mangled name.  */
+      while (c != EOF && (ISALNUM (c) || strchr (valid_symbols, c)))
+       {
+         if (i >= sizeof (mbuffer) - 1)
+           break;
+         mbuffer[i++] = c;
+         c = getchar ();
+       }
+
+      if (i > 0)
+       {
+         mbuffer[i] = 0;
+         demangle_it (mbuffer);
+       }
+
+      if (c == EOF)
+       break;
+
+      /* Echo the whitespace characters so that the output looks
+        like the input, only with the mangled names demangled.  */
+      putchar (c);
+      if (c == '\n')
+       fflush (stdout);
+    }
+
+  fflush (stdout);
+  return 0;
+}
diff --git a/contrib/binutils-2.21/elfcpp/arm.h b/contrib/binutils-2.21/elfcpp/arm.h
new file mode 100644 (file)
index 0000000..cb85eeb
--- /dev/null
@@ -0,0 +1,344 @@
+// arm.h -- ELF definitions specific to EM_ARM  -*- C++ -*-
+
+// Copyright 2009, Free Software Foundation, Inc.
+// Written by Doug Kwan <dougkwan@google.com>.
+
+// This file is part of elfcpp.
+   
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public License
+// as published by the Free Software Foundation; either version 2, or
+// (at your option) any later version.
+
+// In addition to the permissions in the GNU Library General Public
+// License, the Free Software Foundation gives you unlimited
+// permission to link the compiled version of this file into
+// combinations with other programs, and to distribute those
+// combinations without any restriction coming from the use of this
+// file.  (The Library Public License restrictions do apply in other
+// respects; for example, they cover modification of the file, and
+// distribution when not linked into a combined executable.)
+
+// 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
+// Library General Public License for more details.
+
+// You should have received a copy of the GNU Library 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.
+
+#ifndef ELFCPP_ARM_H
+#define ELFCPP_ARM_H
+
+// The relocation type information is taken from:
+//
+//   ELF for the ARM Architecture
+//   Document number: ARM IHI 0044C, current through ABI release 2.07
+//   Date of Issue: 10th October, 2008
+//
+
+namespace elfcpp
+{
+
+//
+// ARM Relocations Codes
+//
+
+// Operation notes: 
+//   S: Address of the symbol.
+//   A: Addend for relocation.
+//   P: Address of the place being relocated.
+//   Pa: Adjusted address of the place being relocated (P & 0xfffffffc)
+//   T: is 1 if S has type STT_FUNC and the symbol addresses a Thumb
+//      instruction.Thumb-bit; it is 0 otherwise.
+//   B(S): Addressing origin of the output segment defining S.
+//   GOT_ORG: Addressing origin of the Global Offset Table.
+//   GOT(S): Address of the GOT entry for S.
+//
+
+enum
+{
+                               // Type         Class   Operation               
+                               // ------------------------------
+  R_ARM_NONE = 0,              // Static       Misc
+  R_ARM_PC24 = 1,              // Deprecated   ARM     ((S + A) | T) - P
+  R_ARM_ABS32 = 2,             // Static       Data    (S + A) | T
+  R_ARM_REL32 = 3,             // Static       Data    ((S + A) | T) - P
+  R_ARM_LDR_PC_G0 = 4,         // Static       ARM     S + A - P
+  R_ARM_ABS16 = 5,             // Static       Data    S + A
+  R_ARM_ABS12 = 6,             // Static       ARM     S + A
+  R_ARM_THM_ABS5 = 7,          // Static       Thumb16 S + A
+  R_ARM_ABS8 = 8,              // Static       Data    S + A
+  R_ARM_SBREL32 = 9,           // Static       Data    ((S + A) | T) - B(S)
+  R_ARM_THM_CALL = 10,         // Static       Thumb32 ((S + A) | T) - P
+  R_ARM_THM_PC8 = 11,          // Static       Thumb16
+  R_ARM_BREL_ADJ = 12,         // Dynamic      Data    DeltaB(S) + A
+  R_ARM_TLS_DESC = 13,         // Dynamic      Data
+  R_ARM_THM_SWI8 = 14,         // Obsolete
+  R_ARM_XPC25 = 15,            // Obsolete
+  R_ARM_THM_XPC22 = 16,                // Obsolete
+  R_ARM_TLS_DTPMOD32 = 17,     // Dynamic      Data    Module(S)
+  R_ARM_TLS_DTPOFF32 = 18,     // Dynamic      Data    S + A - TLS
+  R_ARM_TLS_TPOFF32 = 19,      // Dynamic      Data    S + A - tp
+  R_ARM_COPY = 20,             // Dynamic      Misc
+  R_ARM_GLOB_DAT = 21,         // Dynamic      Data    (S + A) | T
+  R_ARM_JUMP_SLOT = 22,                // Dynamic      Data    (S + A) | T
+  R_ARM_RELATIVE = 23,         // Dynamic      Data    B(S) + A
+  R_ARM_GOTOFF32 = 24,         // Static       Data    (((S + A) | T) - GOT_ORG
+  R_ARM_BASE_PREL = 25,                // Static       Data    B(S) + A - P
+  R_ARM_GOT_BREL = 26,         // Static       Data    GOT(S) + A - GOT_ORG
+  R_ARM_PLT32 = 27,            // Deprecated   ARM     ((S + A) | T) - P
+  R_ARM_CALL = 28,             // Static       ARM     ((S + A) | T) - P
+  R_ARM_JUMP24 = 29,           // Static       ARM     ((S + A) | T) - P
+  R_ARM_THM_JUMP24 = 30,       // Static       Thumb32 ((S + A) | T) - P
+  R_ARM_BASE_ABS = 31,         // Static       Data    B(S) + A
+  R_ARM_ALU_PCREL_7_0 = 32,    // Obsolete
+  R_ARM_ALU_PCREL_15_8 = 33,   // Obsolete
+  R_ARM_ALU_PCREL_23_15 = 34,  // Obsolete
+  R_ARM_LDR_SBREL_11_0_NC = 35,        // Deprecated   ARM     S + A - B(S)
+  R_ARM_ALU_SBREL_19_12_NC = 36,// Deprecated  ARM     S + A - B(S)
+  R_ARM_ALU_SBREL_27_20_CK = 37,// Deprecated  ARM     S + A - B(S)
+  R_ARM_TARGET1 = 38,          // Data         Misc    (S + A) | T or
+                               //                      ((S + A) | T) - P
+  R_ARM_SBREL31 = 39,          // Deprecated   Data    ((S + A) | T) - B(S)
+  R_ARM_V4BX = 40,             // Static       Misc 
+  R_ARM_TARGET2 = 41,          // Static       Misc
+  R_ARM_PREL31 = 42,           // Static       Data    ((S + A) | T) - P
+  R_ARM_MOVW_ABS_NC = 43,      // Static       ARM     (S + A) | T
+  R_ARM_MOVT_ABS = 44,         // Static       ARM     S + A
+  R_ARM_MOVW_PREL_NC = 45,     // Static       ARM     ((S + A) | T) - P
+  R_ARM_MOVT_PREL = 46,                // Static       ARM     S + A - P
+  R_ARM_THM_MOVW_ABS_NC = 47,  // Static       Thumb32 (S + A) | T
+  R_ARM_THM_MOVT_ABS = 48,     // Static       Thumb32 S + A - P
+  R_ARM_THM_MOVW_PREL_NC =  49,        // Static       Thumb32 ((S + A) | T) - P
+  R_ARM_THM_MOVT_PREL = 50,    // Static       Thumb32 S + A - P
+  R_ARM_THM_JUMP19 = 51,       // Static       Thumb32 ((S + A) | T) - P
+  R_ARM_THM_JUMP6 = 52,                // Static       Thumb16 S + A - P
+  R_ARM_THM_ALU_PREL_11_0 = 53,        // Static       Thumb32 ((S + A) | T) - Pa
+  R_ARM_THM_PC12 = 54,         // Static       Thumb32 S + A - Pa
+  R_ARM_ABS32_NOI = 55,                // Static       Data    S + A
+  R_ARM_REL32_NOI = 56,                // Static       Data    S + A - P
+  R_ARM_ALU_PC_G0_NC = 57,     // Static       ARM     ((S + A) | T) - P
+  R_ARM_ALU_PC_G0 = 58,                // Static       ARM     ((S + A) | T) - P
+  R_ARM_ALU_PC_G1_NC = 59,     // Static       ARM     ((S + A) | T) - P
+  R_ARM_ALU_PC_G1 = 60,                // Static       ARM     ((S + A) | T) - P
+  R_ARM_ALU_PC_G2 = 61,                // Static       ARM     ((S + A) | T) - P
+  R_ARM_LDR_PC_G1 = 62,                // Static       ARM     S + A - P
+  R_ARM_LDR_PC_G2 = 63,                // Static       ARM     S + A - P
+  R_ARM_LDRS_PC_G0 = 64,       // Static       ARM     S + A - P
+  R_ARM_LDRS_PC_G1 = 65,       // Static       ARM     S + A - P
+  R_ARM_LDRS_PC_G2 = 66,       // Static       ARM     S + A - P
+  R_ARM_LDC_PC_G0 = 67,                // Static       ARM     S + A - P
+  R_ARM_LDC_PC_G1 = 68,                // Static       ARM     S + A - P
+  R_ARM_LDC_PC_G2 = 69,                // Static       ARM     S + A - P
+  R_ARM_ALU_SB_G0_NC = 70,     // Static       ARM     ((S + A) | T) - B(S)
+  R_ARM_ALU_SB_G0 = 71,                // Static       ARM     ((S + A) | T) - B(S)
+  R_ARM_ALU_SB_G1_NC = 72,     // Static       ARM     ((S + A) | T) - B(S)
+  R_ARM_ALU_SB_G1 = 73,                // Static       ARM     ((S + A) | T) - B(S)
+  R_ARM_ALU_SB_G2 = 74,                // Static       ARM     ((S + A) | T) - B(S)
+  R_ARM_LDR_SB_G0 = 75,                // Static       ARM     S + A - B(S)
+  R_ARM_LDR_SB_G1 = 76,                // Static       ARM     S + A - B(S)
+  R_ARM_LDR_SB_G2 = 77,                // Static       ARM     S + A - B(S)
+  R_ARM_LDRS_SB_G0 = 78,       // Static       ARM     S + A - B(S)
+  R_ARM_LDRS_SB_G1 = 79,       // Static       ARM     S + A - B(S)
+  R_ARM_LDRS_SB_G2 = 80,       // Static       ARM     S + A - B(S)
+  R_ARM_LDC_SB_G0 = 81,                // Static       ARM     S + A - B(S)
+  R_ARM_LDC_SB_G1 = 82,                // Static       ARM     S + A - B(S)
+  R_ARM_LDC_SB_G2 = 83,                // Static       ARM     S + A - B(S)
+  R_ARM_MOVW_BREL_NC = 84,     // Static       ARM     ((S + A) | T) - B(S)
+  R_ARM_MOVT_BREL = 85,                // Static       ARM     S + A - B(S)
+  R_ARM_MOVW_BREL = 86,                // Static       ARM     ((S + A) | T) - B(S)
+  R_ARM_THM_MOVW_BREL_NC = 87, // Static       Thumb32 ((S + A) | T) - B(S)
+  R_ARM_THM_MOVT_BREL = 88,    // Static       Thumb32 S + A - B(S)
+  R_ARM_THM_MOVW_BREL = 89,    // Static       Thumb32 ((S + A) | T) - B(S)
+  R_ARM_TLS_GOTDESC = 90,      // Static       Data
+  R_ARM_TLS_CALL = 91,         // Static       ARM
+  R_ARM_TLS_DESCSEQ = 92,      // Static       ARM     TLS relaxation
+  R_ARM_THM_TLS_CALL = 93,     // Static       Thumb32
+  R_ARM_PLT32_ABS =  94,       // Static       Data    PLT(S) + A
+  R_ARM_GOT_ABS =  95,         // Static       Data    GOT(S) + A
+  R_ARM_GOT_PREL = 96,         // Static       Data    GOT(S) + A - P
+  R_ARM_GOT_BREL12 =  97,      // Static       ARM     GOT(S) + A - GOT_ORG
+  R_ARM_GOTOFF12 =  98,                // Static       ARM     S + A - GOT_ROG
+  R_ARM_GOTRELAX =  99,                // Static       Misc
+  R_ARM_GNU_VTENTRY = 100,     // Deprecated   Data
+  R_ARM_GNU_VTINHERIT = 101,   // Deprecated   Data
+  R_ARM_THM_JUMP11 = 102,      // Static       Thumb16 S + A - P
+  R_ARM_THM_JUMP8 = 103,       // Static       Thumb16 S + A - P
+  R_ARM_TLS_GD32 = 104,                // Static       Data    GOT(S) + A - P
+  R_ARM_TLS_LDM32 = 105,       // Static       Data    GOT(S) + A - P
+  R_ARM_TLS_LDO32 = 106,       // Static       Data    S + A - TLS
+  R_ARM_TLS_IE32 = 107,                // Static       Data    GOT(S) + A - P
+  R_ARM_TLS_LE32 = 108,                // Static       Data    S + A - tp
+  R_ARM_TLS_LDO12 = 109,       // Static       ARM     S + A - TLS
+  R_ARM_TLS_LE12 = 110,                // Static       ARM     S + A - tp
+  R_ARM_TLS_IE12GP = 111,      // Static       ARM     GOT(S) + A - GOT_ORG
+  R_ARM_PRIVATE_0 = 112,       // Private (n = 0, 1, ... 15)
+  R_ARM_PRIVATE_1 = 113,
+  R_ARM_PRIVATE_2 = 114,
+  R_ARM_PRIVATE_3 = 115,
+  R_ARM_PRIVATE_4 = 116,
+  R_ARM_PRIVATE_5 = 117,
+  R_ARM_PRIVATE_6 = 118,
+  R_ARM_PRIVATE_7 = 119,
+  R_ARM_PRIVATE_8 = 120,
+  R_ARM_PRIVATE_9 = 121,
+  R_ARM_PRIVATE_10 = 122,
+  R_ARM_PRIVATE_11 = 123,
+  R_ARM_PRIVATE_12 = 124,
+  R_ARM_PRIVATE_13 = 125,
+  R_ARM_PRIVATE_14 = 126,
+  R_ARM_PRIVATE_15 = 127,
+  R_ARM_ME_TOO = 128,          // Obsolete
+  R_ARM_THM_TLS_DESCSEQ16 = 129,// Static      Thumb16 
+  R_ARM_THM_TLS_DESCSEQ32 = 130,// Static      Thumb32
+  // 131 - 139                 Unallocated
+  // 140 - 159                 Dynamic         Reserved for future allocation
+  // 160 - 255                 Unallocated
+};
+
+// e_flags values used for ARM.  We only support flags defined in AAELF.
+
+enum
+{
+  EF_ARM_BE8 = 0x00800000,
+
+  // Mask to extract EABI version, not really a flag value.
+  EF_ARM_EABIMASK = 0xFF000000,
+
+  EF_ARM_EABI_UNKNOWN = 0x00000000,
+  EF_ARM_EABI_VER1 = 0x01000000,
+  EF_ARM_EABI_VER2 = 0x02000000,
+  EF_ARM_EABI_VER3 = 0x03000000,
+  EF_ARM_EABI_VER4 = 0x04000000,
+  EF_ARM_EABI_VER5 = 0x05000000,
+};
+
+// Extract EABI version from flags.
+
+inline Elf_Word
+arm_eabi_version(Elf_Word flags)
+{ return flags & EF_ARM_EABIMASK; }
+
+// Values for the Tag_CPU_arch EABI attribute.
+enum
+{
+  TAG_CPU_ARCH_PRE_V4,
+  TAG_CPU_ARCH_V4,
+  TAG_CPU_ARCH_V4T,
+  TAG_CPU_ARCH_V5T,
+  TAG_CPU_ARCH_V5TE,
+  TAG_CPU_ARCH_V5TEJ,
+  TAG_CPU_ARCH_V6,
+  TAG_CPU_ARCH_V6KZ,
+  TAG_CPU_ARCH_V6T2,
+  TAG_CPU_ARCH_V6K,
+  TAG_CPU_ARCH_V7,
+  TAG_CPU_ARCH_V6_M,
+  TAG_CPU_ARCH_V6S_M,
+  TAG_CPU_ARCH_V7E_M,
+  MAX_TAG_CPU_ARCH = TAG_CPU_ARCH_V7E_M,
+  // Pseudo-architecture to allow objects to be compatible with the subset of
+  // armv4t and armv6-m.  This value should never be stored in object files.
+  TAG_CPU_ARCH_V4T_PLUS_V6_M = (MAX_TAG_CPU_ARCH + 1)
+};
+
+// EABI object attributes.
+enum
+{
+  // 0-3 are generic.
+  Tag_CPU_raw_name = 4,
+  Tag_CPU_name = 5,
+  Tag_CPU_arch = 6,
+  Tag_CPU_arch_profile = 7,
+  Tag_ARM_ISA_use = 8,
+  Tag_THUMB_ISA_use = 9,
+  Tag_FP_arch = 10,
+  Tag_WMMX_arch = 11,
+  Tag_Advanced_SIMD_arch = 12,
+  Tag_PCS_config = 13,
+  Tag_ABI_PCS_R9_use = 14,
+  Tag_ABI_PCS_RW_data = 15,
+  Tag_ABI_PCS_RO_data = 16,
+  Tag_ABI_PCS_GOT_use = 17,
+  Tag_ABI_PCS_wchar_t = 18,
+  Tag_ABI_FP_rounding = 19,
+  Tag_ABI_FP_denormal = 20,
+  Tag_ABI_FP_exceptions = 21,
+  Tag_ABI_FP_user_exceptions = 22,
+  Tag_ABI_FP_number_model = 23,
+  Tag_ABI_align_needed = 24,
+  Tag_ABI_align_preserved = 25,
+  Tag_ABI_enum_size = 26,
+  Tag_ABI_HardFP_use = 27,
+  Tag_ABI_VFP_args = 28,
+  Tag_ABI_WMMX_args = 29,
+  Tag_ABI_optimization_goals = 30,
+  Tag_ABI_FP_optimization_goals = 31,
+  // 32 is generic (Tag_compatibility).
+  Tag_undefined33 = 33,
+  Tag_CPU_unaligned_access = 34,
+  Tag_undefined35 = 35,
+  Tag_FP_HP_extension = 36,
+  Tag_undefined37 = 37,
+  Tag_ABI_FP_16bit_format = 38,
+  Tag_undefined39 = 39,
+  Tag_undefined40 = 40,
+  Tag_undefined41 = 41,
+  Tag_MPextension_use = 42,
+  Tag_undefined43 = 43,
+  Tag_DIV_use = 44,
+  Tag_nodefaults = 64,
+  Tag_also_compatible_with = 65,
+  Tag_T2EE_use = 66,
+  Tag_conformance = 67,
+  Tag_Virtualization_use = 68,
+  Tag_undefined69 = 69,
+  Tag_MPextension_use_legacy = 70,
+
+  // The following tags are legacy names for other tags.
+  Tag_VFP_arch = Tag_FP_arch,
+  Tag_ABI_align8_needed = Tag_ABI_align_needed,
+  Tag_ABI_align8_preserved = Tag_ABI_align_preserved,
+  Tag_VFP_HP_extension = Tag_FP_HP_extension
+};
+
+// Values for Tag_ABI_PCS_R9_use.
+enum
+{
+  AEABI_R9_V6 = 0,
+  AEABI_R9_SB = 1,
+  AEABI_R9_TLS = 2,
+  AEABI_R9_unused = 3
+};
+
+// Values for Tag_ABI_PCS_RW_data.
+enum
+{
+  AEABI_PCS_RW_data_absolute = 0,
+  AEABI_PCS_RW_data_PCrel = 1,
+  AEABI_PCS_RW_data_SBrel = 2,
+  AEABI_PCS_RW_data_unused = 3
+};
+
+// Values for Tag_ABI_enum_size.
+enum
+{
+  AEABI_enum_unused = 0,
+  AEABI_enum_short = 1,
+  AEABI_enum_wide = 2,
+  AEABI_enum_forced_wide = 3
+};
+
+// For Exception Index Table. (Exception handling ABI for the ARM
+// architectue, Section 5)
+enum
+{
+  EXIDX_CANTUNWIND = 1,
+};
+
+} // End namespace elfcpp.
+
+#endif // !defined(ELFCPP_ARM_H)
diff --git a/contrib/binutils-2.21/elfcpp/powerpc.h b/contrib/binutils-2.21/elfcpp/powerpc.h
new file mode 100644 (file)
index 0000000..2bcb3ca
--- /dev/null
@@ -0,0 +1,189 @@
+// powerpc.h -- ELF definitions specific to EM_PPC and EM_PPC64  -*- C++ -*-
+
+// Copyright 2008, 2010 Free Software Foundation, Inc.
+// Written by David S. Miller <davem@davemloft.net>.
+
+// This file is part of elfcpp.
+   
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public License
+// as published by the Free Software Foundation; either version 2, or
+// (at your option) any later version.
+
+// In addition to the permissions in the GNU Library General Public
+// License, the Free Software Foundation gives you unlimited
+// permission to link the compiled version of this file into
+// combinations with other programs, and to distribute those
+// combinations without any restriction coming from the use of this
+// file.  (The Library Public License restrictions do apply in other
+// respects; for example, they cover modification of the file, and
+/// distribution when not linked into a combined executable.)
+
+// 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
+// Library General Public License for more details.
+
+// You should have received a copy of the GNU Library 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.
+
+#ifndef ELFCPP_POWERPC_H
+#define ELFCPP_POWERPC_H
+
+namespace elfcpp
+{
+
+// The relocation numbers for 32-bit and 64-bit powerpc are nearly
+// identical.  Therefore I've adopted the convention of using
+// R_POWERPC_foo for values which are the same in R_PPC_* and R_PPC64_*.
+// For relocations which are specific to the word size I will use
+// R_PPC_foo or R_PPC64_foo.
+enum
+{
+  R_POWERPC_NONE = 0,
+  R_POWERPC_ADDR32 = 1,
+  R_POWERPC_ADDR24 = 2,
+  R_POWERPC_ADDR16 = 3,
+  R_POWERPC_ADDR16_LO = 4,
+  R_POWERPC_ADDR16_HI = 5,
+  R_POWERPC_ADDR16_HA = 6,
+  R_POWERPC_ADDR14 = 7,
+  R_POWERPC_ADDR14_BRTAKEN = 8,
+  R_POWERPC_ADDR14_BRNTAKEN = 9,
+  R_POWERPC_REL24 = 10,
+  R_POWERPC_REL14 = 11,
+  R_POWERPC_REL14_BRTAKEN = 12,
+  R_POWERPC_REL14_BRNTAKEN = 13,
+  R_POWERPC_GOT16 = 14,
+  R_POWERPC_GOT16_LO = 15,
+  R_POWERPC_GOT16_HI = 16,
+  R_POWERPC_GOT16_HA = 17,
+  R_PPC_PLTREL24 = 18,
+  R_POWERPC_COPY = 19,
+  R_POWERPC_GLOB_DAT = 20,
+  R_POWERPC_JMP_SLOT = 21,
+  R_POWERPC_RELATIVE = 22,
+  R_PPC_LOCAL24PC = 23,
+  R_POWERPC_UADDR32 = 24,
+  R_POWERPC_UADDR16 = 25,
+  R_POWERPC_REL32 = 26,
+  R_POWERPC_PLT32 = 27,
+  R_POWERPC_PLTREL32 = 28,
+  R_POWERPC_PLT16_LO = 29,
+  R_POWERPC_PLT16_HI = 30,
+  R_POWERPC_PLT16_HA = 31,
+  R_PPC_SDAREL16 = 32,
+  R_POWERPC_SECTOFF = 33,
+  R_POWERPC_SECTOFF_LO = 34,
+  R_POWERPC_SECTOFF_HI = 35,
+  R_POWERPC_SECTOFF_HA = 36,
+  R_POWERPC_ADDR30 = 37,
+  R_PPC64_ADDR64 = 38,
+  R_PPC64_ADDR16_HIGHER = 39,
+  R_PPC64_ADDR16_HIGHERA = 40,
+  R_PPC64_ADDR16_HIGHEST = 41,
+  R_PPC64_ADDR16_HIGHESTA = 42,
+  R_PPC64_UADDR64 = 43,
+  R_PPC64_REL64 = 44,
+  R_PPC64_PLT64 = 45,
+  R_PPC64_PLTREL64 = 46,
+  R_PPC64_TOC16 = 47,
+  R_PPC64_TOC16_LO = 48,
+  R_PPC64_TOC16_HI = 49,
+  R_PPC64_TOC16_HA = 50,
+  R_PPC64_TOC = 51,
+  R_PPC64_PLTGOT16 = 52,
+  R_PPC64_PLTGOT16_LO = 53,
+  R_PPC64_PLTGOT16_HI = 54,
+  R_PPC64_PLTGOT16_HA = 55,
+  R_PPC64_ADDR16_DS = 56,
+  R_PPC64_ADDR16_LO_DS = 57,
+  R_PPC64_GOT16_DS = 58,
+  R_PPC64_GOT16_LO_DS = 59,
+  R_PPC64_PLT16_LO_DS = 60,
+  R_PPC64_SECTOFF_DS = 61,
+  R_PPC64_SECTOFF_LO_DS = 62,
+  R_PPC64_TOC16_DS = 63,
+  R_PPC64_TOC16_LO_DS = 64,
+  R_PPC64_PLTGOT16_DS = 65,
+  R_PPC64_PLTGOT16_LO_DS = 66,
+  R_POWERPC_TLS = 67,
+  R_POWERPC_DTPMOD = 68,
+  R_POWERPC_TPREL16 = 69,
+  R_POWERPC_TPREL16_LO = 70,
+  R_POWERPC_TPREL16_HI = 71,
+  R_POWERPC_TPREL16_HA = 72,
+  R_POWERPC_TPREL = 73,
+  R_POWERPC_DTPREL16 = 74,
+  R_POWERPC_DTPREL16_LO = 75,
+  R_POWERPC_DTPREL16_HI = 76,
+  R_POWERPC_DTPREL16_HA = 77,
+  R_POWERPC_DTPREL = 78,
+  R_POWERPC_GOT_TLSGD16 = 79,
+  R_POWERPC_GOT_TLSGD16_LO = 80,
+  R_POWERPC_GOT_TLSGD16_HI = 81,
+  R_POWERPC_GOT_TLSGD16_HA = 82,
+  R_POWERPC_GOT_TLSLD16 = 83,
+  R_POWERPC_GOT_TLSLD16_LO = 84,
+  R_POWERPC_GOT_TLSLD16_HI = 85,
+  R_POWERPC_GOT_TLSLD16_HA = 86,
+  R_POWERPC_GOT_TPREL16 = 87,
+  R_POWERPC_GOT_TPREL16_LO = 88,
+  R_POWERPC_GOT_TPREL16_HI = 89,
+  R_POWERPC_GOT_TPREL16_HA = 90,
+  R_POWERPC_GOT_DTPREL16 = 91,
+  R_POWERPC_GOT_DTPREL16_LO = 92,
+  R_POWERPC_GOT_DTPREL16_HI = 93,
+  R_POWERPC_GOT_DTPREL16_HA = 94,
+  R_PPC64_TPREL16_DS = 95,
+  R_PPC64_TPREL16_LO_DS = 96,
+  R_PPC64_TPREL16_HIGHER = 97,
+  R_PPC64_TPREL16_HIGHERA = 98,
+  R_PPC64_TPREL16_HIGHEST = 99,
+  R_PPC64_TPREL16_HIGHESTA = 100,
+  R_PPC64_DTPREL16_DS = 101,
+  R_PPC64_DTPREL16_LO_DS = 102,
+  R_PPC64_DTPREL16_HIGHER = 103,
+  R_PPC64_DTPREL16_HIGHERA = 104,
+  R_PPC64_DTPREL16_HIGHEST = 105,
+  R_PPC64_DTPREL16_HIGHESTA = 106,
+  R_PPC_EMB_NADDR32 = 101,
+  R_PPC_EMB_NADDR16 = 102,
+  R_PPC_EMB_NADDR16_LO = 103,
+  R_PPC_EMB_NADDR16_HI = 104,
+  R_PPC_EMB_NADDR16_HA = 105,
+  R_PPC_EMB_SDAI16 = 106,
+  R_PPC_EMB_SDA2I16 = 107,
+  R_PPC_EMB_SDA2REL = 108,
+  R_PPC_EMB_SDA21 = 109,
+  R_PPC_EMB_MRKREF = 110,
+  R_PPC_EMB_RELSEC16 = 111,
+  R_PPC_EMB_RELST_LO = 112,
+  R_PPC_EMB_RELST_HI = 113,
+  R_PPC_EMB_RELST_HA = 114,
+  R_PPC_EMB_BIT_FLD = 115,
+  R_PPC_EMB_RELSDA = 116,
+
+  R_POWERPC_IRELATIVE = 248,
+  R_PPC_REL16 = 249,
+  R_PPC_REL16_LO = 250,
+  R_PPC_REL16_HI = 251,
+  R_PPC_REL16_HA = 252,
+  R_POWERPC_GNU_VTINHERIT = 253,
+  R_POWERPC_GNU_VTENTRY = 254,
+  R_PPC_TOC16 = 255,
+};
+
+// e_flags values defined for powerpc
+enum
+{
+  EF_PPC_EMB = 0x80000000,             // PowerPC embedded flag.
+  EF_PPC_RELOCATABLE = 0x00010000,     // PowerPC -mrelocatable flag.  */
+  EF_PPC_RELOCATABLE_LIB = 0x00008000, // PowerPC -mrelocatable-lib flag.  */
+};
+
+} // End namespace elfcpp.
+
+#endif // !defined(ELFCPP_POWERPC_H)
diff --git a/contrib/binutils-2.21/elfcpp/sparc.h b/contrib/binutils-2.21/elfcpp/sparc.h
new file mode 100644 (file)
index 0000000..6a9193b
--- /dev/null
@@ -0,0 +1,171 @@
+// sparc.h -- ELF definitions specific to EM_SPARC  -*- C++ -*-
+
+// Copyright 2008, 2010 Free Software Foundation, Inc.
+// Written by David S. Miller <davem@davemloft.net>.
+
+// This file is part of elfcpp.
+   
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public License
+// as published by the Free Software Foundation; either version 2, or
+// (at your option) any later version.
+
+// In addition to the permissions in the GNU Library General Public
+// License, the Free Software Foundation gives you unlimited
+// permission to link the compiled version of this file into
+// combinations with other programs, and to distribute those
+// combinations without any restriction coming from the use of this
+// file.  (The Library Public License restrictions do apply in other
+// respects; for example, they cover modification of the file, and
+/// distribution when not linked into a combined executable.)
+
+// 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
+// Library General Public License for more details.
+
+// You should have received a copy of the GNU Library 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.
+
+#ifndef ELFCPP_SPARC_H
+#define ELFCPP_SPARC_H
+
+// Documentation for the TLS relocs is taken from
+//   http://people.redhat.com/drepper/tls.pdf
+//
+// More full documentation on sparc specific ELF file
+// format details can be found at
+//
+//   http://docs.sun.com/app/docs/doc/819/0690/
+//   "Linker and Libraries Guide"
+//
+// specifically Chapter 7 "Object File Format" and
+// Chapter 8 "Thread-Local Storage"
+
+namespace elfcpp
+{
+
+enum
+{
+  R_SPARC_NONE = 0,           // No reloc
+  R_SPARC_8 = 1,              // Direct 8 bit
+  R_SPARC_16 = 2,             // Direct 16 bit
+  R_SPARC_32 = 3,             // Direct 32 bit
+  R_SPARC_DISP8 = 4,          // PC relative 8 bit
+  R_SPARC_DISP16 = 5,         // PC relative 16 bit
+  R_SPARC_DISP32 = 6,         // PC relative 32 bit
+  R_SPARC_WDISP30 = 7,        // PC relative 30 bit shifted
+  R_SPARC_WDISP22 = 8,        // PC relative 22 bit shifted
+  R_SPARC_HI22 = 9,           // High 22 bit
+  R_SPARC_22 = 10,            // Direct 22 bit
+  R_SPARC_13 = 11,            // Direct 13 bit
+  R_SPARC_LO10 = 12,          // Truncated 10 bit
+  R_SPARC_GOT10 = 13,         // Truncated 10 bit GOT entry
+  R_SPARC_GOT13 = 14,         // 13 bit GOT entry
+  R_SPARC_GOT22 = 15,         // 22 bit GOT entry shifted
+  R_SPARC_PC10 = 16,          // PC relative 10 bit truncated
+  R_SPARC_PC22 = 17,          // PC relative 22 bit shifted
+  R_SPARC_WPLT30 = 18,        // 30 bit PC relative PLT address
+  R_SPARC_COPY = 19,          // Copy symbol at runtime
+  R_SPARC_GLOB_DAT = 20,      // Create GOT entry
+  R_SPARC_JMP_SLOT = 21,      // Create PLT entry
+  R_SPARC_RELATIVE = 22,      // Adjust by program base
+  R_SPARC_UA32 = 23,          // Direct 32 bit unaligned
+  R_SPARC_PLT32 = 24,         // Direct 32 bit ref to PLT entry
+  R_SPARC_HIPLT22 = 25,       // High 22 bit PLT entry
+  R_SPARC_LOPLT10 = 26,       // Truncated 10 bit PLT entry
+  R_SPARC_PCPLT32 = 27,       // PC rel 32 bit ref to PLT entry
+  R_SPARC_PCPLT22 = 28,       // PC rel high 22 bit PLT entry
+  R_SPARC_PCPLT10 = 29,       // PC rel trunc 10 bit PLT entry
+  R_SPARC_10 = 30,            // Direct 10 bit
+  R_SPARC_11 = 31,            // Direct 11 bit
+  R_SPARC_64 = 32,            // Direct 64 bit
+  R_SPARC_OLO10 = 33,         // 10bit with secondary 13bit addend
+  R_SPARC_HH22 = 34,          // Top 22 bits of direct 64 bit
+  R_SPARC_HM10 = 35,          // High middle 10 bits of ...
+  R_SPARC_LM22 = 36,          // Low middle 22 bits of ...
+  R_SPARC_PC_HH22 = 37,       // Top 22 bits of pc rel 64 bit
+  R_SPARC_PC_HM10 = 38,       // High middle 10 bit of ...
+  R_SPARC_PC_LM22 = 39,       // Low miggle 22 bits of ...
+  R_SPARC_WDISP16 = 40,       // PC relative 16 bit shifted
+  R_SPARC_WDISP19 = 41,       // PC relative 19 bit shifted
+  R_SPARC_GLOB_JMP = 42,      // was part of v9 ABI but was removed
+  R_SPARC_7 = 43,             // Direct 7 bit
+  R_SPARC_5 = 44,             // Direct 5 bit
+  R_SPARC_6 = 45,             // Direct 6 bit
+  R_SPARC_DISP64 = 46,        // PC relative 64 bit
+  R_SPARC_PLT64 = 47,         // Direct 64 bit ref to PLT entry
+  R_SPARC_HIX22 = 48,         // High 22 bit complemented
+  R_SPARC_LOX10 = 49,         // Truncated 11 bit complemented
+  R_SPARC_H44 = 50,           // Direct high 12 of 44 bit
+  R_SPARC_M44 = 51,           // Direct mid 22 of 44 bit
+  R_SPARC_L44 = 52,           // Direct low 10 of 44 bit
+  R_SPARC_REGISTER = 53,      // Global register usage
+  R_SPARC_UA64 = 54,          // Direct 64 bit unaligned
+  R_SPARC_UA16 = 55,          // Direct 16 bit unaligned
+  R_SPARC_TLS_GD_HI22 = 56,   // Initial General Dynamic reloc, high 22-bit
+  R_SPARC_TLS_GD_LO10 = 57,   // Initial General Dynamic reloc, low 10-bit
+  R_SPARC_TLS_GD_ADD = 58,    // Initial General Dynamic reloc, add
+  R_SPARC_TLS_GD_CALL = 59,   // Initial General Dynamic reloc, call
+  R_SPARC_TLS_LDM_HI22 = 60,  // Initial Local Dynamic reloc, high 22-bit
+  R_SPARC_TLS_LDM_LO10 = 61,  // Initial Local Dynamic reloc, low 10-bit
+  R_SPARC_TLS_LDM_ADD = 62,   // Initial Local Dynamic reloc, add
+  R_SPARC_TLS_LDM_CALL = 63,  // Initial Local Dynamic reloc, call
+  R_SPARC_TLS_LDO_HIX22 = 64, // Initial Local Dynamic, high extended 22-bit
+  R_SPARC_TLS_LDO_LOX10 = 65, // Initial Local Dynamic, low extended 10-bit
+  R_SPARC_TLS_LDO_ADD = 66,   // Initial Local Dynamic, add extended
+  R_SPARC_TLS_IE_HI22 = 67,   // Initial Initial Exec reloc, high 22-bit
+  R_SPARC_TLS_IE_LO10 = 68,   // Initial Initial Exec reloc, low 10-bit
+  R_SPARC_TLS_IE_LD = 69,     // Initial Initial Exec reloc, load 32-bit
+  R_SPARC_TLS_IE_LDX = 70,    // Initial Initial Exec reloc, load 64-bit
+  R_SPARC_TLS_IE_ADD = 71,    // Initial Initial Exec reloc, add
+  R_SPARC_TLS_LE_HIX22 = 72,  // Initial Local Exec reloc, high extended 22-bit
+  R_SPARC_TLS_LE_LOX10 = 73,  // Initial Local Exec reloc, low extended 10-bit
+  R_SPARC_TLS_DTPMOD32 = 74,  // Outstanding General/Local Dynamic reloc, 32-bit
+  R_SPARC_TLS_DTPMOD64 = 75,  // Outstanding General/Local Dynamic reloc, 64-bit
+  R_SPARC_TLS_DTPOFF32 = 76,  // Outstanding General Dynamic reloc, 32-bit
+  R_SPARC_TLS_DTPOFF64 = 77,  // Outstanding General Dynamic reloc, 64-bit
+  R_SPARC_TLS_TPOFF32 = 78,   // Outstanding Initial Exec reloc, 32-bit
+  R_SPARC_TLS_TPOFF64 = 79,   // Outstanding Initial Exec reloc, 64-bit
+
+  // GOT data code transformations
+  R_SPARC_GOTDATA_HIX22 = 80,
+  R_SPARC_GOTDATA_LOX10 = 81,
+  R_SPARC_GOTDATA_OP_HIX22 = 82,
+  R_SPARC_GOTDATA_OP_LOX10 = 83,
+  R_SPARC_GOTDATA_OP = 84,
+
+  R_SPARC_H34 = 85,           // Direct high 12 of 34 bit
+  R_SPARC_SIZE32 = 86,        // size of symbol, 32-bit
+  R_SPARC_SIZE64 = 87,        // size of symbol, 64-bit
+
+  R_SPARC_IRELATIVE = 249,    // Adjust indirectly by program base
+
+  // GNU vtable garbage collection extensions.
+  R_SPARC_GNU_VTINHERIT = 250,
+  R_SPARC_GNU_VTENTRY = 251,
+
+  R_SPARC_REV32 = 252,
+};
+
+// e_flags values defined for sparc
+enum
+{
+  EF_SPARC_EXT_MASK = 0xffff00,    // reserved for vendor extensions
+  EF_SPARC_32PLUS_MASK = 0xffff00, // bits indicating V8+ type
+  EF_SPARC_32PLUS = 0x000100,      // generic V8+ features
+  EF_SPARC_SUN_US1 = 0x000200,     // Sun UltraSPARC-I extensions
+  EF_SPARC_HAL_R1 = 0x000400,      // HAL R1 extensions
+  EF_SPARC_SUN_US3 = 0x000800,     // Sun UltraSPARC-III extensions
+  EF_SPARC_LEDATA = 0x800000,      // little endian data
+  EF_SPARCV9_MM = 0x3,             // memory model mask
+  EF_SPARCV9_TSO = 0x0,            // total store ordering
+  EF_SPARCV9_PSO = 0x1,            // partial store ordering
+  EF_SPARCV9_RMO = 0x2,            // relaxed store ordering
+};
+
+} // End namespace elfcpp.
+
+#endif // !defined(ELFCPP_SPARC_H)
diff --git a/contrib/binutils-2.21/gold/arm-reloc-property.cc b/contrib/binutils-2.21/gold/arm-reloc-property.cc
new file mode 100644 (file)
index 0000000..007653c
--- /dev/null
@@ -0,0 +1,333 @@
+// arm-reloc-property.cc -- ARM relocation property.
+
+// Copyright 2010 Free Software Foundation, Inc.
+// Written by Doug Kwan <dougkwan@google.com>.
+
+// This file is part of gold.
+
+// 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 "gold.h"
+
+#include <cstdio>
+#include <cstring>
+#include <stack>
+#include <string>
+#include <vector>
+
+#include "elfcpp.h"
+#include "arm.h"
+#include "arm-reloc-property.h"
+
+namespace gold
+{
+
+// Arm_reloc_property::Tree_node methods.
+
+// Parse an S-expression S and build a tree and return the root node.
+// Caller is responsible for releasing tree after use.
+
+Arm_reloc_property::Tree_node*
+Arm_reloc_property::Tree_node::make_tree(const std::string& s)
+{
+  std::stack<size_t> size_stack;
+  Tree_node_vector node_stack;
+
+  // strtok needs a non-const string pointer.
+  char* buffer = new char[s.size() + 1];
+  memcpy(buffer, s.data(), s.size());
+  buffer[s.size()] = '\0';
+  char* token = strtok(buffer, " ");
+
+  while (token != NULL)
+    {
+      if (strcmp(token, "(") == 0)
+       // Remember the node stack position for start of a new internal node.
+       size_stack.push(node_stack.size());
+      else if (strcmp(token, ")") == 0)
+       {
+         // Pop all tree nodes after the previous '(' and use them as
+         // children to build a new internal node.  Push internal node back.
+         size_t current_size = node_stack.size();
+         size_t prev_size = size_stack.top();
+         size_stack.pop();
+         Tree_node* node =
+           new Tree_node(node_stack.begin() + prev_size,
+                         node_stack.begin() + current_size); 
+         node_stack.resize(prev_size);
+         node_stack.push_back(node);
+       }
+      else
+       // Just push a leaf node to node_stack.
+       node_stack.push_back(new Tree_node(token));
+
+      token = strtok(NULL, " ");
+    }
+
+  delete[] buffer;
+
+  // At this point, size_stack should be empty and node_stack should only
+  // contain the root node.
+  gold_assert(size_stack.empty() && node_stack.size() == 1);
+  return node_stack[0];
+}
+
+// Arm_reloc_property methods.
+
+// Constructor.
+
+Arm_reloc_property::Arm_reloc_property(
+    unsigned int code,
+    const char* name,
+    Reloc_type rtype,
+    bool is_deprecated,
+    Reloc_class rclass,
+    const std::string& operation,
+    bool is_implemented,
+    int group_index,
+    bool checks_overflow)
+  : code_(code), name_(name), reloc_type_(rtype), reloc_class_(rclass),
+    group_index_(group_index), size_(0), align_(1),
+    relative_address_base_(RAB_NONE), is_deprecated_(is_deprecated),
+    is_implemented_(is_implemented), checks_overflow_(checks_overflow),
+    uses_got_entry_(false), uses_got_origin_(false), uses_plt_entry_(false),
+    uses_thumb_bit_(false), uses_symbol_base_(false), uses_addend_(false),
+    uses_symbol_(false)
+{
+  // Set size and alignment of static and dynamic relocations.
+  if (rtype == RT_STATIC)
+    {
+      switch (rclass)
+       {
+       case RC_DATA:
+         // Except for R_ARM_ABS16 and R_ARM_ABS8, all static data relocations
+         // have size 4.  All static data relocations have alignment of 1.
+         if (code == elfcpp::R_ARM_ABS8)
+           this->size_ = 1;
+         else if (code == elfcpp::R_ARM_ABS16)
+           this->size_ = 2;
+         else
+           this->size_ = 4;
+         this->align_ = 1;
+         break;
+       case RC_MISC:
+         // R_ARM_V4BX should be treated as an ARM relocation.  For all
+         // others, just use defaults.
+         if (code != elfcpp::R_ARM_V4BX)
+           break;
+         // Fall through.
+       case RC_ARM:
+         this->size_ = 4;
+         this->align_ = 4;
+         break;
+       case RC_THM16:
+         this->size_ = 2;
+         this->align_ = 2;
+         break;
+       case RC_THM32:
+         this->size_ = 4;
+         this->align_ = 2;
+         break;
+       default:
+         gold_unreachable();
+       }
+    }
+  else if (rtype == RT_DYNAMIC)
+    {
+      // With the exception of R_ARM_COPY, all dynamic relocations requires
+      // that the place being relocated is a word-aligned 32-bit object.
+      if (code != elfcpp::R_ARM_COPY)
+       {
+         this->size_ = 4;
+         this->align_ = 4;
+       }
+    }
+
+  // If no relocation operation is specified, we are done.
+  if (operation == "NONE")
+    return;
+
+  // Extract information from relocation operation.
+  Tree_node* root_node = Tree_node::make_tree(operation);
+  Tree_node* node = root_node;
+
+  // Check for an expression of the form XXX - YYY.
+  if (!node->is_leaf()
+      && node->child(0)->is_leaf()
+      && node->child(0)->name() == "-")
+    {
+      struct RAB_table_entry
+      {
+       Relative_address_base rab;
+       const char* name;
+      };
+
+      static const RAB_table_entry rab_table[] =
+      {
+       { RAB_B_S, "( B S )" },
+       { RAB_DELTA_B_S, "( DELTA_B ( S ) )" },
+       { RAB_GOT_ORG, "GOT_ORG" },
+       { RAB_P, "P" },
+       { RAB_Pa, "Pa" },
+       { RAB_TLS, "TLS" },
+       { RAB_tp, "tp" }
+      };
+
+      static size_t rab_table_size = sizeof(rab_table) / sizeof(rab_table[0]);
+      const std::string rhs(node->child(2)->s_expression());
+      for (size_t i = 0; i < rab_table_size; ++i)
+       if (rhs == rab_table[i].name)
+         {
+           this->relative_address_base_ = rab_table[i].rab;
+           break;
+         }
+
+      gold_assert(this->relative_address_base_ != RAB_NONE);
+      if (this->relative_address_base_ == RAB_B_S)
+       this->uses_symbol_base_ = true;
+      node = node->child(1);
+    }
+
+  // Check for an expression of the form XXX | T.
+  if (!node->is_leaf()
+      && node->child(0)->is_leaf()
+      && node->child(0)->name() == "|")
+    {
+      gold_assert(node->number_of_children() == 3
+                 && node->child(2)->is_leaf()
+                 && node->child(2)->name() == "T");
+      this->uses_thumb_bit_ = true;
+      node = node->child(1);
+    }
+
+  // Check for an expression of the form XXX + A.
+  if (!node->is_leaf()
+      && node->child(0)->is_leaf()
+      && node->child(0)->name() == "+")
+    {
+      gold_assert(node->number_of_children() == 3
+                 && node->child(2)->is_leaf()
+                 && node->child(2)->name() == "A");
+      this->uses_addend_ = true;
+      node = node->child(1);
+    }
+
+  // Check for an expression of the form XXX(S).
+  if (!node->is_leaf() && node->child(0)->is_leaf())
+    {
+      gold_assert(node->number_of_children() == 2
+                 && node->child(1)->is_leaf()
+                 && node->child(1)->name() == "S");
+      const std::string func(node->child(0)->name());
+      if (func == "B")
+       this->uses_symbol_base_ = true;
+      else if (func == "GOT")
+       this->uses_got_entry_ = true;
+      else if (func == "PLT")
+       this->uses_plt_entry_ = true;
+      else if (func == "Module" || func == "DELTA_B")
+       // These are used in dynamic relocations.
+       ;
+      else
+       gold_unreachable();
+      node = node->child(1);
+    }
+
+  gold_assert(node->is_leaf() && node->name() == "S");
+  this->uses_symbol_ = true;
+
+  delete root_node;
+}
+
+// Arm_reloc_property_table methods.
+
+// Constructor.  This processing informations in arm-reloc.def to
+// initialize the table.
+
+Arm_reloc_property_table::Arm_reloc_property_table()
+{
+  // These appers in arm-reloc.def.  Do not rename them.
+  Parse_expression A("A"), GOT_ORG("GOT_ORG"), NONE("NONE"), P("P"),
+                  Pa("Pa"), S("S"), T("T"), TLS("TLS"), tp("tp");
+  const bool Y(true), N(false);
+
+  for (unsigned int i = 0; i < Property_table_size; ++i)
+    this->table_[i] = NULL;
+
+#undef RD
+#define RD(name, type, deprecated, class, operation, is_implemented, \
+          group_index, checks_oveflow) \
+  do \
+    { \
+      unsigned int code = elfcpp::R_ARM_##name; \
+      gold_assert(code < Property_table_size); \
+      this->table_[code] = \
+       new Arm_reloc_property(elfcpp::R_ARM_##name, "R_ARM_" #name, \
+                              Arm_reloc_property::RT_##type, deprecated, \
+                              Arm_reloc_property::RC_##class, \
+                              (operation).s_expression(), is_implemented, \
+                              group_index, checks_oveflow); \
+    } \
+  while(0);
+
+#include "arm-reloc.def"
+#undef RD
+}
+
+// Return a string describing a relocation code that fails to get a
+// relocation property in get_implemented_static_reloc_property().
+
+std::string
+Arm_reloc_property_table::reloc_name_in_error_message(unsigned int code)
+{
+  gold_assert(code < Property_table_size);
+
+  const Arm_reloc_property* arp = this->table_[code];
+
+  if (arp == NULL)
+    {
+      char buffer[100];
+      sprintf(buffer, _("invalid reloc %u"), code);
+      return std::string(buffer);
+    }
+  
+  // gold only implements static relocation codes.
+  Arm_reloc_property::Reloc_type reloc_type = arp->reloc_type();
+  gold_assert(reloc_type == Arm_reloc_property::RT_STATIC
+             || !arp->is_implemented());
+
+  const char* prefix = NULL;
+  switch (reloc_type)
+    {
+    case Arm_reloc_property::RT_STATIC:
+      prefix = arp->is_implemented() ? _("reloc ") : _("unimplemented reloc ");
+      break;
+    case Arm_reloc_property::RT_DYNAMIC:
+      prefix = _("dynamic reloc ");
+      break;
+    case Arm_reloc_property::RT_PRIVATE:
+      prefix = _("private reloc ");
+      break;
+    case Arm_reloc_property::RT_OBSOLETE:
+      prefix = _("obsolete reloc ");
+      break;
+    default:
+      gold_unreachable();
+    }
+  return std::string(prefix) + arp->name();
+}
+
+} // End namespace gold.
diff --git a/contrib/binutils-2.21/gold/arm-reloc-property.h b/contrib/binutils-2.21/gold/arm-reloc-property.h
new file mode 100644 (file)
index 0000000..e7d7f50
--- /dev/null
@@ -0,0 +1,386 @@
+// arm-reloc-property.h -- ARM relocation properties   -*- C++ -*-
+
+// Copyright 2010 Free Software Foundation, Inc.
+// Written by Doug Kwan <dougkwan@google.com>.
+
+// This file is part of gold.
+
+// 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.
+
+#ifndef GOLD_ARM_RELOC_PROPERTY_H
+#define GOLD_ARM_RELOC_PROPERTY_H
+
+namespace gold
+{
+// The Arm_reloc_property class is to store information about a paticular
+// relocation code.
+
+class Arm_reloc_property
+{
+ public:
+  // Types of relocation codes.
+  enum Reloc_type {
+    RT_NONE,           // No relocation type.
+    RT_STATIC, // Relocations processed by static linkers.
+    RT_DYNAMIC,        // Relocations processed by dynamic linkers.
+    RT_PRIVATE,        // Private relocations, not supported by gold.
+    RT_OBSOLETE        // Obsolete relocations that should not be used.
+  };
+
+  // Classes of relocation codes.
+  enum Reloc_class {
+    RC_NONE,   // No relocation class.
+    RC_DATA,   // Data relocation.
+    RC_ARM,    // ARM instruction relocation.
+    RC_THM16,  // 16-bit THUMB instruction relocation.
+    RC_THM32,  // 32-bit THUMB instruction relocation.
+    RC_MISC    // Miscellaneous class.
+  };
+
+  // Types of bases of relative addressing relocation codes.
+  enum Relative_address_base {
+    RAB_NONE,          // Relocation is not relative addressing
+    RAB_B_S,           // Address origin of output segment of defining symbol.
+    RAB_DELTA_B_S,     // Change of address origin.
+    RAB_GOT_ORG,       // Origin of GOT.
+    RAB_P,             // Address of the place being relocated.
+    RAB_Pa,            // Adjusted address (P & 0xfffffffc).
+    RAB_TLS,           // Thread local storage.
+    RAB_tp             // Thread pointer.
+  };
+
+  // Relocation code represented by this.
+  unsigned int
+  code() const
+  { return this->code_; }
+
+  // Name of the relocation code.
+  const std::string&
+  name() const
+  { return this->name_; }
+  
+  // Type of relocation code.
+  Reloc_type
+  reloc_type() const
+  { return this->reloc_type_; }
+
+  // Whether this code is deprecated.
+  bool
+  is_deprecated() const
+  { return this->is_deprecated_; }
+
+  // Class of relocation code.
+  Reloc_class
+  reloc_class() const
+  { return this->reloc_class_; }
+
+  // Whether this code is implemented in gold.
+  bool
+  is_implemented() const
+  { return this->is_implemented_; }
+
+  // If code is a group relocation code, return the group number, otherwise -1.
+  int
+  group_index() const
+  { return this->group_index_; }
+
+  // Whether relocation checks for overflow.
+  bool
+  checks_overflow() const
+  { return this->checks_overflow_; }
+
+  // Return size of relocation.
+  size_t
+  size() const
+  { return this->size_; }
+
+  // Return alignment of relocation.
+  size_t
+  align() const
+  { return this->align_; }
+
+  // Whether relocation use a GOT entry.
+  bool
+  uses_got_entry() const
+  { return this->uses_got_entry_; }
+
+  // Whether relocation use a GOT origin.
+  bool
+  uses_got_origin() const
+  { return this->uses_got_origin_; }
+  
+  // Whether relocation uses the Thumb-bit in a symbol address.
+  bool
+  uses_thumb_bit() const
+  { return this->uses_thumb_bit_; }
+
+  // Whether relocation uses the symbol base.
+  bool
+  uses_symbol_base() const
+  { return this->uses_symbol_base_; }
+
+  // Whether relocation uses the symbol.
+  bool
+  uses_symbol() const
+  { return this->uses_symbol_; }
+
+  // Return the type of relative address base or RAB_NONE if this
+  // is not a relative addressing relocation.
+  Relative_address_base
+  relative_address_base() const
+  { return this->relative_address_base_; } 
+
+ protected:
+  // These are protected.  We only allow Arm_reloc_property_table to
+  // manage Arm_reloc_property. 
+  Arm_reloc_property(unsigned int code, const char* name, Reloc_type rtype,
+                    bool is_deprecated, Reloc_class rclass,
+                    const std::string& operation, bool is_implemented,
+                    int group_index, bool checks_overflow);
+
+  friend class Arm_reloc_property_table;
+  
+ private:
+  // Copying is not allowed.
+  Arm_reloc_property(const Arm_reloc_property&);
+  Arm_reloc_property& operator=(const Arm_reloc_property&);
+
+  // The Tree_node class is used to represent parsed relocation operations. 
+  // We look at Trees to extract information about relocation operations.
+  class Tree_node
+  {
+   public:
+    typedef std::vector<Tree_node*> Tree_node_vector;
+
+    // Construct a leaf node.
+    Tree_node(const char* name)
+      : is_leaf_(true), name_(name), children_()
+    { }
+
+    // Construct an internal node.  A node owns all its children and is
+    // responsible for releasing them at its own destruction.
+    Tree_node(Tree_node_vector::const_iterator begin,
+             Tree_node_vector::const_iterator end)
+      : is_leaf_(false), name_(), children_()
+    {
+      for (Tree_node_vector::const_iterator p = begin; p != end; ++p)
+       this->children_.push_back(*p);
+    }
+
+    ~Tree_node()
+    {
+      for(size_t i = 0; i <this->children_.size(); ++i)
+       delete this->children_[i];
+    }
+
+    // Whether this is a leaf node.
+    bool
+    is_leaf() const
+    { return this->is_leaf_; }
+
+    // Return name of this.  This is only valid for a leaf node.
+    const std::string&
+    name() const
+    {
+      gold_assert(this->is_leaf_);
+      return this->name_;
+    }
+
+    // Return the number of children.  This is only valid for a non-leaf node.
+    size_t
+    number_of_children() const
+    {
+      gold_assert(!this->is_leaf_);
+      return this->children_.size();
+    }
+
+    // Return the i-th child of this.  This is only valid for a non-leaf node.
+    Tree_node*
+    child(size_t i) const
+    {
+      gold_assert(!this->is_leaf_ && i < this->children_.size());
+      return this->children_[i];
+    }
+
+    // Parse an S-expression string and build a tree and return the root node.
+    // Caller is responsible for releasing tree after use.
+    static Tree_node*
+    make_tree(const std::string&);
+
+    // Convert a tree back to an S-expression string.
+    std::string
+    s_expression() const
+    {
+      if (this->is_leaf_)
+       return this->name_;
+
+      // Concatenate S-expressions of children. Enclose them with
+      // a pair of parentheses and use space as token delimiters.
+      std::string s("(");
+      for(size_t i = 0; i <this->children_.size(); ++i)
+       s = s + " " + this->children_[i]->s_expression();
+      return s + " )";
+    }
+
+   private:
+    // Whether this is a leaf node.
+    bool is_leaf_;
+    // Name of this if this is a leaf node.
+    std::string name_;
+    // Children of this if this a non-leaf node.
+    Tree_node_vector children_;
+  };
+
+  // Relocation code.
+  unsigned int code_;
+  // Relocation name.
+  std::string name_;
+  // Type of relocation.
+  Reloc_type reloc_type_;
+  // Class of relocation.
+  Reloc_class reloc_class_;
+  // Group index (0, 1, or 2) if this is a group relocation or -1 otherwise.
+  int group_index_; 
+  // Size of relocation.
+  size_t size_;
+  // Alignment of relocation.
+  size_t align_;
+  // Relative address base.
+  Relative_address_base relative_address_base_;
+  // Whether this is deprecated.
+  bool is_deprecated_ : 1;
+  // Whether this is implemented in gold.
+  bool is_implemented_ : 1;
+  // Whether this checks overflow.
+  bool checks_overflow_ : 1;
+  // Whether this uses a GOT entry.
+  bool uses_got_entry_ : 1;
+  // Whether this uses a GOT origin.
+  bool uses_got_origin_ : 1;
+  // Whether this uses a PLT entry.
+  bool uses_plt_entry_ : 1;
+  // Whether this uses the THUMB bit in symbol address.
+  bool uses_thumb_bit_ : 1;
+  // Whether this uses the symbol base.
+  bool uses_symbol_base_ : 1;
+  // Whether this uses an addend.
+  bool uses_addend_ : 1;
+  // Whether this uses the symbol.
+  bool uses_symbol_ : 1;
+};
+
+// Arm_reloc_property_table.  This table is used for looking up propeties
+// of relocationt types.  The table entries are initialized using information
+// from arm-reloc.def.
+
+class Arm_reloc_property_table
+{
+ public:
+  Arm_reloc_property_table();
+
+  // Return an Arm_reloc_property object for CODE if it is a valid relocation
+  // code or NULL otherwise.
+  const Arm_reloc_property*
+  get_reloc_property(unsigned int code) const
+  {
+    gold_assert(code < Property_table_size);
+    return this->table_[code];
+  }
+
+  // Like get_reloc_property but only return non-NULL if relocation code is
+  // static and implemented.
+  const Arm_reloc_property*
+  get_implemented_static_reloc_property(unsigned int code) const
+  {
+    gold_assert(code < Property_table_size);
+    const Arm_reloc_property* arp = this->table_[code];
+    return ((arp != NULL
+            && (arp->reloc_type() == Arm_reloc_property::RT_STATIC)
+            && arp->is_implemented())
+           ? arp
+           : NULL);
+  }
+  
+  // Return a string describing the a relocation code that is not
+  // an implemented static reloc code.
+  std::string
+  reloc_name_in_error_message(unsigned int code);
+
+ private:
+  // Copying is not allowed.
+  Arm_reloc_property_table(const Arm_reloc_property_table&);
+  Arm_reloc_property_table& operator=(const Arm_reloc_property_table&);
+
+  // The Parse_expression class is used to convert relocation operations in
+  // arm-reloc.def into S-expression strings, which are parsed again to
+  // build actual expression trees.  We do not build the expression trees
+  // directly because the parser for operations in arm-reloc.def is simpler
+  // this way.  Coversion from S-expressions to trees is simple.
+  class Parse_expression
+  {
+   public:
+    // Construction a Parse_expression with an S-expression string.
+    Parse_expression(const std::string& s_expression)
+      : s_expression_(s_expression)
+    { }
+
+    // Value of this expression as an S-expression string.
+    const std::string&
+    s_expression() const
+    { return this->s_expression_; }
+
+    // We want to overload operators used in relocation operations so
+    // that we can execute operations in arm-reloc.def to generate
+    // S-expressions directly.
+#define DEF_OPERATOR_OVERLOAD(op) \
+    Parse_expression \
+    operator op (const Parse_expression& e) \
+    { \
+      return Parse_expression("( " #op " " + this->s_expression_ + " " + \
+                             e.s_expression_ + " )"); \
+    }
+
+    // Operator appearing in relocation operations in arm-reloc.def.
+    DEF_OPERATOR_OVERLOAD(+)
+    DEF_OPERATOR_OVERLOAD(-)
+    DEF_OPERATOR_OVERLOAD(|)
+    
+   private:
+    // This represented as an S-expression string.
+    std::string s_expression_;
+  };
+
+#define DEF_RELOC_FUNC(name) \
+  static Parse_expression \
+  (name)(const Parse_expression& arg) \
+  { return Parse_expression("( " #name " " + arg.s_expression() + " )"); }
+
+  // Functions appearing in relocation operations in arm-reloc.def.
+  DEF_RELOC_FUNC(B)
+  DEF_RELOC_FUNC(DELTA_B)
+  DEF_RELOC_FUNC(GOT)
+  DEF_RELOC_FUNC(Module)
+  DEF_RELOC_FUNC(PLT)
+
+  static const unsigned int Property_table_size = 256;
+
+  // The property table.
+  Arm_reloc_property* table_[Property_table_size];
+};
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_ARM_RELOC_PROPERTY_H)
diff --git a/contrib/binutils-2.21/gold/arm-reloc.def b/contrib/binutils-2.21/gold/arm-reloc.def
new file mode 100644 (file)
index 0000000..2caf371
--- /dev/null
@@ -0,0 +1,194 @@
+// arm-reloc.def -- ARM relocation definitions.
+
+// Copyright 2010 Free Software Foundation, Inc.
+// Written by Doug Kwan <dougkwan@google.com>.
+
+// This file is part of gold.
+
+// 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.
+
+// The information here is based on the official ARM document "ELF for ARM
+// Architecture" (Document number ARM IHI 0044C).  The first five columns of
+// the table below are derived from Table 4-8 in the ARM ELF document.  Each
+// relocation from Table 4-8 corresponds to one relocation definition in the
+// table below.  A relocation defintion has the following information:
+//
+// Name: This is the name of the relocation without the "R_ARM_" prefix.
+//
+// Type: Relocation type.  There are four.
+//   - STATIC for static relocations processed by a static linker.
+//   - DYNAMIC for dynamic relocations processed by a dynamic linker.
+//   - PRIVATE for R_ARM_PRIVATE_<n> private relocation type.
+//   - OBSOLETE for old relocation types no longer used.
+//   We do not use DEPRECATED as a distinct type since we still have to
+//   handle deprecated relocations so we one of the types above.
+//
+// Deprecated:  Whether this is a deprecated relocation type.  The linker
+//   is expected to handle these though they should not be generated by fully
+//   conforming tool-chains.
+//
+// Operation: An expression specifying how the linker should performace a
+//   relocation.  If there is no operation or the operation cannot be
+//   specified, it is "NONE".
+//
+// Implemented: Whether this is implemented by the gold.
+//
+// Group_index: For a group relocation type, it is one of 0, 1 or 2.  For
+//   a non-group relocation type, it is -1.
+//
+// Overflow: Whether gold should check for overflow.  This is "No" by default
+//   for relocation types DYNAMIC, PRIVATE and OBSOLETE.
+//
+// Overflow-----------------------------------------------------------------+
+// Group index----------------------------------------------------------+   |
+// Implemented-------------------------------------------------------+  |   |
+// Operation-------------------------------+                         |  |   |
+// Class----------------------------+      |                         |  |   |
+// Deprecated--------------------+  |      |                         |  |   |
+// Type----------------+         |  |      |                         |  |   |
+// Name                |         |  |      |                         |  |   |
+// |                   |         |  |      |                         |  |   |
+RD(NONE              , STATIC  , N, MISC , NONE                   ,  Y, -1, N)
+RD(PC24              , STATIC  , Y, ARM  , ((S + A) | T) - P      ,  Y, -1, Y)
+RD(ABS32             , STATIC  , N, DATA , (S + A) | T            ,  Y, -1, N)
+RD(REL32             , STATIC  , N, DATA , ((S + A) | T) - P      ,  Y, -1, N)
+RD(LDR_PC_G0         , STATIC  , N, ARM  , S + A - P              ,  Y,  0, Y)
+RD(ABS16             , STATIC  , N, DATA , S + A                  ,  Y, -1, Y)
+RD(ABS12             , STATIC  , N, ARM  , S + A                  ,  Y, -1, Y)
+RD(THM_ABS5          , STATIC  , N, THM16, S + A                  ,  Y, -1, Y)
+RD(ABS8              , STATIC  , N, DATA , S + A                  ,  Y, -1, Y)
+RD(SBREL32           , STATIC  , N, DATA , ((S + A) | T) - B(S)   ,  N, -1, N)
+RD(THM_CALL          , STATIC  , N, THM32, ((S + A) | T) - P      ,  Y, -1, Y)
+RD(THM_PC8           , STATIC  , N, THM16, S + A - Pa             ,  Y, -1, Y)
+RD(BREL_ADJ          , DYNAMIC , N, DATA , DELTA_B(S) + A         ,  Y, -1, N)
+RD(TLS_DESC          , DYNAMIC , N, DATA , NONE                   ,  Y, -1, N)
+RD(THM_SWI8          , OBSOLETE, N, NONE , NONE                   ,  N, -1, N)
+RD(XPC25             , OBSOLETE, N, NONE , NONE                   ,  N, -1, N)
+RD(THM_XPC22         , OBSOLETE, N, NONE , NONE                   ,  N, -1, N)
+RD(TLS_DTPMOD32      , DYNAMIC , N, DATA , Module(S)              ,  Y, -1, N)
+RD(TLS_DTPOFF32      , DYNAMIC , N, DATA , S + A - TLS            ,  Y, -1, N)
+RD(TLS_TPOFF32       , DYNAMIC , N, DATA , S + A - tp             ,  Y, -1, N)
+RD(COPY              , DYNAMIC , N, MISC , NONE                   ,  Y, -1, N)
+RD(GLOB_DAT          , DYNAMIC , N, DATA , (S + A) | T            ,  Y, -1, N)
+RD(JUMP_SLOT         , DYNAMIC , N, DATA , (S + A) | T            ,  Y, -1, N)
+RD(RELATIVE          , DYNAMIC , N, DATA , B(S) + A               ,  Y, -1, N)
+RD(GOTOFF32          , STATIC  , N, DATA , ((S + A) | T) - GOT_ORG,  Y, -1, N)
+RD(BASE_PREL         , STATIC  , N, DATA , B(S) + A - P           ,  Y, -1, N)
+RD(GOT_BREL          , STATIC  , N, DATA , GOT(S) + A - GOT_ORG   ,  Y, -1, N)
+RD(PLT32             , STATIC  , Y, ARM  , ((S + A) | T) - P      ,  Y, -1, Y)
+RD(CALL              , STATIC  , N, ARM  , ((S + A) | T) - P      ,  Y, -1, Y)
+RD(JUMP24            , STATIC  , N, ARM  , ((S + A) | T) - P      ,  Y, -1, Y)
+RD(THM_JUMP24        , STATIC  , N, THM32, ((S + A) | T) - P      ,  Y, -1, Y)
+RD(BASE_ABS          , STATIC  , N, DATA , B(S) + A               ,  Y, -1, N)
+RD(ALU_PCREL_7_0     , OBSOLETE, N, NONE , NONE                   ,  N, -1, N)
+RD(ALU_PCREL_15_8    , OBSOLETE, N, NONE , NONE                   ,  N, -1, N)
+RD(ALU_PCREL_23_15   , OBSOLETE, N, NONE , NONE                   ,  N, -1, N)
+RD(LDR_SBREL_11_0_NC , STATIC  , Y, ARM  , S + A - B(S)           ,  N, -1, N)
+RD(ALU_SBREL_19_12_NC, STATIC  , Y, ARM  , S + A - B(S)           ,  N, -1, N)
+RD(ALU_SBREL_27_20_CK, STATIC  , Y, ARM  , S + A - B(S)           ,  N, -1, Y)
+RD(TARGET1           , STATIC  , N, MISC , NONE                   ,  Y, -1, N)
+RD(SBREL31           , STATIC  , Y, DATA , ((S + A) | T) - B(S)   ,  N, -1, N)
+RD(V4BX              , STATIC  , N, MISC , NONE                   ,  Y, -1, N)
+RD(TARGET2           , STATIC  , N, MISC , NONE                   ,  Y, -1, N)
+RD(PREL31            , STATIC  , N, DATA , ((S + A) | T) - P      ,  Y, -1, Y)
+RD(MOVW_ABS_NC       , STATIC  , N, ARM  , (S + A) | T            ,  Y, -1, N)
+RD(MOVT_ABS          , STATIC  , N, ARM  , S + A                  ,  Y, -1, Y)
+RD(MOVW_PREL_NC      , STATIC  , N, ARM  , ((S + A) | T) - P      ,  Y, -1, N)
+RD(MOVT_PREL         , STATIC  , N, ARM  , (S + A)  - P           ,  Y, -1, Y)
+RD(THM_MOVW_ABS_NC   , STATIC  , N, THM32, (S + A) | T            ,  Y, -1, N)
+RD(THM_MOVT_ABS      , STATIC  , N, THM32, S + A                  ,  Y, -1, N)
+RD(THM_MOVW_PREL_NC  , STATIC  , N, THM32, ((S + A) | T) - P      ,  Y, -1, N)
+RD(THM_MOVT_PREL     , STATIC  , N, THM32, S + A - P              ,  Y, -1, N)
+RD(THM_JUMP19        , STATIC  , N, THM32, ((S + A) | T) - P      ,  Y, -1, Y)
+RD(THM_JUMP6         , STATIC  , N, THM16, S + A - P              ,  Y, -1, Y)
+RD(THM_ALU_PREL_11_0 , STATIC  , N, THM32, ((S + A) | T) - Pa     ,  Y, -1, Y)
+RD(THM_PC12          , STATIC  , N, THM32, S + A - Pa             ,  Y, -1, Y)
+RD(ABS32_NOI         , STATIC  , N, DATA , S + A                  ,  Y, -1, N)
+RD(REL32_NOI         , STATIC  , N, DATA , S + A - P              ,  N, -1, N)
+RD(ALU_PC_G0_NC      , STATIC  , N, ARM  , ((S + A) | T) - P      ,  Y,  0, N)
+RD(ALU_PC_G0         , STATIC  , N, ARM  , ((S + A) | T) - P      ,  Y,  0, Y)
+RD(ALU_PC_G1_NC      , STATIC  , N, ARM  , ((S + A) | T) - P      ,  Y,  1, N)
+RD(ALU_PC_G1         , STATIC  , N, ARM  , ((S + A) | T) - P      ,  Y,  1, Y)
+RD(ALU_PC_G2         , STATIC  , N, ARM  , ((S + A) | T) - P      ,  Y,  2, Y)
+RD(LDR_PC_G1         , STATIC  , N, ARM  , S + A - P              ,  Y,  1, Y)
+RD(LDR_PC_G2         , STATIC  , N, ARM  , S + A - P              ,  Y,  2, Y)
+RD(LDRS_PC_G0        , STATIC  , N, ARM  , S + A - P              ,  Y,  0, Y)
+RD(LDRS_PC_G1        , STATIC  , N, ARM  , S + A - P              ,  Y,  1, Y)
+RD(LDRS_PC_G2        , STATIC  , N, ARM  , S + A - P              ,  Y,  2, Y)
+RD(LDC_PC_G0         , STATIC  , N, ARM  , S + A - P              ,  Y,  0, Y)
+RD(LDC_PC_G1         , STATIC  , N, ARM  , S + A - P              ,  Y,  1, Y)
+RD(LDC_PC_G2         , STATIC  , N, ARM  , S + A - P              ,  Y,  2, Y)
+RD(ALU_SB_G0_NC      , STATIC  , N, ARM  , ((S + A) | T) - B(S)   ,  Y,  0, N)
+RD(ALU_SB_G0         , STATIC  , N, ARM  , ((S + A) | T) - B(S)   ,  Y,  0, Y)
+RD(ALU_SB_G1_NC      , STATIC  , N, ARM  , ((S + A) | T) - B(S)   ,  Y,  1, N)
+RD(ALU_SB_G1         , STATIC  , N, ARM  , ((S + A) | T) - B(S)   ,  Y,  1, Y)
+RD(ALU_SB_G2         , STATIC  , N, ARM  , ((S + A) | T) - B(S)   ,  Y,  2, Y)
+RD(LDR_SB_G0         , STATIC  , N, ARM  , S + A - B(S)           ,  Y,  0, Y)
+RD(LDR_SB_G1         , STATIC  , N, ARM  , S + A - B(S)           ,  Y,  1, Y)
+RD(LDR_SB_G2         , STATIC  , N, ARM  , S + A - B(S)           ,  Y,  2, Y)
+RD(LDRS_SB_G0        , STATIC  , N, ARM  , S + A - B(S)           ,  Y,  0, Y)
+RD(LDRS_SB_G1        , STATIC  , N, ARM  , S + A - B(S)           ,  Y,  1, Y)
+RD(LDRS_SB_G2        , STATIC  , N, ARM  , S + A - B(S)           ,  Y,  2, Y)
+RD(LDC_SB_G0         , STATIC  , N, ARM  , S + A - B(S)           ,  Y,  0, Y)
+RD(LDC_SB_G1         , STATIC  , N, ARM  , S + A - B(S)           ,  Y,  1, Y)
+RD(LDC_SB_G2         , STATIC  , N, ARM  , S + A - B(S)           ,  Y,  2, Y)
+RD(MOVW_BREL_NC      , STATIC  , N, ARM  , ((S + A) | T) - B(S)   ,  Y, -1, N)
+RD(MOVT_BREL         , STATIC  , N, ARM  , S + A - B(S)           ,  Y, -1, Y)
+RD(MOVW_BREL         , STATIC  , N, ARM  , ((S + A) | T) - B(S)   ,  Y, -1, Y)
+RD(THM_MOVW_BREL_NC  , STATIC  , N, THM32, ((S + A) | T) - B(S)   ,  Y, -1, N)
+RD(THM_MOVT_BREL     , STATIC  , N, THM32, S + A - B(S)           ,  Y, -1, N)
+RD(THM_MOVW_BREL     , STATIC  , N, THM32, ((S + A) | T) - B(S)   ,  Y, -1, Y)
+RD(TLS_GOTDESC       , STATIC  , N, DATA , NONE                   ,  Y, -1, N)
+RD(TLS_CALL          , STATIC  , N, ARM  , NONE                   ,  N, -1, Y)
+RD(TLS_DESCSEQ       , STATIC  , N, ARM  , NONE                   ,  N, -1, Y)
+RD(THM_TLS_CALL      , STATIC  , N, THM32, NONE                   ,  N, -1, Y)
+RD(PLT32_ABS         , STATIC  , N, DATA , PLT(S) + A             ,  N, -1, N)
+RD(GOT_ABS           , STATIC  , N, DATA , GOT(S) + A             ,  N, -1, N)
+RD(GOT_PREL          , STATIC  , N, DATA , GOT(S) + A - P         ,  Y, -1, N)
+RD(GOT_BREL12        , STATIC  , N, ARM  , GOT(S) + A - GOT_ORG   ,  N, -1, Y)
+RD(GOTOFF12          , STATIC  , N, ARM  , S + A - GOT_ORG        ,  N, -1, Y)
+RD(GOTRELAX          , STATIC  , N, MISC , NONE                   ,  N, -1, N)
+RD(GNU_VTENTRY       , STATIC  , Y, DATA , NONE                   ,  Y, -1, N)
+RD(GNU_VTINHERIT     , STATIC  , Y, DATA , NONE                   ,  Y, -1, N)
+RD(THM_JUMP11        , STATIC  , N, THM16, S + A - P              ,  Y, -1, Y)
+RD(THM_JUMP8         , STATIC  , N, THM16, S + A - P              ,  Y, -1, Y)
+RD(TLS_GD32          , STATIC  , N, DATA , GOT(S) + A - P         ,  Y, -1, N)
+RD(TLS_LDM32         , STATIC  , N, DATA , GOT(S) + A - P         ,  Y, -1, N)
+RD(TLS_LDO32         , STATIC  , N, DATA , S + A - TLS            ,  Y, -1, N)
+RD(TLS_IE32          , STATIC  , N, DATA , GOT(S) + A - P         ,  Y, -1, N)
+RD(TLS_LE32          , STATIC  , N, DATA , S + A - tp             ,  Y, -1, N)
+RD(TLS_LDO12         , STATIC  , N, ARM  , S + A - TLS            ,  N, -1, Y)
+RD(TLS_LE12          , STATIC  , N, ARM  , S + A - tp             ,  N, -1, Y)
+RD(TLS_IE12GP        , STATIC  , N, ARM  , GOT(S) + A - GOT_ORG   ,  N, -1, Y)
+RD(PRIVATE_0         , PRIVATE , N, NONE , NONE                   ,  N, -1, N)
+RD(PRIVATE_1         , PRIVATE , N, NONE , NONE                   ,  N, -1, N)
+RD(PRIVATE_2         , PRIVATE , N, NONE , NONE                   ,  N, -1, N)
+RD(PRIVATE_3         , PRIVATE , N, NONE , NONE                   ,  N, -1, N)
+RD(PRIVATE_4         , PRIVATE , N, NONE , NONE                   ,  N, -1, N)
+RD(PRIVATE_5         , PRIVATE , N, NONE , NONE                   ,  N, -1, N)
+RD(PRIVATE_6         , PRIVATE , N, NONE , NONE                   ,  N, -1, N)
+RD(PRIVATE_7         , PRIVATE , N, NONE , NONE                   ,  N, -1, N)
+RD(PRIVATE_8         , PRIVATE , N, NONE , NONE                   ,  N, -1, N)
+RD(PRIVATE_9         , PRIVATE , N, NONE , NONE                   ,  N, -1, N)
+RD(PRIVATE_10        , PRIVATE , N, NONE , NONE                   ,  N, -1, N)
+RD(PRIVATE_11        , PRIVATE , N, NONE , NONE                   ,  N, -1, N)
+RD(PRIVATE_12        , PRIVATE , N, NONE , NONE                   ,  N, -1, N)
+RD(PRIVATE_13        , PRIVATE , N, NONE , NONE                   ,  N, -1, N)
+RD(PRIVATE_14        , PRIVATE , N, NONE , NONE                   ,  N, -1, N)
+RD(PRIVATE_15        , PRIVATE , N, NONE , NONE                   ,  N, -1, N)
+RD(ME_TOO            , OBSOLETE, N, NONE , NONE                   ,  N, -1, N)
+RD(THM_TLS_DESCSEQ16 , STATIC  , N, THM16, NONE                   ,  N, -1, Y)
+RD(THM_TLS_DESCSEQ32 , STATIC  , N, THM32, NONE                   ,  N, -1, Y)
diff --git a/contrib/binutils-2.21/gold/freebsd.h b/contrib/binutils-2.21/gold/freebsd.h
new file mode 100644 (file)
index 0000000..de69735
--- /dev/null
@@ -0,0 +1,168 @@
+// freebsd.h -- FreeBSD support for gold    -*- C++ -*-
+
+// Copyright 2009 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// This file is part of gold.
+
+// 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 "target.h"
+#include "target-select.h"
+
+#ifndef GOLD_FREEBSD_H
+#define GOLD_FREEBSD_H
+
+namespace gold
+{
+
+// FreeBSD 4.1 and later wants the EI_OSABI field in the ELF header to
+// be set to ELFOSABI_FREEBSD.  This is a subclass of Sized_target
+// which supports that.  The real target would be a subclass of this
+// one.  We permit combining FreeBSD and non-FreeBSD object files.
+// The effect of this target is to set the code in the output file.
+
+template<int size, bool big_endian>
+class Target_freebsd : public Sized_target<size, big_endian>
+{
+ public:
+  // Set the value to use for the EI_OSABI field in the ELF header.
+  void
+  set_osabi(elfcpp::ELFOSABI osabi)
+  { this->osabi_ = osabi; }
+
+ protected:
+  Target_freebsd(const Target::Target_info* pti)
+    : Sized_target<size, big_endian>(pti),
+      osabi_(elfcpp::ELFOSABI_NONE)
+  { }
+
+  virtual void
+  do_adjust_elf_header(unsigned char* view, int len) const;
+
+ private:
+  // Value to store in the EI_OSABI field of the ELF file header.
+  elfcpp::ELFOSABI osabi_;
+};
+
+// Adjust the ELF file header by storing the requested value in the
+// OSABI field.  This is for FreeBSD support.
+
+template<int size, bool big_endian>
+inline void
+Target_freebsd<size, big_endian>::do_adjust_elf_header(unsigned char* view,
+                                                      int len) const
+{
+  if (this->osabi_ != elfcpp::ELFOSABI_NONE)
+    {
+      gold_assert(len == elfcpp::Elf_sizes<size>::ehdr_size);
+
+      elfcpp::Ehdr<size, false> ehdr(view);
+      unsigned char e_ident[elfcpp::EI_NIDENT];
+      memcpy(e_ident, ehdr.get_e_ident(), elfcpp::EI_NIDENT);
+
+      e_ident[elfcpp::EI_OSABI] = this->osabi_;
+
+      elfcpp::Ehdr_write<size, false> oehdr(view);
+      oehdr.put_e_ident(e_ident);
+    }
+}
+
+// A target selector for targets which permit combining both FreeBSD
+// and non-FreeBSD object files.
+
+class Target_selector_freebsd : public Target_selector
+{
+ public:
+  Target_selector_freebsd(int machine, int size, bool is_big_endian,
+                         const char* bfd_name,
+                         const char* freebsd_bfd_name)
+    : Target_selector(machine, size, is_big_endian, NULL),
+      bfd_name_(bfd_name), freebsd_bfd_name_(freebsd_bfd_name)
+  { }
+
+ protected:
+  // If we see a FreeBSD input file, mark the output file as using
+  // FreeBSD.
+  virtual Target*
+  do_recognize(int, int osabi, int)
+  {
+    Target* ret = this->instantiate_target();
+    if (osabi == elfcpp::ELFOSABI_FREEBSD)
+      this->set_osabi(ret);
+    return ret;
+  }
+  
+  // Recognize two names.
+  virtual Target*
+  do_recognize_by_name(const char* name)
+  {
+    if (strcmp(name, this->bfd_name_) == 0)
+      return this->instantiate_target();
+    else if (strcmp(name, this->freebsd_bfd_name_) == 0)
+      {
+       Target* ret = this->instantiate_target();
+       this->set_osabi(ret);
+       return ret;
+      }
+    else
+      return NULL;
+  }
+
+  // Print both names in --help output.
+  virtual void
+  do_supported_names(std::vector<const char*>* names)
+  {
+    names->push_back(this->bfd_name_);
+    names->push_back(this->freebsd_bfd_name_);
+  }
+
+ private:
+  // Set the OSABI field.  This is quite ugly.
+  void
+  set_osabi(Target* target)
+  {
+    if (this->get_size() == 32)
+      {
+       if (this->is_big_endian())
+         static_cast<Target_freebsd<32, true>*>(target)->
+           set_osabi(elfcpp::ELFOSABI_FREEBSD);
+       else
+         static_cast<Target_freebsd<32, false>*>(target)->
+           set_osabi(elfcpp::ELFOSABI_FREEBSD);
+      }
+    else if (this->get_size() == 64)
+      {
+       if (this->is_big_endian())
+         static_cast<Target_freebsd<64, true>*>(target)->
+           set_osabi(elfcpp::ELFOSABI_FREEBSD);
+       else
+         static_cast<Target_freebsd<64, false>*>(target)->
+           set_osabi(elfcpp::ELFOSABI_FREEBSD);
+      }
+    else
+      gold_unreachable();
+  }
+
+  // The BFD name for the non-Freebsd target.
+  const char* bfd_name_;
+  // The BFD name for the Freebsd target.
+  const char* freebsd_bfd_name_;
+};
+
+} // end namespace gold
+
+#endif // !defined(GOLD_FREEBSD_H)
diff --git a/contrib/binutils-2.21/gold/powerpc.cc b/contrib/binutils-2.21/gold/powerpc.cc
new file mode 100644 (file)
index 0000000..49af65f
--- /dev/null
@@ -0,0 +1,2099 @@
+// powerpc.cc -- powerpc target support for gold.
+
+// Copyright 2008, 2009, 2010 Free Software Foundation, Inc.
+// Written by David S. Miller <davem@davemloft.net>
+//        and David Edelsohn <edelsohn@gnu.org>
+
+// This file is part of gold.
+
+// 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 "gold.h"
+
+#include "elfcpp.h"
+#include "parameters.h"
+#include "reloc.h"
+#include "powerpc.h"
+#include "object.h"
+#include "symtab.h"
+#include "layout.h"
+#include "output.h"
+#include "copy-relocs.h"
+#include "target.h"
+#include "target-reloc.h"
+#include "target-select.h"
+#include "tls.h"
+#include "errors.h"
+#include "gc.h"
+
+namespace
+{
+
+using namespace gold;
+
+template<int size, bool big_endian>
+class Output_data_plt_powerpc;
+
+template<int size, bool big_endian>
+class Target_powerpc : public Sized_target<size, big_endian>
+{
+ public:
+  typedef Output_data_reloc<elfcpp::SHT_RELA, true, size, big_endian> Reloc_section;
+
+  Target_powerpc()
+    : Sized_target<size, big_endian>(&powerpc_info),
+      got_(NULL), got2_(NULL), toc_(NULL),
+      plt_(NULL), rela_dyn_(NULL),
+      copy_relocs_(elfcpp::R_POWERPC_COPY),
+      dynbss_(NULL), got_mod_index_offset_(-1U)
+  {
+  }
+
+  // Process the relocations to determine unreferenced sections for 
+  // garbage collection.
+  void
+  gc_process_relocs(Symbol_table* symtab,
+                   Layout* layout,
+                   Sized_relobj<size, big_endian>* object,
+                   unsigned int data_shndx,
+                   unsigned int sh_type,
+                   const unsigned char* prelocs,
+                   size_t reloc_count,
+                   Output_section* output_section,
+                   bool needs_special_offset_handling,
+                   size_t local_symbol_count,
+                   const unsigned char* plocal_symbols);
+
+  // Scan the relocations to look for symbol adjustments.
+  void
+  scan_relocs(Symbol_table* symtab,
+             Layout* layout,
+             Sized_relobj<size, big_endian>* object,
+             unsigned int data_shndx,
+             unsigned int sh_type,
+             const unsigned char* prelocs,
+             size_t reloc_count,
+             Output_section* output_section,
+             bool needs_special_offset_handling,
+             size_t local_symbol_count,
+             const unsigned char* plocal_symbols);
+  // Finalize the sections.
+  void
+  do_finalize_sections(Layout*, const Input_objects*, Symbol_table*);
+
+  // Return the value to use for a dynamic which requires special
+  // treatment.
+  uint64_t
+  do_dynsym_value(const Symbol*) const;
+
+  // Relocate a section.
+  void
+  relocate_section(const Relocate_info<size, big_endian>*,
+                  unsigned int sh_type,
+                  const unsigned char* prelocs,
+                  size_t reloc_count,
+                  Output_section* output_section,
+                  bool needs_special_offset_handling,
+                  unsigned char* view,
+                  typename elfcpp::Elf_types<size>::Elf_Addr view_address,
+                  section_size_type view_size,
+                  const Reloc_symbol_changes*);
+
+  // Scan the relocs during a relocatable link.
+  void
+  scan_relocatable_relocs(Symbol_table* symtab,
+                         Layout* layout,
+                         Sized_relobj<size, big_endian>* object,
+                         unsigned int data_shndx,
+                         unsigned int sh_type,
+                         const unsigned char* prelocs,
+                         size_t reloc_count,
+                         Output_section* output_section,
+                         bool needs_special_offset_handling,
+                         size_t local_symbol_count,
+                         const unsigned char* plocal_symbols,
+                         Relocatable_relocs*);
+
+  // Relocate a section during a relocatable link.
+  void
+  relocate_for_relocatable(const Relocate_info<size, big_endian>*,
+                          unsigned int sh_type,
+                          const unsigned char* prelocs,
+                          size_t reloc_count,
+                          Output_section* output_section,
+                          off_t offset_in_output_section,
+                          const Relocatable_relocs*,
+                          unsigned char* view,
+                          typename elfcpp::Elf_types<size>::Elf_Addr view_address,
+                          section_size_type view_size,
+                          unsigned char* reloc_view,
+                          section_size_type reloc_view_size);
+
+  // Return whether SYM is defined by the ABI.
+  bool
+  do_is_defined_by_abi(const Symbol* sym) const
+  {
+    return strcmp(sym->name(), "___tls_get_addr") == 0;
+  }
+
+  // Return the size of the GOT section.
+  section_size_type
+  got_size() const
+  {
+    gold_assert(this->got_ != NULL);
+    return this->got_->data_size();
+  }
+
+  // Return the number of entries in the GOT.
+  unsigned int
+  got_entry_count() const
+  {
+    if (this->got_ == NULL)
+      return 0;
+    return this->got_size() / (size / 8);
+  }
+
+  // Return the number of entries in the PLT.
+  unsigned int
+  plt_entry_count() const;
+
+  // Return the offset of the first non-reserved PLT entry.
+  unsigned int
+  first_plt_entry_offset() const;
+
+  // Return the size of each PLT entry.
+  unsigned int
+  plt_entry_size() const;
+
+ private:
+
+  // The class which scans relocations.
+  class Scan
+  {
+  public:
+    Scan()
+      : issued_non_pic_error_(false)
+    { }
+
+    inline void
+    local(Symbol_table* symtab, Layout* layout, Target_powerpc* target,
+         Sized_relobj<size, big_endian>* object,
+         unsigned int data_shndx,
+         Output_section* output_section,
+         const elfcpp::Rela<size, big_endian>& reloc, unsigned int r_type,
+         const elfcpp::Sym<size, big_endian>& lsym);
+
+    inline void
+    global(Symbol_table* symtab, Layout* layout, Target_powerpc* target,
+          Sized_relobj<size, big_endian>* object,
+          unsigned int data_shndx,
+          Output_section* output_section,
+          const elfcpp::Rela<size, big_endian>& reloc, unsigned int r_type,
+          Symbol* gsym);
+
+    inline bool
+    local_reloc_may_be_function_pointer(Symbol_table* , Layout* ,
+                                       Target_powerpc* ,
+                                       Sized_relobj<size, big_endian>* ,
+                                       unsigned int ,
+                                       Output_section* ,
+                                       const elfcpp::Rela<size, big_endian>& ,
+                                       unsigned int ,
+                                       const elfcpp::Sym<size, big_endian>&)
+    { return false; }
+
+    inline bool
+    global_reloc_may_be_function_pointer(Symbol_table* , Layout* ,
+                                        Target_powerpc* ,
+                                        Sized_relobj<size, big_endian>* ,
+                                        unsigned int ,
+                                        Output_section* ,
+                                        const elfcpp::Rela<size,
+                                                           big_endian>& ,
+                                        unsigned int , Symbol*)
+    { return false; }
+
+  private:
+    static void
+    unsupported_reloc_local(Sized_relobj<size, big_endian>*,
+                           unsigned int r_type);
+
+    static void
+    unsupported_reloc_global(Sized_relobj<size, big_endian>*,
+                            unsigned int r_type, Symbol*);
+
+    static void
+    generate_tls_call(Symbol_table* symtab, Layout* layout,
+                     Target_powerpc* target);
+
+    void
+    check_non_pic(Relobj*, unsigned int r_type);
+
+    // Whether we have issued an error about a non-PIC compilation.
+    bool issued_non_pic_error_;
+  };
+
+  // The class which implements relocation.
+  class Relocate
+  {
+   public:
+    // Do a relocation.  Return false if the caller should not issue
+    // any warnings about this relocation.
+    inline bool
+    relocate(const Relocate_info<size, big_endian>*, Target_powerpc*,
+            Output_section*, size_t relnum,
+            const elfcpp::Rela<size, big_endian>&,
+            unsigned int r_type, const Sized_symbol<size>*,
+            const Symbol_value<size>*,
+            unsigned char*,
+            typename elfcpp::Elf_types<size>::Elf_Addr,
+            section_size_type);
+
+   private:
+    // Do a TLS relocation.
+    inline void
+    relocate_tls(const Relocate_info<size, big_endian>*,
+                Target_powerpc* target,
+                 size_t relnum, const elfcpp::Rela<size, big_endian>&,
+                unsigned int r_type, const Sized_symbol<size>*,
+                const Symbol_value<size>*,
+                unsigned char*,
+                typename elfcpp::Elf_types<size>::Elf_Addr,
+                section_size_type);
+  };
+
+  // A class which returns the size required for a relocation type,
+  // used while scanning relocs during a relocatable link.
+  class Relocatable_size_for_reloc
+  {
+   public:
+    unsigned int
+    get_size_for_reloc(unsigned int, Relobj*);
+  };
+
+  // Get the GOT section, creating it if necessary.
+  Output_data_got<size, big_endian>*
+  got_section(Symbol_table*, Layout*);
+
+  Output_data_space*
+  got2_section() const
+  {
+    gold_assert(this->got2_ != NULL);
+    return this->got2_;
+  }
+
+  // Get the TOC section.
+  Output_data_space*
+  toc_section() const
+  {
+    gold_assert(this->toc_ != NULL);
+    return this->toc_;
+  }
+
+  // Create a PLT entry for a global symbol.
+  void
+  make_plt_entry(Symbol_table*, Layout*, Symbol*);
+
+  // Create a GOT entry for the TLS module index.
+  unsigned int
+  got_mod_index_entry(Symbol_table* symtab, Layout* layout,
+                     Sized_relobj<size, big_endian>* object);
+
+  // Get the PLT section.
+  const Output_data_plt_powerpc<size, big_endian>*
+  plt_section() const
+  {
+    gold_assert(this->plt_ != NULL);
+    return this->plt_;
+  }
+
+  // Get the dynamic reloc section, creating it if necessary.
+  Reloc_section*
+  rela_dyn_section(Layout*);
+
+  // Copy a relocation against a global symbol.
+  void
+  copy_reloc(Symbol_table* symtab, Layout* layout,
+             Sized_relobj<size, big_endian>* object,
+            unsigned int shndx, Output_section* output_section,
+            Symbol* sym, const elfcpp::Rela<size, big_endian>& reloc)
+  {
+    this->copy_relocs_.copy_reloc(symtab, layout,
+                                 symtab->get_sized_symbol<size>(sym),
+                                 object, shndx, output_section,
+                                 reloc, this->rela_dyn_section(layout));
+  }
+
+  // Information about this specific target which we pass to the
+  // general Target structure.
+  static Target::Target_info powerpc_info;
+
+  // The types of GOT entries needed for this platform.
+  // These values are exposed to the ABI in an incremental link.
+  // Do not renumber existing values without changing the version
+  // number of the .gnu_incremental_inputs section.
+  enum Got_type
+  {
+    GOT_TYPE_STANDARD = 0,      // GOT entry for a regular symbol
+    GOT_TYPE_TLS_OFFSET = 1,    // GOT entry for TLS offset
+    GOT_TYPE_TLS_PAIR = 2,      // GOT entry for TLS module/offset pair
+  };
+
+  // The GOT section.
+  Output_data_got<size, big_endian>* got_;
+  // The GOT2 section.
+  Output_data_space* got2_;
+  // The TOC section.
+  Output_data_space* toc_;
+  // The PLT section.
+  Output_data_plt_powerpc<size, big_endian>* plt_;
+  // The dynamic reloc section.
+  Reloc_section* rela_dyn_;
+  // Relocs saved to avoid a COPY reloc.
+  Copy_relocs<elfcpp::SHT_RELA, size, big_endian> copy_relocs_;
+  // Space for variables copied with a COPY reloc.
+  Output_data_space* dynbss_;
+  // Offset of the GOT entry for the TLS module index;
+  unsigned int got_mod_index_offset_;
+};
+
+template<>
+Target::Target_info Target_powerpc<32, true>::powerpc_info =
+{
+  32,                  // size
+  true,                        // is_big_endian
+  elfcpp::EM_PPC,      // machine_code
+  false,               // has_make_symbol
+  false,               // has_resolve
+  false,               // has_code_fill
+  true,                        // is_default_stack_executable
+  '\0',                        // wrap_char
+  "/usr/lib/ld.so.1",  // dynamic_linker
+  0x10000000,          // default_text_segment_address
+  64 * 1024,           // abi_pagesize (overridable by -z max-page-size)
+  4 * 1024,            // common_pagesize (overridable by -z common-page-size)
+  elfcpp::SHN_UNDEF,   // small_common_shndx
+  elfcpp::SHN_UNDEF,   // large_common_shndx
+  0,                   // small_common_section_flags
+  0,                   // large_common_section_flags
+  NULL,                        // attributes_section
+  NULL                 // attributes_vendor
+};
+
+template<>
+Target::Target_info Target_powerpc<32, false>::powerpc_info =
+{
+  32,                  // size
+  false,               // is_big_endian
+  elfcpp::EM_PPC,      // machine_code
+  false,               // has_make_symbol
+  false,               // has_resolve
+  false,               // has_code_fill
+  true,                        // is_default_stack_executable
+  '\0',                        // wrap_char
+  "/usr/lib/ld.so.1",  // dynamic_linker
+  0x10000000,          // default_text_segment_address
+  64 * 1024,           // abi_pagesize (overridable by -z max-page-size)
+  4 * 1024,            // common_pagesize (overridable by -z common-page-size)
+  elfcpp::SHN_UNDEF,   // small_common_shndx
+  elfcpp::SHN_UNDEF,   // large_common_shndx
+  0,                   // small_common_section_flags
+  0,                   // large_common_section_flags
+  NULL,                        // attributes_section
+  NULL                 // attributes_vendor
+};
+
+template<>
+Target::Target_info Target_powerpc<64, true>::powerpc_info =
+{
+  64,                  // size
+  true,                        // is_big_endian
+  elfcpp::EM_PPC64,    // machine_code
+  false,               // has_make_symbol
+  false,               // has_resolve
+  false,               // has_code_fill
+  true,                        // is_default_stack_executable
+  '\0',                        // wrap_char
+  "/usr/lib/ld.so.1",  // dynamic_linker
+  0x10000000,          // default_text_segment_address
+  64 * 1024,           // abi_pagesize (overridable by -z max-page-size)
+  8 * 1024,            // common_pagesize (overridable by -z common-page-size)
+  elfcpp::SHN_UNDEF,   // small_common_shndx
+  elfcpp::SHN_UNDEF,   // large_common_shndx
+  0,                   // small_common_section_flags
+  0,                   // large_common_section_flags
+  NULL,                        // attributes_section
+  NULL                 // attributes_vendor
+};
+
+template<>
+Target::Target_info Target_powerpc<64, false>::powerpc_info =
+{
+  64,                  // size
+  false,               // is_big_endian
+  elfcpp::EM_PPC64,    // machine_code
+  false,               // has_make_symbol
+  false,               // has_resolve
+  false,               // has_code_fill
+  true,                        // is_default_stack_executable
+  '\0',                        // wrap_char
+  "/usr/lib/ld.so.1",  // dynamic_linker
+  0x10000000,          // default_text_segment_address
+  64 * 1024,           // abi_pagesize (overridable by -z max-page-size)
+  8 * 1024,            // common_pagesize (overridable by -z common-page-size)
+  elfcpp::SHN_UNDEF,   // small_common_shndx
+  elfcpp::SHN_UNDEF,   // large_common_shndx
+  0,                   // small_common_section_flags
+  0,                   // large_common_section_flags
+  NULL,                        // attributes_section
+  NULL                 // attributes_vendor
+};
+
+template<int size, bool big_endian>
+class Powerpc_relocate_functions
+{
+private:
+  // Do a simple relocation with the addend in the relocation.
+  template<int valsize>
+  static inline void
+  rela(unsigned char* view,
+       unsigned int right_shift,
+       elfcpp::Elf_Xword dst_mask,
+       typename elfcpp::Swap<size, big_endian>::Valtype value,
+       typename elfcpp::Swap<size, big_endian>::Valtype addend)
+  {
+    typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype;
+    Valtype* wv = reinterpret_cast<Valtype*>(view);
+    Valtype val = elfcpp::Swap<valsize, big_endian>::readval(wv);
+    Valtype reloc = ((value + addend) >> right_shift);
+
+    val &= ~dst_mask;
+    reloc &= dst_mask;
+
+    elfcpp::Swap<valsize, big_endian>::writeval(wv, val | reloc);
+  }
+
+  // Do a simple relocation using a symbol value with the addend in
+  // the relocation.
+  template<int valsize>
+  static inline void
+  rela(unsigned char* view,
+       unsigned int right_shift,
+       elfcpp::Elf_Xword dst_mask,
+       const Sized_relobj<size, big_endian>* object,
+       const Symbol_value<size>* psymval,
+       typename elfcpp::Swap<valsize, big_endian>::Valtype addend)
+  {
+    typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype;
+    Valtype* wv = reinterpret_cast<Valtype*>(view);
+    Valtype val = elfcpp::Swap<valsize, big_endian>::readval(wv);
+    Valtype reloc = (psymval->value(object, addend) >> right_shift);
+
+    val &= ~dst_mask;
+    reloc &= dst_mask;
+
+    elfcpp::Swap<valsize, big_endian>::writeval(wv, val | reloc);
+  }
+
+  // Do a simple relocation using a symbol value with the addend in
+  // the relocation, unaligned.
+  template<int valsize>
+  static inline void
+  rela_ua(unsigned char* view, unsigned int right_shift,
+         elfcpp::Elf_Xword dst_mask,
+         const Sized_relobj<size, big_endian>* object,
+         const Symbol_value<size>* psymval,
+         typename elfcpp::Swap<size, big_endian>::Valtype addend)
+  {
+    typedef typename elfcpp::Swap_unaligned<valsize,
+           big_endian>::Valtype Valtype;
+    unsigned char* wv = view;
+    Valtype val = elfcpp::Swap_unaligned<valsize, big_endian>::readval(wv);
+    Valtype reloc = (psymval->value(object, addend) >> right_shift);
+
+    val &= ~dst_mask;
+    reloc &= dst_mask;
+
+    elfcpp::Swap_unaligned<valsize, big_endian>::writeval(wv, val | reloc);
+  }
+
+  // Do a simple PC relative relocation with a Symbol_value with the
+  // addend in the relocation.
+  template<int valsize>
+  static inline void
+  pcrela(unsigned char* view, unsigned int right_shift,
+        elfcpp::Elf_Xword dst_mask,
+        const Sized_relobj<size, big_endian>* object,
+        const Symbol_value<size>* psymval,
+        typename elfcpp::Swap<size, big_endian>::Valtype addend,
+        typename elfcpp::Elf_types<size>::Elf_Addr address)
+  {
+    typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype;
+    Valtype* wv = reinterpret_cast<Valtype*>(view);
+    Valtype val = elfcpp::Swap<valsize, big_endian>::readval(wv);
+    Valtype reloc = ((psymval->value(object, addend) - address)
+                    >> right_shift);
+
+    val &= ~dst_mask;
+    reloc &= dst_mask;
+
+    elfcpp::Swap<valsize, big_endian>::writeval(wv, val | reloc);
+  }
+
+  template<int valsize>
+  static inline void
+  pcrela_unaligned(unsigned char* view,
+                  const Sized_relobj<size, big_endian>* object,
+                  const Symbol_value<size>* psymval,
+                  typename elfcpp::Swap<size, big_endian>::Valtype addend,
+                  typename elfcpp::Elf_types<size>::Elf_Addr address)
+  {
+    typedef typename elfcpp::Swap_unaligned<valsize,
+           big_endian>::Valtype Valtype;
+    unsigned char* wv = view;
+    Valtype reloc = (psymval->value(object, addend) - address);
+
+    elfcpp::Swap_unaligned<valsize, big_endian>::writeval(wv, reloc);
+  }
+
+  typedef Powerpc_relocate_functions<size, big_endian> This;
+  typedef Relocate_functions<size, big_endian> This_reloc;
+public:
+  // R_POWERPC_REL32: (Symbol + Addend - Address)
+  static inline void
+  rel32(unsigned char* view,
+       const Sized_relobj<size, big_endian>* object,
+       const Symbol_value<size>* psymval,
+       typename elfcpp::Elf_types<size>::Elf_Addr addend,
+       typename elfcpp::Elf_types<size>::Elf_Addr address)
+  { This_reloc::pcrela32(view, object, psymval, addend, address); }
+
+  // R_POWERPC_REL24: (Symbol + Addend - Address) & 0x3fffffc
+  static inline void
+  rel24(unsigned char* view,
+       const Sized_relobj<size, big_endian>* object,
+       const Symbol_value<size>* psymval,
+       typename elfcpp::Elf_types<size>::Elf_Addr addend,
+       typename elfcpp::Elf_types<size>::Elf_Addr address)
+  {
+    This::template pcrela<32>(view, 0, 0x03fffffc, object,
+                             psymval, addend, address);
+  }
+
+  // R_POWERPC_REL14: (Symbol + Addend - Address) & 0xfffc
+  static inline void
+  rel14(unsigned char* view,
+       const Sized_relobj<size, big_endian>* object,
+       const Symbol_value<size>* psymval,
+       typename elfcpp::Elf_types<size>::Elf_Addr addend,
+       typename elfcpp::Elf_types<size>::Elf_Addr address)
+  {
+    This::template pcrela<32>(view, 0, 0x0000fffc, object,
+                             psymval, addend, address);
+  }
+
+  // R_POWERPC_ADDR16: (Symbol + Addend) & 0xffff
+  static inline void
+  addr16(unsigned char* view,
+        typename elfcpp::Elf_types<size>::Elf_Addr value,
+        typename elfcpp::Elf_types<size>::Elf_Addr addend)
+  { This_reloc::rela16(view, value, addend); }
+
+  static inline void
+  addr16(unsigned char* view,
+        const Sized_relobj<size, big_endian>* object,
+        const Symbol_value<size>* psymval,
+        typename elfcpp::Elf_types<size>::Elf_Addr addend)
+  { This_reloc::rela16(view, object, psymval, addend); }
+
+  // R_POWERPC_ADDR16_DS: (Symbol + Addend) & 0xfffc
+  static inline void
+  addr16_ds(unsigned char* view,
+           typename elfcpp::Elf_types<size>::Elf_Addr value,
+           typename elfcpp::Elf_types<size>::Elf_Addr addend)
+  {
+    This::template rela<16>(view, 0, 0xfffc, value, addend);
+  }
+
+  // R_POWERPC_ADDR16_LO: (Symbol + Addend) & 0xffff
+  static inline void
+  addr16_lo(unsigned char* view,
+        typename elfcpp::Elf_types<size>::Elf_Addr value,
+        typename elfcpp::Elf_types<size>::Elf_Addr addend)
+  { This_reloc::rela16(view, value, addend); }
+
+  static inline void
+  addr16_lo(unsigned char* view,
+           const Sized_relobj<size, big_endian>* object,
+           const Symbol_value<size>* psymval,
+           typename elfcpp::Elf_types<size>::Elf_Addr addend)
+  { This_reloc::rela16(view, object, psymval, addend); }
+
+  // R_POWERPC_ADDR16_HI: ((Symbol + Addend) >> 16) & 0xffff
+  static inline void
+  addr16_hi(unsigned char* view,
+           typename elfcpp::Elf_types<size>::Elf_Addr value,
+           typename elfcpp::Elf_types<size>::Elf_Addr addend)
+  {
+    This::template rela<16>(view, 16, 0xffff, value, addend);
+  }
+
+  static inline void
+  addr16_hi(unsigned char* view,
+           const Sized_relobj<size, big_endian>* object,
+           const Symbol_value<size>* psymval,
+           typename elfcpp::Elf_types<size>::Elf_Addr addend)
+  {
+    This::template rela<16>(view, 16, 0xffff, object, psymval, addend);
+  }
+
+  // R_POWERPC_ADDR16_HA: Same as R_POWERPC_ADDR16_HI except that if the
+  //                      final value of the low 16 bits of the
+  //                      relocation is negative, add one.
+  static inline void
+  addr16_ha(unsigned char* view,
+           typename elfcpp::Elf_types<size>::Elf_Addr value,
+           typename elfcpp::Elf_types<size>::Elf_Addr addend)
+  {
+    typename elfcpp::Elf_types<size>::Elf_Addr reloc;
+
+    reloc = value + addend;
+
+    if (reloc & 0x8000)
+      reloc += 0x10000;
+    reloc >>= 16;
+
+    elfcpp::Swap<16, big_endian>::writeval(view, reloc);
+  }
+
+  static inline void
+  addr16_ha(unsigned char* view,
+           const Sized_relobj<size, big_endian>* object,
+           const Symbol_value<size>* psymval,
+           typename elfcpp::Elf_types<size>::Elf_Addr addend)
+  {
+    typename elfcpp::Elf_types<size>::Elf_Addr reloc;
+
+    reloc = psymval->value(object, addend);
+
+    if (reloc & 0x8000)
+      reloc += 0x10000;
+    reloc >>= 16;
+
+    elfcpp::Swap<16, big_endian>::writeval(view, reloc);
+  }
+
+  // R_PPC_REL16: (Symbol + Addend - Address) & 0xffff
+  static inline void
+  rel16(unsigned char* view,
+       const Sized_relobj<size, big_endian>* object,
+       const Symbol_value<size>* psymval,
+       typename elfcpp::Elf_types<size>::Elf_Addr addend,
+       typename elfcpp::Elf_types<size>::Elf_Addr address)
+  { This_reloc::pcrela16(view, object, psymval, addend, address); }
+
+  // R_PPC_REL16_LO: (Symbol + Addend - Address) & 0xffff
+  static inline void
+  rel16_lo(unsigned char* view,
+          const Sized_relobj<size, big_endian>* object,
+          const Symbol_value<size>* psymval,
+          typename elfcpp::Elf_types<size>::Elf_Addr addend,
+          typename elfcpp::Elf_types<size>::Elf_Addr address)
+  { This_reloc::pcrela16(view, object, psymval, addend, address); }
+
+  // R_PPC_REL16_HI: ((Symbol + Addend - Address) >> 16) & 0xffff
+  static inline void
+  rel16_hi(unsigned char* view,
+          const Sized_relobj<size, big_endian>* object,
+          const Symbol_value<size>* psymval,
+          typename elfcpp::Elf_types<size>::Elf_Addr addend,
+          typename elfcpp::Elf_types<size>::Elf_Addr address)
+  {
+    This::template pcrela<16>(view, 16, 0xffff, object,
+                             psymval, addend, address);
+  }
+
+  // R_PPC_REL16_HA: Same as R_PPC_REL16_HI except that if the
+  //                 final value of the low 16 bits of the
+  //                 relocation is negative, add one.
+  static inline void
+  rel16_ha(unsigned char* view,
+          const Sized_relobj<size, big_endian>* object,
+          const Symbol_value<size>* psymval,
+          typename elfcpp::Elf_types<size>::Elf_Addr addend,
+          typename elfcpp::Elf_types<size>::Elf_Addr address)
+  {
+    typename elfcpp::Elf_types<size>::Elf_Addr reloc;
+
+    reloc = (psymval->value(object, addend) - address);
+    if (reloc & 0x8000)
+      reloc += 0x10000;
+    reloc >>= 16;
+
+    elfcpp::Swap<16, big_endian>::writeval(view, reloc);
+  }
+};
+
+// Get the GOT section, creating it if necessary.
+
+template<int size, bool big_endian>
+Output_data_got<size, big_endian>*
+Target_powerpc<size, big_endian>::got_section(Symbol_table* symtab,
+                                             Layout* layout)
+{
+  if (this->got_ == NULL)
+    {
+      gold_assert(symtab != NULL && layout != NULL);
+
+      this->got_ = new Output_data_got<size, big_endian>();
+
+      layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
+                                     elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE,
+                                     this->got_, ORDER_DATA, false);
+
+      // Create the GOT2 or TOC in the .got section.
+      if (size == 32)
+       {
+         this->got2_ = new Output_data_space(4, "** GOT2");
+         layout->add_output_section_data(".got2", elfcpp::SHT_PROGBITS,
+                                         elfcpp::SHF_ALLOC
+                                         | elfcpp::SHF_WRITE,
+                                         this->got2_, ORDER_DATA, false);
+       }
+      else
+       {
+         this->toc_ = new Output_data_space(8, "** TOC");
+         layout->add_output_section_data(".toc", elfcpp::SHT_PROGBITS,
+                                         elfcpp::SHF_ALLOC
+                                         | elfcpp::SHF_WRITE,
+                                         this->toc_, ORDER_DATA, false);
+       }
+
+      // Define _GLOBAL_OFFSET_TABLE_ at the start of the .got section.
+      symtab->define_in_output_data("_GLOBAL_OFFSET_TABLE_", NULL,
+                                   Symbol_table::PREDEFINED,
+                                   this->got_,
+                                   0, 0, elfcpp::STT_OBJECT,
+                                   elfcpp::STB_LOCAL,
+                                   elfcpp::STV_HIDDEN, 0,
+                                   false, false);
+    }
+
+  return this->got_;
+}
+
+// Get the dynamic reloc section, creating it if necessary.
+
+template<int size, bool big_endian>
+typename Target_powerpc<size, big_endian>::Reloc_section*
+Target_powerpc<size, big_endian>::rela_dyn_section(Layout* layout)
+{
+  if (this->rela_dyn_ == NULL)
+    {
+      gold_assert(layout != NULL);
+      this->rela_dyn_ = new Reloc_section(parameters->options().combreloc());
+      layout->add_output_section_data(".rela.dyn", elfcpp::SHT_RELA,
+                                     elfcpp::SHF_ALLOC, this->rela_dyn_,
+                                     ORDER_DYNAMIC_RELOCS, false);
+    }
+  return this->rela_dyn_;
+}
+
+// A class to handle the PLT data.
+
+template<int size, bool big_endian>
+class Output_data_plt_powerpc : public Output_section_data
+{
+ public:
+  typedef Output_data_reloc<elfcpp::SHT_RELA, true,
+                           size, big_endian> Reloc_section;
+
+  Output_data_plt_powerpc(Layout*);
+
+  // Add an entry to the PLT.
+  void add_entry(Symbol* gsym);
+
+  // Return the .rela.plt section data.
+  const Reloc_section* rel_plt() const
+ {
+    return this->rel_;
+  }
+
+  // Return the number of PLT entries.
+  unsigned int
+  entry_count() const
+  { return this->count_; }
+
+  // Return the offset of the first non-reserved PLT entry.
+  static unsigned int
+  first_plt_entry_offset()
+  { return 4 * base_plt_entry_size; }
+
+  // Return the size of a PLT entry.
+  static unsigned int
+  get_plt_entry_size()
+  { return base_plt_entry_size; }
+
+ protected:
+  void do_adjust_output_section(Output_section* os);
+
+ private:
+  // The size of an entry in the PLT.
+  static const int base_plt_entry_size = (size == 32 ? 16 : 24);
+
+  // Set the final size.
+  void
+  set_final_data_size()
+  {
+    unsigned int full_count = this->count_ + 4;
+
+    this->set_data_size(full_count * base_plt_entry_size);
+  }
+
+  // Write out the PLT data.
+  void
+  do_write(Output_file*);
+
+  // The reloc section.
+  Reloc_section* rel_;
+  // The number of PLT entries.
+  unsigned int count_;
+};
+
+// Create the PLT section.  The ordinary .got section is an argument,
+// since we need to refer to the start.
+
+template<int size, bool big_endian>
+Output_data_plt_powerpc<size, big_endian>::Output_data_plt_powerpc(Layout* layout)
+  : Output_section_data(size == 32 ? 4 : 8), count_(0)
+{
+  this->rel_ = new Reloc_section(false);
+  layout->add_output_section_data(".rela.plt", elfcpp::SHT_RELA,
+                                 elfcpp::SHF_ALLOC, this->rel_,
+                                 ORDER_DYNAMIC_PLT_RELOCS, false);
+}
+
+template<int size, bool big_endian>
+void
+Output_data_plt_powerpc<size, big_endian>::do_adjust_output_section(Output_section* os)
+{
+  os->set_entsize(0);
+}
+
+// Add an entry to the PLT.
+
+template<int size, bool big_endian>
+void
+Output_data_plt_powerpc<size, big_endian>::add_entry(Symbol* gsym)
+{
+  gold_assert(!gsym->has_plt_offset());
+  unsigned int index = this->count_+ + 4;
+  section_offset_type plt_offset;
+
+  if (index < 8192)
+    plt_offset = index * base_plt_entry_size;
+  else
+    gold_unreachable();
+
+  gsym->set_plt_offset(plt_offset);
+
+  ++this->count_;
+
+  gsym->set_needs_dynsym_entry();
+  this->rel_->add_global(gsym, elfcpp::R_POWERPC_JMP_SLOT, this,
+                        plt_offset, 0);
+}
+
+static const unsigned int addis_11_11     = 0x3d6b0000;
+static const unsigned int addis_11_30     = 0x3d7e0000;
+static const unsigned int addis_12_12     = 0x3d8c0000;
+static const unsigned int addi_11_11      = 0x396b0000;
+static const unsigned int add_0_11_11     = 0x7c0b5a14;
+static const unsigned int add_11_0_11     = 0x7d605a14;
+static const unsigned int b               = 0x48000000;
+static const unsigned int bcl_20_31       = 0x429f0005;
+static const unsigned int bctr            = 0x4e800420;
+static const unsigned int lis_11          = 0x3d600000;
+static const unsigned int lis_12          = 0x3d800000;
+static const unsigned int lwzu_0_12       = 0x840c0000;
+static const unsigned int lwz_0_12        = 0x800c0000;
+static const unsigned int lwz_11_11       = 0x816b0000;
+static const unsigned int lwz_11_30       = 0x817e0000;
+static const unsigned int lwz_12_12       = 0x818c0000;
+static const unsigned int mflr_0          = 0x7c0802a6;
+static const unsigned int mflr_12         = 0x7d8802a6;
+static const unsigned int mtctr_0         = 0x7c0903a6;
+static const unsigned int mtctr_11        = 0x7d6903a6;
+static const unsigned int mtlr_0          = 0x7c0803a6;
+static const unsigned int nop             = 0x60000000;
+static const unsigned int sub_11_11_12    = 0x7d6c5850;
+
+static const unsigned int addis_r12_r2    = 0x3d820000;  /* addis %r12,%r2,xxx@ha     */
+static const unsigned int std_r2_40r1     = 0xf8410028;  /* std   %r2,40(%r1)         */
+static const unsigned int ld_r11_0r12     = 0xe96c0000;  /* ld    %r11,xxx+0@l(%r12)  */
+static const unsigned int ld_r2_0r12      = 0xe84c0000;  /* ld    %r2,xxx+8@l(%r12)   */
+                                                         /* ld    %r11,xxx+16@l(%r12) */
+
+
+// Write out the PLT.
+
+template<int size, bool big_endian>
+void
+Output_data_plt_powerpc<size, big_endian>::do_write(Output_file* of)
+{
+  const off_t offset = this->offset();
+  const section_size_type oview_size =
+    convert_to_section_size_type(this->data_size());
+  unsigned char* const oview = of->get_output_view(offset, oview_size);
+  unsigned char* pov = oview;
+
+  memset(pov, 0, base_plt_entry_size * 4);
+  pov += base_plt_entry_size * 4;
+
+  unsigned int plt_offset = base_plt_entry_size * 4;
+  const unsigned int count = this->count_;
+
+  if (size == 64)
+    {
+      for (unsigned int i = 0; i < count; i++)
+       {
+       }
+    }
+  else
+    {
+      for (unsigned int i = 0; i < count; i++)
+       {
+         elfcpp::Swap<32, true>::writeval(pov + 0x00,
+                                          lwz_11_30 + plt_offset);
+         elfcpp::Swap<32, true>::writeval(pov + 0x04, mtctr_11);
+         elfcpp::Swap<32, true>::writeval(pov + 0x08, bctr);
+         elfcpp::Swap<32, true>::writeval(pov + 0x0c, nop);
+         pov += base_plt_entry_size;
+         plt_offset += base_plt_entry_size;
+       }
+    }
+
+  gold_assert(static_cast<section_size_type>(pov - oview) == oview_size);
+
+  of->write_output_view(offset, oview_size, oview);
+}
+
+// Create a PLT entry for a global symbol.
+
+template<int size, bool big_endian>
+void
+Target_powerpc<size, big_endian>::make_plt_entry(Symbol_table* symtab,
+                                                Layout* layout,
+                                                Symbol* gsym)
+{
+  if (gsym->has_plt_offset())
+    return;
+
+  if (this->plt_ == NULL)
+    {
+      // Create the GOT section first.
+      this->got_section(symtab, layout);
+
+      // Ensure that .rela.dyn always appears before .rela.plt  This is
+      // necessary due to how, on PowerPC and some other targets, .rela.dyn
+      // needs to include .rela.plt in it's range.
+      this->rela_dyn_section(layout);
+
+      this->plt_ = new Output_data_plt_powerpc<size, big_endian>(layout);
+      layout->add_output_section_data(".plt", elfcpp::SHT_PROGBITS,
+                                     (elfcpp::SHF_ALLOC
+                                      | elfcpp::SHF_EXECINSTR
+                                      | elfcpp::SHF_WRITE),
+                                     this->plt_, ORDER_PLT, false);
+
+      // Define _PROCEDURE_LINKAGE_TABLE_ at the start of the .plt section.
+      symtab->define_in_output_data("_PROCEDURE_LINKAGE_TABLE_", NULL,
+                                   Symbol_table::PREDEFINED,
+                                   this->plt_,
+                                   0, 0, elfcpp::STT_OBJECT,
+                                   elfcpp::STB_LOCAL,
+                                   elfcpp::STV_HIDDEN, 0,
+                                   false, false);
+    }
+
+  this->plt_->add_entry(gsym);
+}
+
+// Return the number of entries in the PLT.
+
+template<int size, bool big_endian>
+unsigned int
+Target_powerpc<size, big_endian>::plt_entry_count() const
+{
+  if (this->plt_ == NULL)
+    return 0;
+  return this->plt_->entry_count();
+}
+
+// Return the offset of the first non-reserved PLT entry.
+
+template<int size, bool big_endian>
+unsigned int
+Target_powerpc<size, big_endian>::first_plt_entry_offset() const
+{
+  return Output_data_plt_powerpc<size, big_endian>::first_plt_entry_offset();
+}
+
+// Return the size of each PLT entry.
+
+template<int size, bool big_endian>
+unsigned int
+Target_powerpc<size, big_endian>::plt_entry_size() const
+{
+  return Output_data_plt_powerpc<size, big_endian>::get_plt_entry_size();
+}
+
+// Create a GOT entry for the TLS module index.
+
+template<int size, bool big_endian>
+unsigned int
+Target_powerpc<size, big_endian>::got_mod_index_entry(Symbol_table* symtab,
+                                                     Layout* layout,
+                                                     Sized_relobj<size, big_endian>* object)
+{
+  if (this->got_mod_index_offset_ == -1U)
+    {
+      gold_assert(symtab != NULL && layout != NULL && object != NULL);
+      Reloc_section* rela_dyn = this->rela_dyn_section(layout);
+      Output_data_got<size, big_endian>* got;
+      unsigned int got_offset;
+
+      got = this->got_section(symtab, layout);
+      got_offset = got->add_constant(0);
+      rela_dyn->add_local(object, 0, elfcpp::R_POWERPC_DTPMOD, got,
+                         got_offset, 0);
+      got->add_constant(0);
+      this->got_mod_index_offset_ = got_offset;
+    }
+  return this->got_mod_index_offset_;
+}
+
+// Optimize the TLS relocation type based on what we know about the
+// symbol.  IS_FINAL is true if the final address of this symbol is
+// known at link time.
+
+static tls::Tls_optimization
+optimize_tls_reloc(bool /* is_final */, int r_type)
+{
+  // If we are generating a shared library, then we can't do anything
+  // in the linker.
+  if (parameters->options().shared())
+    return tls::TLSOPT_NONE;
+  switch (r_type)
+    {
+      // XXX
+    default:
+      gold_unreachable();
+    }
+}
+
+// Report an unsupported relocation against a local symbol.
+
+template<int size, bool big_endian>
+void
+Target_powerpc<size, big_endian>::Scan::unsupported_reloc_local(
+                       Sized_relobj<size, big_endian>* object,
+                       unsigned int r_type)
+{
+  gold_error(_("%s: unsupported reloc %u against local symbol"),
+            object->name().c_str(), r_type);
+}
+
+// We are about to emit a dynamic relocation of type R_TYPE.  If the
+// dynamic linker does not support it, issue an error.
+
+template<int size, bool big_endian>
+void
+Target_powerpc<size, big_endian>::Scan::check_non_pic(Relobj* object,
+                                                     unsigned int r_type)
+{
+  gold_assert(r_type != elfcpp::R_POWERPC_NONE);
+
+  // These are the relocation types supported by glibc for both 32-bit
+  // and 64-bit powerpc.
+  switch (r_type)
+    {
+    case elfcpp::R_POWERPC_RELATIVE:
+    case elfcpp::R_POWERPC_GLOB_DAT:
+    case elfcpp::R_POWERPC_DTPMOD:
+    case elfcpp::R_POWERPC_DTPREL:
+    case elfcpp::R_POWERPC_TPREL:
+    case elfcpp::R_POWERPC_JMP_SLOT:
+    case elfcpp::R_POWERPC_COPY:
+    case elfcpp::R_POWERPC_ADDR32:
+    case elfcpp::R_POWERPC_ADDR24:
+    case elfcpp::R_POWERPC_REL24:
+      return;
+
+    default:
+      break;
+    }
+
+  if (size == 64)
+    {
+      switch (r_type)
+       {
+         // These are the relocation types supported only on 64-bit.
+       case elfcpp::R_PPC64_ADDR64:
+       case elfcpp::R_PPC64_TPREL16_LO_DS:
+       case elfcpp::R_PPC64_TPREL16_DS:
+       case elfcpp::R_POWERPC_TPREL16:
+       case elfcpp::R_POWERPC_TPREL16_LO:
+       case elfcpp::R_POWERPC_TPREL16_HI:
+       case elfcpp::R_POWERPC_TPREL16_HA:
+       case elfcpp::R_PPC64_TPREL16_HIGHER:
+       case elfcpp::R_PPC64_TPREL16_HIGHEST:
+       case elfcpp::R_PPC64_TPREL16_HIGHERA:
+       case elfcpp::R_PPC64_TPREL16_HIGHESTA:
+       case elfcpp::R_PPC64_ADDR16_LO_DS:
+       case elfcpp::R_POWERPC_ADDR16_LO:
+       case elfcpp::R_POWERPC_ADDR16_HI:
+       case elfcpp::R_POWERPC_ADDR16_HA:
+       case elfcpp::R_POWERPC_ADDR30:
+       case elfcpp::R_PPC64_UADDR64:
+       case elfcpp::R_POWERPC_UADDR32:
+       case elfcpp::R_POWERPC_ADDR16:
+       case elfcpp::R_POWERPC_UADDR16:
+       case elfcpp::R_PPC64_ADDR16_DS:
+       case elfcpp::R_PPC64_ADDR16_HIGHER:
+       case elfcpp::R_PPC64_ADDR16_HIGHEST:
+       case elfcpp::R_PPC64_ADDR16_HIGHERA:
+       case elfcpp::R_PPC64_ADDR16_HIGHESTA:
+       case elfcpp::R_POWERPC_ADDR14_BRTAKEN:
+       case elfcpp::R_POWERPC_ADDR14_BRNTAKEN:
+       case elfcpp::R_POWERPC_REL32:
+       case elfcpp::R_PPC64_REL64:
+         return;
+
+       default:
+         break;
+       }
+    }
+  else
+    {
+      switch (r_type)
+       {
+         // These are the relocation types supported only on 32-bit.
+
+       default:
+         break;
+       }
+    }
+
+  // This prevents us from issuing more than one error per reloc
+  // section.  But we can still wind up issuing more than one
+  // error per object file.
+  if (this->issued_non_pic_error_)
+    return;
+  gold_assert(parameters->options().output_is_position_independent());
+  object->error(_("requires unsupported dynamic reloc; "
+                 "recompile with -fPIC"));
+  this->issued_non_pic_error_ = true;
+  return;
+}
+
+// Scan a relocation for a local symbol.
+
+template<int size, bool big_endian>
+inline void
+Target_powerpc<size, big_endian>::Scan::local(
+                       Symbol_table* symtab,
+                       Layout* layout,
+                       Target_powerpc<size, big_endian>* target,
+                       Sized_relobj<size, big_endian>* object,
+                       unsigned int data_shndx,
+                       Output_section* output_section,
+                       const elfcpp::Rela<size, big_endian>& reloc,
+                       unsigned int r_type,
+                       const elfcpp::Sym<size, big_endian>& lsym)
+{
+  switch (r_type)
+    {
+    case elfcpp::R_POWERPC_NONE:
+    case elfcpp::R_POWERPC_GNU_VTINHERIT:
+    case elfcpp::R_POWERPC_GNU_VTENTRY:
+      break;
+
+    case elfcpp::R_PPC64_ADDR64:
+    case elfcpp::R_POWERPC_ADDR32:
+    case elfcpp::R_POWERPC_ADDR16_HA:
+    case elfcpp::R_POWERPC_ADDR16_LO:
+      // If building a shared library (or a position-independent
+      // executable), we need to create a dynamic relocation for
+      // this location.
+      if (parameters->options().output_is_position_independent())
+        {
+          Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+
+         check_non_pic(object, r_type);
+          if (lsym.get_st_type() != elfcpp::STT_SECTION)
+            {
+              unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+              rela_dyn->add_local(object, r_sym, r_type, output_section,
+                                 data_shndx, reloc.get_r_offset(),
+                                 reloc.get_r_addend());
+            }
+          else
+            {
+             unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+              gold_assert(lsym.get_st_value() == 0);
+              rela_dyn->add_local_relative(object, r_sym, r_type,
+                                          output_section, data_shndx,
+                                          reloc.get_r_offset(),
+                                          reloc.get_r_addend());
+            }
+        }
+      break;
+
+    case elfcpp::R_POWERPC_REL24:
+    case elfcpp::R_PPC_LOCAL24PC:
+    case elfcpp::R_POWERPC_REL32:
+    case elfcpp::R_PPC_REL16_LO:
+    case elfcpp::R_PPC_REL16_HA:
+      break;
+
+    case elfcpp::R_POWERPC_GOT16:
+    case elfcpp::R_POWERPC_GOT16_LO:
+    case elfcpp::R_POWERPC_GOT16_HI:
+    case elfcpp::R_POWERPC_GOT16_HA:
+    case elfcpp::R_PPC64_TOC16:
+    case elfcpp::R_PPC64_TOC16_LO:
+    case elfcpp::R_PPC64_TOC16_HI:
+    case elfcpp::R_PPC64_TOC16_HA:
+    case elfcpp::R_PPC64_TOC16_DS:
+    case elfcpp::R_PPC64_TOC16_LO_DS:
+      {
+        // The symbol requires a GOT entry.
+        Output_data_got<size, big_endian>* got;
+       unsigned int r_sym;
+
+       got = target->got_section(symtab, layout);
+       r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+
+       // If we are generating a shared object, we need to add a
+       // dynamic relocation for this symbol's GOT entry.
+       if (parameters->options().output_is_position_independent())
+         {
+           if (!object->local_has_got_offset(r_sym, GOT_TYPE_STANDARD))
+             {
+               Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+               unsigned int off;
+
+               off = got->add_constant(0);
+               object->set_local_got_offset(r_sym, GOT_TYPE_STANDARD, off);
+               rela_dyn->add_local_relative(object, r_sym,
+                                            elfcpp::R_POWERPC_RELATIVE,
+                                            got, off, 0);
+             }
+          }
+       else
+         got->add_local(object, r_sym, GOT_TYPE_STANDARD);
+      }
+      break;
+
+    case elfcpp::R_PPC64_TOC:
+      // We need a GOT section.
+      target->got_section(symtab, layout);
+      break;
+
+      // These are relocations which should only be seen by the
+      // dynamic linker, and should never be seen here.
+    case elfcpp::R_POWERPC_COPY:
+    case elfcpp::R_POWERPC_GLOB_DAT:
+    case elfcpp::R_POWERPC_JMP_SLOT:
+    case elfcpp::R_POWERPC_RELATIVE:
+    case elfcpp::R_POWERPC_DTPMOD:
+      gold_error(_("%s: unexpected reloc %u in object file"),
+                object->name().c_str(), r_type);
+      break;
+
+    default:
+      unsupported_reloc_local(object, r_type);
+      break;
+    }
+}
+
+// Report an unsupported relocation against a global symbol.
+
+template<int size, bool big_endian>
+void
+Target_powerpc<size, big_endian>::Scan::unsupported_reloc_global(
+                       Sized_relobj<size, big_endian>* object,
+                       unsigned int r_type,
+                       Symbol* gsym)
+{
+  gold_error(_("%s: unsupported reloc %u against global symbol %s"),
+            object->name().c_str(), r_type, gsym->demangled_name().c_str());
+}
+
+// Scan a relocation for a global symbol.
+
+template<int size, bool big_endian>
+inline void
+Target_powerpc<size, big_endian>::Scan::global(
+                               Symbol_table* symtab,
+                               Layout* layout,
+                               Target_powerpc<size, big_endian>* target,
+                               Sized_relobj<size, big_endian>* object,
+                               unsigned int data_shndx,
+                               Output_section* output_section,
+                               const elfcpp::Rela<size, big_endian>& reloc,
+                               unsigned int r_type,
+                               Symbol* gsym)
+{
+  switch (r_type)
+    {
+    case elfcpp::R_POWERPC_NONE:
+    case elfcpp::R_POWERPC_GNU_VTINHERIT:
+    case elfcpp::R_POWERPC_GNU_VTENTRY:
+      break;
+
+    case elfcpp::R_PPC_PLTREL24:
+      // If the symbol is fully resolved, this is just a PC32 reloc.
+      // Otherwise we need a PLT entry.
+      if (gsym->final_value_is_known())
+       break;
+      // If building a shared library, we can also skip the PLT entry
+      // if the symbol is defined in the output file and is protected
+      // or hidden.
+      if (gsym->is_defined()
+          && !gsym->is_from_dynobj()
+          && !gsym->is_preemptible())
+       break;
+      target->make_plt_entry(symtab, layout, gsym);
+      break;
+
+    case elfcpp::R_POWERPC_ADDR16:
+    case elfcpp::R_POWERPC_ADDR16_LO:
+    case elfcpp::R_POWERPC_ADDR16_HI:
+    case elfcpp::R_POWERPC_ADDR16_HA:
+    case elfcpp::R_POWERPC_ADDR32:
+    case elfcpp::R_PPC64_ADDR64:
+      {
+        // Make a PLT entry if necessary.
+        if (gsym->needs_plt_entry())
+          {
+            target->make_plt_entry(symtab, layout, gsym);
+            // Since this is not a PC-relative relocation, we may be
+            // taking the address of a function. In that case we need to
+            // set the entry in the dynamic symbol table to the address of
+            // the PLT entry.
+            if (gsym->is_from_dynobj() && !parameters->options().shared())
+              gsym->set_needs_dynsym_value();
+          }
+        // Make a dynamic relocation if necessary.
+        if (gsym->needs_dynamic_reloc(Symbol::ABSOLUTE_REF))
+          {
+            if (gsym->may_need_copy_reloc())
+              {
+               target->copy_reloc(symtab, layout, object,
+                                  data_shndx, output_section, gsym, reloc);
+              }
+            else if ((r_type == elfcpp::R_POWERPC_ADDR32
+                     || r_type == elfcpp::R_PPC64_ADDR64)
+                     && gsym->can_use_relative_reloc(false))
+              {
+                Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+                rela_dyn->add_global_relative(gsym, elfcpp::R_POWERPC_RELATIVE,
+                                             output_section, object,
+                                             data_shndx, reloc.get_r_offset(),
+                                             reloc.get_r_addend());
+              }
+            else
+              {
+                Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+
+               check_non_pic(object, r_type);
+               if (gsym->is_from_dynobj()
+                   || gsym->is_undefined()
+                   || gsym->is_preemptible())
+                 rela_dyn->add_global(gsym, r_type, output_section,
+                                      object, data_shndx,
+                                      reloc.get_r_offset(),
+                                      reloc.get_r_addend());
+               else
+                 rela_dyn->add_global_relative(gsym, r_type,
+                                               output_section, object,
+                                               data_shndx,
+                                               reloc.get_r_offset(),
+                                               reloc.get_r_addend());
+              }
+          }
+      }
+      break;
+
+    case elfcpp::R_POWERPC_REL24:
+    case elfcpp::R_PPC_LOCAL24PC:
+    case elfcpp::R_PPC_REL16:
+    case elfcpp::R_PPC_REL16_LO:
+    case elfcpp::R_PPC_REL16_HI:
+    case elfcpp::R_PPC_REL16_HA:
+      {
+       if (gsym->needs_plt_entry())
+         target->make_plt_entry(symtab, layout, gsym);
+       // Make a dynamic relocation if necessary.
+       int flags = Symbol::NON_PIC_REF;
+       if (gsym->type() == elfcpp::STT_FUNC)
+         flags |= Symbol::FUNCTION_CALL;
+       if (gsym->needs_dynamic_reloc(flags))
+         {
+           if (gsym->may_need_copy_reloc())
+             {
+               target->copy_reloc(symtab, layout, object,
+                                  data_shndx, output_section, gsym,
+                                  reloc);
+             }
+           else
+             {
+               Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+               check_non_pic(object, r_type);
+               rela_dyn->add_global(gsym, r_type, output_section, object,
+                                    data_shndx, reloc.get_r_offset(),
+                                    reloc.get_r_addend());
+             }
+         }
+      }
+      break;
+
+    case elfcpp::R_POWERPC_GOT16:
+    case elfcpp::R_POWERPC_GOT16_LO:
+    case elfcpp::R_POWERPC_GOT16_HI:
+    case elfcpp::R_POWERPC_GOT16_HA:
+    case elfcpp::R_PPC64_TOC16:
+    case elfcpp::R_PPC64_TOC16_LO:
+    case elfcpp::R_PPC64_TOC16_HI:
+    case elfcpp::R_PPC64_TOC16_HA:
+    case elfcpp::R_PPC64_TOC16_DS:
+    case elfcpp::R_PPC64_TOC16_LO_DS:
+      {
+        // The symbol requires a GOT entry.
+        Output_data_got<size, big_endian>* got;
+
+       got = target->got_section(symtab, layout);
+        if (gsym->final_value_is_known())
+          got->add_global(gsym, GOT_TYPE_STANDARD);
+        else
+          {
+            // If this symbol is not fully resolved, we need to add a
+            // dynamic relocation for it.
+            Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+            if (gsym->is_from_dynobj()
+                || gsym->is_undefined()
+                || gsym->is_preemptible())
+              got->add_global_with_rela(gsym, GOT_TYPE_STANDARD, rela_dyn,
+                                        elfcpp::R_POWERPC_GLOB_DAT);
+            else if (!gsym->has_got_offset(GOT_TYPE_STANDARD))
+              {
+               unsigned int off = got->add_constant(0);
+
+               gsym->set_got_offset(GOT_TYPE_STANDARD, off);
+               rela_dyn->add_global_relative(gsym, elfcpp::R_POWERPC_RELATIVE,
+                                             got, off, 0);
+             }
+          }
+      }
+      break;
+
+    case elfcpp::R_PPC64_TOC:
+      // We need a GOT section.
+      target->got_section(symtab, layout);
+      break;
+
+    case elfcpp::R_POWERPC_GOT_TPREL16:
+    case elfcpp::R_POWERPC_TLS:
+      // XXX TLS
+      break;
+
+      // These are relocations which should only be seen by the
+      // dynamic linker, and should never be seen here.
+    case elfcpp::R_POWERPC_COPY:
+    case elfcpp::R_POWERPC_GLOB_DAT:
+    case elfcpp::R_POWERPC_JMP_SLOT:
+    case elfcpp::R_POWERPC_RELATIVE:
+    case elfcpp::R_POWERPC_DTPMOD:
+      gold_error(_("%s: unexpected reloc %u in object file"),
+                object->name().c_str(), r_type);
+      break;
+
+    default:
+      unsupported_reloc_global(object, r_type, gsym);
+      break;
+    }
+}
+
+// Process relocations for gc.
+
+template<int size, bool big_endian>
+void
+Target_powerpc<size, big_endian>::gc_process_relocs(
+                       Symbol_table* symtab,
+                       Layout* layout,
+                       Sized_relobj<size, big_endian>* object,
+                       unsigned int data_shndx,
+                       unsigned int,
+                       const unsigned char* prelocs,
+                       size_t reloc_count,
+                       Output_section* output_section,
+                       bool needs_special_offset_handling,
+                       size_t local_symbol_count,
+                       const unsigned char* plocal_symbols)
+{
+  typedef Target_powerpc<size, big_endian> Powerpc;
+  typedef typename Target_powerpc<size, big_endian>::Scan Scan;
+
+  gold::gc_process_relocs<size, big_endian, Powerpc, elfcpp::SHT_RELA, Scan,
+                         typename Target_powerpc::Relocatable_size_for_reloc>(
+    symtab,
+    layout,
+    this,
+    object,
+    data_shndx,
+    prelocs,
+    reloc_count,
+    output_section,
+    needs_special_offset_handling,
+    local_symbol_count,
+    plocal_symbols);
+}
+
+// Scan relocations for a section.
+
+template<int size, bool big_endian>
+void
+Target_powerpc<size, big_endian>::scan_relocs(
+                       Symbol_table* symtab,
+                       Layout* layout,
+                       Sized_relobj<size, big_endian>* object,
+                       unsigned int data_shndx,
+                       unsigned int sh_type,
+                       const unsigned char* prelocs,
+                       size_t reloc_count,
+                       Output_section* output_section,
+                       bool needs_special_offset_handling,
+                       size_t local_symbol_count,
+                       const unsigned char* plocal_symbols)
+{
+  typedef Target_powerpc<size, big_endian> Powerpc;
+  typedef typename Target_powerpc<size, big_endian>::Scan Scan;
+  static Output_data_space* sdata;
+
+  if (sh_type == elfcpp::SHT_REL)
+    {
+      gold_error(_("%s: unsupported REL reloc section"),
+                object->name().c_str());
+      return;
+    }
+
+  // Define _SDA_BASE_ at the start of the .sdata section.
+  if (sdata == NULL)
+  {
+    // layout->find_output_section(".sdata") == NULL
+    sdata = new Output_data_space(4, "** sdata");
+    Output_section* os = layout->add_output_section_data(".sdata", 0,
+                                                        elfcpp::SHF_ALLOC
+                                                        | elfcpp::SHF_WRITE,
+                                                        sdata,
+                                                        ORDER_SMALL_DATA,
+                                                        false);
+    symtab->define_in_output_data("_SDA_BASE_", NULL,
+                                 Symbol_table::PREDEFINED,
+                                 os,
+                                 32768, 0,
+                                 elfcpp::STT_OBJECT,
+                                 elfcpp::STB_LOCAL,
+                                 elfcpp::STV_HIDDEN, 0,
+                                 false, false);
+  }
+
+  gold::scan_relocs<size, big_endian, Powerpc, elfcpp::SHT_RELA, Scan>(
+    symtab,
+    layout,
+    this,
+    object,
+    data_shndx,
+    prelocs,
+    reloc_count,
+    output_section,
+    needs_special_offset_handling,
+    local_symbol_count,
+    plocal_symbols);
+}
+
+// Finalize the sections.
+
+template<int size, bool big_endian>
+void
+Target_powerpc<size, big_endian>::do_finalize_sections(
+    Layout* layout,
+    const Input_objects*,
+    Symbol_table*)
+{
+  // Fill in some more dynamic tags.
+  const Reloc_section* rel_plt = (this->plt_ == NULL
+                                 ? NULL
+                                 : this->plt_->rel_plt());
+  layout->add_target_dynamic_tags(false, this->plt_, rel_plt,
+                                 this->rela_dyn_, true, size == 32);
+
+  // Emit any relocs we saved in an attempt to avoid generating COPY
+  // relocs.
+  if (this->copy_relocs_.any_saved_relocs())
+    this->copy_relocs_.emit(this->rela_dyn_section(layout));
+}
+
+// Perform a relocation.
+
+template<int size, bool big_endian>
+inline bool
+Target_powerpc<size, big_endian>::Relocate::relocate(
+                       const Relocate_info<size, big_endian>* relinfo,
+                       Target_powerpc* target,
+                       Output_section*,
+                       size_t relnum,
+                       const elfcpp::Rela<size, big_endian>& rela,
+                       unsigned int r_type,
+                       const Sized_symbol<size>* gsym,
+                       const Symbol_value<size>* psymval,
+                       unsigned char* view,
+                       typename elfcpp::Elf_types<size>::Elf_Addr address,
+                       section_size_type /* view_size */)
+{
+  const unsigned int toc_base_offset = 0x8000;
+  typedef Powerpc_relocate_functions<size, big_endian> Reloc;
+
+  // Pick the value to use for symbols defined in shared objects.
+  Symbol_value<size> symval;
+  if (gsym != NULL
+      && gsym->use_plt_offset(r_type == elfcpp::R_POWERPC_REL24
+                             || r_type == elfcpp::R_PPC_LOCAL24PC
+                             || r_type == elfcpp::R_PPC_REL16
+                             || r_type == elfcpp::R_PPC_REL16_LO
+                             || r_type == elfcpp::R_PPC_REL16_HI
+                             || r_type == elfcpp::R_PPC_REL16_HA))
+    {
+      elfcpp::Elf_Xword value;
+
+      value = target->plt_section()->address() + gsym->plt_offset();
+
+      symval.set_output_value(value);
+
+      psymval = &symval;
+    }
+
+  const Sized_relobj<size, big_endian>* object = relinfo->object;
+  elfcpp::Elf_Xword addend = rela.get_r_addend();
+
+  // Get the GOT offset if needed.  Unlike i386 and x86_64, our GOT
+  // pointer points to the beginning, not the end, of the table.
+  // So we just use the plain offset.
+  unsigned int got_offset = 0;
+  unsigned int got2_offset = 0;
+  switch (r_type)
+    {
+    case elfcpp::R_PPC64_TOC16:
+    case elfcpp::R_PPC64_TOC16_LO:
+    case elfcpp::R_PPC64_TOC16_HI:
+    case elfcpp::R_PPC64_TOC16_HA:
+    case elfcpp::R_PPC64_TOC16_DS:
+    case elfcpp::R_PPC64_TOC16_LO_DS:
+       // Subtract the TOC base address.
+       addend -= target->toc_section()->address() + toc_base_offset;
+       /* FALLTHRU */
+
+    case elfcpp::R_POWERPC_GOT16:
+    case elfcpp::R_POWERPC_GOT16_LO:
+    case elfcpp::R_POWERPC_GOT16_HI:
+    case elfcpp::R_POWERPC_GOT16_HA:
+    case elfcpp::R_PPC64_GOT16_DS:
+    case elfcpp::R_PPC64_GOT16_LO_DS:
+      if (gsym != NULL)
+        {
+          gold_assert(gsym->has_got_offset(GOT_TYPE_STANDARD));
+          got_offset = gsym->got_offset(GOT_TYPE_STANDARD);
+        }
+      else
+        {
+          unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
+          gold_assert(object->local_has_got_offset(r_sym, GOT_TYPE_STANDARD));
+          got_offset = object->local_got_offset(r_sym, GOT_TYPE_STANDARD);
+        }
+      break;
+
+      // R_PPC_PLTREL24 is rather special.  If non-zero,
+      // the addend specifies the GOT pointer offset within .got2.  
+    case elfcpp::R_PPC_PLTREL24:
+      if (addend >= 32768)
+       {
+         Output_data_space* got2;
+         got2 = target->got2_section();
+         got2_offset = got2->offset();
+         addend += got2_offset;
+       }
+      break;
+
+    default:
+      break;
+    }
+
+  switch (r_type)
+    {
+    case elfcpp::R_POWERPC_NONE:
+    case elfcpp::R_POWERPC_GNU_VTINHERIT:
+    case elfcpp::R_POWERPC_GNU_VTENTRY:
+      break;
+
+    case elfcpp::R_POWERPC_REL32:
+      Reloc::rel32(view, object, psymval, addend, address);
+      break;
+
+    case elfcpp::R_POWERPC_REL24:
+      Reloc::rel24(view, object, psymval, addend, address);
+      break;
+
+    case elfcpp::R_POWERPC_REL14:
+      Reloc::rel14(view, object, psymval, addend, address);
+      break;
+
+    case elfcpp::R_PPC_PLTREL24:
+      Reloc::rel24(view, object, psymval, addend, address);
+      break;
+
+    case elfcpp::R_PPC_LOCAL24PC:
+      Reloc::rel24(view, object, psymval, addend, address);
+      break;
+
+    case elfcpp::R_PPC64_ADDR64:
+      if (!parameters->options().output_is_position_independent())
+       Relocate_functions<size, big_endian>::rela64(view, object,
+                                                    psymval, addend);
+      break;
+
+    case elfcpp::R_POWERPC_ADDR32:
+      if (!parameters->options().output_is_position_independent())
+       Relocate_functions<size, big_endian>::rela32(view, object,
+                                                    psymval, addend);
+      break;
+
+    case elfcpp::R_POWERPC_ADDR16_LO:
+      Reloc::addr16_lo(view, object, psymval, addend);
+      break;
+
+    case elfcpp::R_POWERPC_ADDR16_HI:
+      Reloc::addr16_hi(view, object, psymval, addend);
+      break;
+
+    case elfcpp::R_POWERPC_ADDR16_HA:
+      Reloc::addr16_ha(view, object, psymval, addend);
+      break;
+
+    case elfcpp::R_PPC_REL16_LO:
+      Reloc::rel16_lo(view, object, psymval, addend, address);
+      break;
+
+    case elfcpp::R_PPC_REL16_HI:
+      Reloc::rel16_lo(view, object, psymval, addend, address);
+      break;
+
+    case elfcpp::R_PPC_REL16_HA:
+      Reloc::rel16_ha(view, object, psymval, addend, address);
+      break;
+
+    case elfcpp::R_POWERPC_GOT16:
+      Reloc::addr16(view, got_offset, addend);
+      break;
+
+    case elfcpp::R_POWERPC_GOT16_LO:
+      Reloc::addr16_lo(view, got_offset, addend);
+      break;
+
+    case elfcpp::R_POWERPC_GOT16_HI:
+      Reloc::addr16_hi(view, got_offset, addend);
+      break;
+
+    case elfcpp::R_POWERPC_GOT16_HA:
+      Reloc::addr16_ha(view, got_offset, addend);
+      break;
+
+    case elfcpp::R_PPC64_TOC16:
+      Reloc::addr16(view, got_offset, addend);
+      break;
+
+    case elfcpp::R_PPC64_TOC16_LO:
+      Reloc::addr16_lo(view, got_offset, addend);
+      break;
+
+    case elfcpp::R_PPC64_TOC16_HI:
+      Reloc::addr16_hi(view, got_offset, addend);
+      break;
+
+    case elfcpp::R_PPC64_TOC16_HA:
+      Reloc::addr16_ha(view, got_offset, addend);
+      break;
+
+    case elfcpp::R_PPC64_TOC16_DS:
+    case elfcpp::R_PPC64_TOC16_LO_DS:
+      Reloc::addr16_ds(view, got_offset, addend);
+      break;
+
+    case elfcpp::R_PPC64_TOC:
+      {
+       elfcpp::Elf_types<64>::Elf_Addr value;
+       value = target->toc_section()->address() + toc_base_offset;
+       Relocate_functions<64, false>::rela64(view, value, addend);
+      }
+      break;
+
+    case elfcpp::R_POWERPC_COPY:
+    case elfcpp::R_POWERPC_GLOB_DAT:
+    case elfcpp::R_POWERPC_JMP_SLOT:
+    case elfcpp::R_POWERPC_RELATIVE:
+      // This is an outstanding tls reloc, which is unexpected when
+      // linking.
+    case elfcpp::R_POWERPC_DTPMOD:
+      gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
+                            _("unexpected reloc %u in object file"),
+                            r_type);
+      break;
+
+    default:
+      gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
+                            _("unsupported reloc %u"),
+                            r_type);
+      break;
+    }
+
+  return true;
+}
+
+// Perform a TLS relocation.
+
+template<int size, bool big_endian>
+inline void
+Target_powerpc<size, big_endian>::Relocate::relocate_tls(
+                       const Relocate_info<size, big_endian>* relinfo,
+                       Target_powerpc<size, big_endian>* target,
+                       size_t relnum,
+                       const elfcpp::Rela<size, big_endian>& rela,
+                       unsigned int r_type,
+                       const Sized_symbol<size>* gsym,
+                       const Symbol_value<size>* psymval,
+                       unsigned char* view,
+                       typename elfcpp::Elf_types<size>::Elf_Addr address,
+                       section_size_type)
+{
+  Output_segment* tls_segment = relinfo->layout->tls_segment();
+  typedef Powerpc_relocate_functions<size, big_endian> Reloc;
+  const Sized_relobj<size, big_endian>* object = relinfo->object;
+
+  const elfcpp::Elf_Xword addend = rela.get_r_addend();
+  typename elfcpp::Elf_types<size>::Elf_Addr value = psymval->value(object, 0);
+
+  const bool is_final =
+    (gsym == NULL
+     ? !parameters->options().output_is_position_independent()
+     : gsym->final_value_is_known());
+  const tls::Tls_optimization optimized_type
+      = optimize_tls_reloc(is_final, r_type);
+
+  switch (r_type)
+    {
+      // XXX
+    }
+}
+
+// Relocate section data.
+
+template<int size, bool big_endian>
+void
+Target_powerpc<size, big_endian>::relocate_section(
+                       const Relocate_info<size, big_endian>* relinfo,
+                       unsigned int sh_type,
+                       const unsigned char* prelocs,
+                       size_t reloc_count,
+                       Output_section* output_section,
+                       bool needs_special_offset_handling,
+                       unsigned char* view,
+                       typename elfcpp::Elf_types<size>::Elf_Addr address,
+                       section_size_type view_size,
+                       const Reloc_symbol_changes* reloc_symbol_changes)
+{
+  typedef Target_powerpc<size, big_endian> Powerpc;
+  typedef typename Target_powerpc<size, big_endian>::Relocate Powerpc_relocate;
+
+  gold_assert(sh_type == elfcpp::SHT_RELA);
+
+  gold::relocate_section<size, big_endian, Powerpc, elfcpp::SHT_RELA,
+    Powerpc_relocate>(
+    relinfo,
+    this,
+    prelocs,
+    reloc_count,
+    output_section,
+    needs_special_offset_handling,
+    view,
+    address,
+    view_size,
+    reloc_symbol_changes);
+}
+
+// Return the size of a relocation while scanning during a relocatable
+// link.
+
+template<int size, bool big_endian>
+unsigned int
+Target_powerpc<size, big_endian>::Relocatable_size_for_reloc::get_size_for_reloc(
+    unsigned int,
+    Relobj*)
+{
+  // We are always SHT_RELA, so we should never get here.
+  gold_unreachable();
+  return 0;
+}
+
+// Scan the relocs during a relocatable link.
+
+template<int size, bool big_endian>
+void
+Target_powerpc<size, big_endian>::scan_relocatable_relocs(
+                       Symbol_table* symtab,
+                       Layout* layout,
+                       Sized_relobj<size, big_endian>* object,
+                       unsigned int data_shndx,
+                       unsigned int sh_type,
+                       const unsigned char* prelocs,
+                       size_t reloc_count,
+                       Output_section* output_section,
+                       bool needs_special_offset_handling,
+                       size_t local_symbol_count,
+                       const unsigned char* plocal_symbols,
+                       Relocatable_relocs* rr)
+{
+  gold_assert(sh_type == elfcpp::SHT_RELA);
+
+  typedef gold::Default_scan_relocatable_relocs<elfcpp::SHT_RELA,
+    Relocatable_size_for_reloc> Scan_relocatable_relocs;
+
+  gold::scan_relocatable_relocs<size, big_endian, elfcpp::SHT_RELA,
+      Scan_relocatable_relocs>(
+    symtab,
+    layout,
+    object,
+    data_shndx,
+    prelocs,
+    reloc_count,
+    output_section,
+    needs_special_offset_handling,
+    local_symbol_count,
+    plocal_symbols,
+    rr);
+}
+
+// Relocate a section during a relocatable link.
+
+template<int size, bool big_endian>
+void
+Target_powerpc<size, big_endian>::relocate_for_relocatable(
+    const Relocate_info<size, big_endian>* relinfo,
+    unsigned int sh_type,
+    const unsigned char* prelocs,
+    size_t reloc_count,
+    Output_section* output_section,
+    off_t offset_in_output_section,
+    const Relocatable_relocs* rr,
+    unsigned char* view,
+    typename elfcpp::Elf_types<size>::Elf_Addr view_address,
+    section_size_type view_size,
+    unsigned char* reloc_view,
+    section_size_type reloc_view_size)
+{
+  gold_assert(sh_type == elfcpp::SHT_RELA);
+
+  gold::relocate_for_relocatable<size, big_endian, elfcpp::SHT_RELA>(
+    relinfo,
+    prelocs,
+    reloc_count,
+    output_section,
+    offset_in_output_section,
+    rr,
+    view,
+    view_address,
+    view_size,
+    reloc_view,
+    reloc_view_size);
+}
+
+// Return the value to use for a dynamic which requires special
+// treatment.  This is how we support equality comparisons of function
+// pointers across shared library boundaries, as described in the
+// processor specific ABI supplement.
+
+template<int size, bool big_endian>
+uint64_t
+Target_powerpc<size, big_endian>::do_dynsym_value(const Symbol* gsym) const
+{
+  gold_assert(gsym->is_from_dynobj() && gsym->has_plt_offset());
+  return this->plt_section()->address() + gsym->plt_offset();
+}
+
+// The selector for powerpc object files.
+
+template<int size, bool big_endian>
+class Target_selector_powerpc : public Target_selector
+{
+public:
+  Target_selector_powerpc()
+    : Target_selector(elfcpp::EM_NONE, size, big_endian,
+                     (size == 64 ?
+                      (big_endian ? "elf64-powerpc" : "elf64-powerpcle") :
+                      (big_endian ? "elf32-powerpc" : "elf32-powerpcle")))
+  { }
+
+  Target* do_recognize(int machine, int, int)
+  {
+    switch (size)
+      {
+      case 64:
+       if (machine != elfcpp::EM_PPC64)
+         return NULL;
+       break;
+
+      case 32:
+       if (machine != elfcpp::EM_PPC)
+         return NULL;
+       break;
+
+      default:
+       return NULL;
+      }
+
+    return this->instantiate_target();
+  }
+
+  Target* do_instantiate_target()
+  { return new Target_powerpc<size, big_endian>(); }
+};
+
+Target_selector_powerpc<32, true> target_selector_ppc32;
+Target_selector_powerpc<32, false> target_selector_ppc32le;
+Target_selector_powerpc<64, true> target_selector_ppc64;
+Target_selector_powerpc<64, false> target_selector_ppc64le;
+
+} // End anonymous namespace.
diff --git a/contrib/binutils-2.21/gold/sparc.cc b/contrib/binutils-2.21/gold/sparc.cc
new file mode 100644 (file)
index 0000000..2f8ef7a
--- /dev/null
@@ -0,0 +1,3412 @@
+// sparc.cc -- sparc target support for gold.
+
+// Copyright 2008, 2009, 2010 Free Software Foundation, Inc.
+// Written by David S. Miller <davem@davemloft.net>.
+
+// This file is part of gold.
+
+// 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 "gold.h"
+
+#include <cstdlib>
+#include <cstdio>
+#include <cstring>
+
+#include "elfcpp.h"
+#include "parameters.h"
+#include "reloc.h"
+#include "sparc.h"
+#include "object.h"
+#include "symtab.h"
+#include "layout.h"
+#include "output.h"
+#include "copy-relocs.h"
+#include "target.h"
+#include "target-reloc.h"
+#include "target-select.h"
+#include "tls.h"
+#include "errors.h"
+#include "gc.h"
+
+namespace
+{
+
+using namespace gold;
+
+template<int size, bool big_endian>
+class Output_data_plt_sparc;
+
+template<int size, bool big_endian>
+class Target_sparc : public Sized_target<size, big_endian>
+{
+ public:
+  typedef Output_data_reloc<elfcpp::SHT_RELA, true, size, big_endian> Reloc_section;
+
+  Target_sparc()
+    : Sized_target<size, big_endian>(&sparc_info),
+      got_(NULL), plt_(NULL), rela_dyn_(NULL),
+      copy_relocs_(elfcpp::R_SPARC_COPY), dynbss_(NULL),
+      got_mod_index_offset_(-1U), tls_get_addr_sym_(NULL)
+  {
+  }
+
+  // Process the relocations to determine unreferenced sections for 
+  // garbage collection.
+  void
+  gc_process_relocs(Symbol_table* symtab,
+                   Layout* layout,
+                   Sized_relobj<size, big_endian>* object,
+                   unsigned int data_shndx,
+                   unsigned int sh_type,
+                   const unsigned char* prelocs,
+                   size_t reloc_count,
+                   Output_section* output_section,
+                   bool needs_special_offset_handling,
+                   size_t local_symbol_count,
+                   const unsigned char* plocal_symbols);
+
+  // Scan the relocations to look for symbol adjustments.
+  void
+  scan_relocs(Symbol_table* symtab,
+             Layout* layout,
+             Sized_relobj<size, big_endian>* object,
+             unsigned int data_shndx,
+             unsigned int sh_type,
+             const unsigned char* prelocs,
+             size_t reloc_count,
+             Output_section* output_section,
+             bool needs_special_offset_handling,
+             size_t local_symbol_count,
+             const unsigned char* plocal_symbols);
+  // Finalize the sections.
+  void
+  do_finalize_sections(Layout*, const Input_objects*, Symbol_table*);
+
+  // Return the value to use for a dynamic which requires special
+  // treatment.
+  uint64_t
+  do_dynsym_value(const Symbol*) const;
+
+  // Relocate a section.
+  void
+  relocate_section(const Relocate_info<size, big_endian>*,
+                  unsigned int sh_type,
+                  const unsigned char* prelocs,
+                  size_t reloc_count,
+                  Output_section* output_section,
+                  bool needs_special_offset_handling,
+                  unsigned char* view,
+                  typename elfcpp::Elf_types<size>::Elf_Addr view_address,
+                  section_size_type view_size,
+                  const Reloc_symbol_changes*);
+
+  // Scan the relocs during a relocatable link.
+  void
+  scan_relocatable_relocs(Symbol_table* symtab,
+                         Layout* layout,
+                         Sized_relobj<size, big_endian>* object,
+                         unsigned int data_shndx,
+                         unsigned int sh_type,
+                         const unsigned char* prelocs,
+                         size_t reloc_count,
+                         Output_section* output_section,
+                         bool needs_special_offset_handling,
+                         size_t local_symbol_count,
+                         const unsigned char* plocal_symbols,
+                         Relocatable_relocs*);
+
+  // Relocate a section during a relocatable link.
+  void
+  relocate_for_relocatable(const Relocate_info<size, big_endian>*,
+                          unsigned int sh_type,
+                          const unsigned char* prelocs,
+                          size_t reloc_count,
+                          Output_section* output_section,
+                          off_t offset_in_output_section,
+                          const Relocatable_relocs*,
+                          unsigned char* view,
+                          typename elfcpp::Elf_types<size>::Elf_Addr view_address,
+                          section_size_type view_size,
+                          unsigned char* reloc_view,
+                          section_size_type reloc_view_size);
+  // Return whether SYM is defined by the ABI.
+  bool
+  do_is_defined_by_abi(const Symbol* sym) const
+  {
+    // XXX Really need to support this better...
+    if (sym->type() == elfcpp::STT_SPARC_REGISTER)
+      return 1;
+
+    return strcmp(sym->name(), "___tls_get_addr") == 0;
+  }
+
+  // Return whether there is a GOT section.
+  bool
+  has_got_section() const
+  { return this->got_ != NULL; }
+
+  // Return the size of the GOT section.
+  section_size_type
+  got_size() const
+  {
+    gold_assert(this->got_ != NULL);
+    return this->got_->data_size();
+  }
+
+  // Return the number of entries in the GOT.
+  unsigned int
+  got_entry_count() const
+  {
+    if (this->got_ == NULL)
+      return 0;
+    return this->got_size() / (size / 8);
+  }
+
+  // Return the number of entries in the PLT.
+  unsigned int
+  plt_entry_count() const;
+
+  // Return the offset of the first non-reserved PLT entry.
+  unsigned int
+  first_plt_entry_offset() const;
+
+  // Return the size of each PLT entry.
+  unsigned int
+  plt_entry_size() const;
+
+ private:
+
+  // The class which scans relocations.
+  class Scan
+  {
+  public:
+    Scan()
+      : issued_non_pic_error_(false)
+    { }
+
+    inline void
+    local(Symbol_table* symtab, Layout* layout, Target_sparc* target,
+         Sized_relobj<size, big_endian>* object,
+         unsigned int data_shndx,
+         Output_section* output_section,
+         const elfcpp::Rela<size, big_endian>& reloc, unsigned int r_type,
+         const elfcpp::Sym<size, big_endian>& lsym);
+
+    inline void
+    global(Symbol_table* symtab, Layout* layout, Target_sparc* target,
+          Sized_relobj<size, big_endian>* object,
+          unsigned int data_shndx,
+          Output_section* output_section,
+          const elfcpp::Rela<size, big_endian>& reloc, unsigned int r_type,
+          Symbol* gsym);
+
+    inline bool
+    local_reloc_may_be_function_pointer(Symbol_table* , Layout* ,
+                                       Target_sparc* ,
+                                       Sized_relobj<size, big_endian>* ,
+                                               unsigned int ,
+                                       Output_section* ,
+                                       const elfcpp::Rela<size, big_endian>& ,
+                                       unsigned int ,
+                                       const elfcpp::Sym<size, big_endian>&)
+    { return false; }
+
+    inline bool
+    global_reloc_may_be_function_pointer(Symbol_table* , Layout* ,
+                                        Target_sparc* ,
+                                        Sized_relobj<size, big_endian>* ,
+                                        unsigned int ,
+                                        Output_section* ,
+                                        const elfcpp::Rela<size,
+                                                           big_endian>& ,
+                                        unsigned int , Symbol*)
+    { return false; }
+
+
+  private:
+    static void
+    unsupported_reloc_local(Sized_relobj<size, big_endian>*,
+                           unsigned int r_type);
+
+    static void
+    unsupported_reloc_global(Sized_relobj<size, big_endian>*,
+                            unsigned int r_type, Symbol*);
+
+    static void
+    generate_tls_call(Symbol_table* symtab, Layout* layout,
+                     Target_sparc* target);
+
+    void
+    check_non_pic(Relobj*, unsigned int r_type);
+
+    // Whether we have issued an error about a non-PIC compilation.
+    bool issued_non_pic_error_;
+  };
+
+  // The class which implements relocation.
+  class Relocate
+  {
+   public:
+    Relocate()
+      : ignore_gd_add_(false)
+    { }
+
+    ~Relocate()
+    {
+      if (this->ignore_gd_add_)
+       {
+         // FIXME: This needs to specify the location somehow.
+         gold_error(_("missing expected TLS relocation"));
+       }
+    }
+
+    // Do a relocation.  Return false if the caller should not issue
+    // any warnings about this relocation.
+    inline bool
+    relocate(const Relocate_info<size, big_endian>*, Target_sparc*,
+            Output_section*, size_t relnum,
+            const elfcpp::Rela<size, big_endian>&,
+            unsigned int r_type, const Sized_symbol<size>*,
+            const Symbol_value<size>*,
+            unsigned char*,
+            typename elfcpp::Elf_types<size>::Elf_Addr,
+            section_size_type);
+
+   private:
+    // Do a TLS relocation.
+    inline void
+    relocate_tls(const Relocate_info<size, big_endian>*, Target_sparc* target,
+                 size_t relnum, const elfcpp::Rela<size, big_endian>&,
+                unsigned int r_type, const Sized_symbol<size>*,
+                const Symbol_value<size>*,
+                unsigned char*,
+                typename elfcpp::Elf_types<size>::Elf_Addr,
+                section_size_type);
+
+    // Ignore the next relocation which should be R_SPARC_TLS_GD_ADD
+    bool ignore_gd_add_;
+  };
+
+  // A class which returns the size required for a relocation type,
+  // used while scanning relocs during a relocatable link.
+  class Relocatable_size_for_reloc
+  {
+   public:
+    unsigned int
+    get_size_for_reloc(unsigned int, Relobj*);
+  };
+
+  // Get the GOT section, creating it if necessary.
+  Output_data_got<size, big_endian>*
+  got_section(Symbol_table*, Layout*);
+
+  // Create a PLT entry for a global symbol.
+  void
+  make_plt_entry(Symbol_table*, Layout*, Symbol*);
+
+  // Create a GOT entry for the TLS module index.
+  unsigned int
+  got_mod_index_entry(Symbol_table* symtab, Layout* layout,
+                     Sized_relobj<size, big_endian>* object);
+
+  // Return the gsym for "__tls_get_addr".  Cache if not already
+  // cached.
+  Symbol*
+  tls_get_addr_sym(Symbol_table* symtab)
+  {
+    if (!this->tls_get_addr_sym_)
+      this->tls_get_addr_sym_ = symtab->lookup("__tls_get_addr", NULL);
+    gold_assert(this->tls_get_addr_sym_);
+    return this->tls_get_addr_sym_;
+  }
+
+  // Get the PLT section.
+  const Output_data_plt_sparc<size, big_endian>*
+  plt_section() const
+  {
+    gold_assert(this->plt_ != NULL);
+    return this->plt_;
+  }
+
+  // Get the dynamic reloc section, creating it if necessary.
+  Reloc_section*
+  rela_dyn_section(Layout*);
+
+  // Copy a relocation against a global symbol.
+  void
+  copy_reloc(Symbol_table* symtab, Layout* layout,
+             Sized_relobj<size, big_endian>* object,
+            unsigned int shndx, Output_section* output_section,
+            Symbol* sym, const elfcpp::Rela<size, big_endian>& reloc)
+  {
+    this->copy_relocs_.copy_reloc(symtab, layout,
+                                 symtab->get_sized_symbol<size>(sym),
+                                 object, shndx, output_section,
+                                 reloc, this->rela_dyn_section(layout));
+  }
+
+  // Information about this specific target which we pass to the
+  // general Target structure.
+  static Target::Target_info sparc_info;
+
+  // The types of GOT entries needed for this platform.
+  // These values are exposed to the ABI in an incremental link.
+  // Do not renumber existing values without changing the version
+  // number of the .gnu_incremental_inputs section.
+  enum Got_type
+  {
+    GOT_TYPE_STANDARD = 0,      // GOT entry for a regular symbol
+    GOT_TYPE_TLS_OFFSET = 1,    // GOT entry for TLS offset
+    GOT_TYPE_TLS_PAIR = 2,      // GOT entry for TLS module/offset pair
+  };
+
+  // The GOT section.
+  Output_data_got<size, big_endian>* got_;
+  // The PLT section.
+  Output_data_plt_sparc<size, big_endian>* plt_;
+  // The dynamic reloc section.
+  Reloc_section* rela_dyn_;
+  // Relocs saved to avoid a COPY reloc.
+  Copy_relocs<elfcpp::SHT_RELA, size, big_endian> copy_relocs_;
+  // Space for variables copied with a COPY reloc.
+  Output_data_space* dynbss_;
+  // Offset of the GOT entry for the TLS module index;
+  unsigned int got_mod_index_offset_;
+  // Cached pointer to __tls_get_addr symbol
+  Symbol* tls_get_addr_sym_;
+};
+
+template<>
+Target::Target_info Target_sparc<32, true>::sparc_info =
+{
+  32,                  // size
+  true,                        // is_big_endian
+  elfcpp::EM_SPARC,    // machine_code
+  false,               // has_make_symbol
+  false,               // has_resolve
+  false,               // has_code_fill
+  true,                        // is_default_stack_executable
+  '\0',                        // wrap_char
+  "/usr/lib/ld.so.1",  // dynamic_linker
+  0x00010000,          // default_text_segment_address
+  64 * 1024,           // abi_pagesize (overridable by -z max-page-size)
+  8 * 1024,            // common_pagesize (overridable by -z common-page-size)
+  elfcpp::SHN_UNDEF,   // small_common_shndx
+  elfcpp::SHN_UNDEF,   // large_common_shndx
+  0,                   // small_common_section_flags
+  0,                   // large_common_section_flags
+  NULL,                        // attributes_section
+  NULL                 // attributes_vendor
+};
+
+template<>
+Target::Target_info Target_sparc<64, true>::sparc_info =
+{
+  64,                  // size
+  true,                        // is_big_endian
+  elfcpp::EM_SPARCV9,  // machine_code
+  false,               // has_make_symbol
+  false,               // has_resolve
+  false,               // has_code_fill
+  true,                        // is_default_stack_executable
+  '\0',                        // wrap_char
+  "/usr/lib/sparcv9/ld.so.1",  // dynamic_linker
+  0x100000,            // default_text_segment_address
+  64 * 1024,           // abi_pagesize (overridable by -z max-page-size)
+  8 * 1024,            // common_pagesize (overridable by -z common-page-size)
+  elfcpp::SHN_UNDEF,   // small_common_shndx
+  elfcpp::SHN_UNDEF,   // large_common_shndx
+  0,                   // small_common_section_flags
+  0,                   // large_common_section_flags
+  NULL,                        // attributes_section
+  NULL                 // attributes_vendor
+};
+
+// We have to take care here, even when operating in little-endian
+// mode, sparc instructions are still big endian.
+template<int size, bool big_endian>
+class Sparc_relocate_functions
+{
+private:
+  // Do a simple relocation with the addend in the relocation.
+  template<int valsize>
+  static inline void
+  rela(unsigned char* view,
+       unsigned int right_shift,
+       typename elfcpp::Elf_types<valsize>::Elf_Addr dst_mask,
+       typename elfcpp::Swap<size, big_endian>::Valtype value,
+       typename elfcpp::Swap<size, big_endian>::Valtype addend)
+  {
+    typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype;
+    Valtype* wv = reinterpret_cast<Valtype*>(view);
+    Valtype val = elfcpp::Swap<valsize, big_endian>::readval(wv);
+    Valtype reloc = ((value + addend) >> right_shift);
+
+    val &= ~dst_mask;
+    reloc &= dst_mask;
+
+    elfcpp::Swap<valsize, big_endian>::writeval(wv, val | reloc);
+  }
+
+  // Do a simple relocation using a symbol value with the addend in
+  // the relocation.
+  template<int valsize>
+  static inline void
+  rela(unsigned char* view,
+       unsigned int right_shift,
+       typename elfcpp::Elf_types<valsize>::Elf_Addr dst_mask,
+       const Sized_relobj<size, big_endian>* object,
+       const Symbol_value<size>* psymval,
+       typename elfcpp::Swap<valsize, big_endian>::Valtype addend)
+  {
+    typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype;
+    Valtype* wv = reinterpret_cast<Valtype*>(view);
+    Valtype val = elfcpp::Swap<valsize, big_endian>::readval(wv);
+    Valtype reloc = (psymval->value(object, addend) >> right_shift);
+
+    val &= ~dst_mask;
+    reloc &= dst_mask;
+
+    elfcpp::Swap<valsize, big_endian>::writeval(wv, val | reloc);
+  }
+
+  // Do a simple relocation using a symbol value with the addend in
+  // the relocation, unaligned.
+  template<int valsize>
+  static inline void
+  rela_ua(unsigned char* view,
+         unsigned int right_shift, elfcpp::Elf_Xword dst_mask,
+         const Sized_relobj<size, big_endian>* object,
+         const Symbol_value<size>* psymval,
+         typename elfcpp::Swap<size, big_endian>::Valtype addend)
+  {
+    typedef typename elfcpp::Swap_unaligned<valsize,
+           big_endian>::Valtype Valtype;
+    unsigned char* wv = view;
+    Valtype val = elfcpp::Swap_unaligned<valsize, big_endian>::readval(wv);
+    Valtype reloc = (psymval->value(object, addend) >> right_shift);
+
+    val &= ~dst_mask;
+    reloc &= dst_mask;
+
+    elfcpp::Swap_unaligned<valsize, big_endian>::writeval(wv, val | reloc);
+  }
+
+  // Do a simple PC relative relocation with a Symbol_value with the
+  // addend in the relocation.
+  template<int valsize>
+  static inline void
+  pcrela(unsigned char* view,
+        unsigned int right_shift,
+        typename elfcpp::Elf_types<valsize>::Elf_Addr dst_mask,
+        const Sized_relobj<size, big_endian>* object,
+        const Symbol_value<size>* psymval,
+        typename elfcpp::Swap<size, big_endian>::Valtype addend,
+        typename elfcpp::Elf_types<size>::Elf_Addr address)
+  {
+    typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype;
+    Valtype* wv = reinterpret_cast<Valtype*>(view);
+    Valtype val = elfcpp::Swap<valsize, big_endian>::readval(wv);
+    Valtype reloc = ((psymval->value(object, addend) - address)
+                    >> right_shift);
+
+    val &= ~dst_mask;
+    reloc &= dst_mask;
+
+    elfcpp::Swap<valsize, big_endian>::writeval(wv, val | reloc);
+  }
+
+  template<int valsize>
+  static inline void
+  pcrela_unaligned(unsigned char* view,
+                  const Sized_relobj<size, big_endian>* object,
+                  const Symbol_value<size>* psymval,
+                  typename elfcpp::Swap<size, big_endian>::Valtype addend,
+                  typename elfcpp::Elf_types<size>::Elf_Addr address)
+  {
+    typedef typename elfcpp::Swap_unaligned<valsize,
+           big_endian>::Valtype Valtype;
+    unsigned char* wv = view;
+    Valtype reloc = (psymval->value(object, addend) - address);
+
+    elfcpp::Swap_unaligned<valsize, big_endian>::writeval(wv, reloc);
+  }
+
+  typedef Sparc_relocate_functions<size, big_endian> This;
+  typedef Sparc_relocate_functions<size, true> This_insn;
+
+public:
+  // R_SPARC_WDISP30: (Symbol + Addend - Address) >> 2
+  static inline void
+  wdisp30(unsigned char* view,
+          const Sized_relobj<size, big_endian>* object,
+          const Symbol_value<size>* psymval,
+          typename elfcpp::Elf_types<size>::Elf_Addr addend,
+          typename elfcpp::Elf_types<size>::Elf_Addr address)
+  {
+    This_insn::template pcrela<32>(view, 2, 0x3fffffff, object,
+                                  psymval, addend, address);
+  }
+
+  // R_SPARC_WDISP22: (Symbol + Addend - Address) >> 2
+  static inline void
+  wdisp22(unsigned char* view,
+          const Sized_relobj<size, big_endian>* object,
+          const Symbol_value<size>* psymval,
+          typename elfcpp::Elf_types<size>::Elf_Addr addend,
+          typename elfcpp::Elf_types<size>::Elf_Addr address)
+  {
+    This_insn::template pcrela<32>(view, 2, 0x003fffff, object,
+                                  psymval, addend, address);
+  }
+
+  // R_SPARC_WDISP19: (Symbol + Addend - Address) >> 2
+  static inline void
+  wdisp19(unsigned char* view,
+         const Sized_relobj<size, big_endian>* object,
+         const Symbol_value<size>* psymval,
+         typename elfcpp::Elf_types<size>::Elf_Addr addend,
+         typename elfcpp::Elf_types<size>::Elf_Addr address)
+  {
+    This_insn::template pcrela<32>(view, 2, 0x0007ffff, object,
+                                  psymval, addend, address);
+  }
+
+  // R_SPARC_WDISP16: (Symbol + Addend - Address) >> 2
+  static inline void
+  wdisp16(unsigned char* view,
+         const Sized_relobj<size, big_endian>* object,
+         const Symbol_value<size>* psymval,
+         typename elfcpp::Elf_types<size>::Elf_Addr addend,
+         typename elfcpp::Elf_types<size>::Elf_Addr address)
+  {
+    typedef typename elfcpp::Swap<32, true>::Valtype Valtype;
+    Valtype* wv = reinterpret_cast<Valtype*>(view);
+    Valtype val = elfcpp::Swap<32, true>::readval(wv);
+    Valtype reloc = ((psymval->value(object, addend) - address)
+                    >> 2);
+
+    // The relocation value is split between the low 14 bits,
+    // and bits 20-21.
+    val &= ~((0x3 << 20) | 0x3fff);
+    reloc = (((reloc & 0xc000) << (20 - 14))
+            | (reloc & 0x3ffff));
+
+    elfcpp::Swap<32, true>::writeval(wv, val | reloc);
+  }
+
+  // R_SPARC_PC22: (Symbol + Addend - Address) >> 10
+  static inline void
+  pc22(unsigned char* view,
+       const Sized_relobj<size, big_endian>* object,
+       const Symbol_value<size>* psymval,
+       typename elfcpp::Elf_types<size>::Elf_Addr addend,
+       typename elfcpp::Elf_types<size>::Elf_Addr address)
+  {
+    This_insn::template pcrela<32>(view, 10, 0x003fffff, object,
+                                  psymval, addend, address);
+  }
+
+  // R_SPARC_PC10: (Symbol + Addend - Address) & 0x3ff
+  static inline void
+  pc10(unsigned char* view,
+       const Sized_relobj<size, big_endian>* object,
+       const Symbol_value<size>* psymval,
+       typename elfcpp::Elf_types<size>::Elf_Addr addend,
+       typename elfcpp::Elf_types<size>::Elf_Addr address)
+  {
+    This_insn::template pcrela<32>(view, 0, 0x000003ff, object,
+                                  psymval, addend, address);
+  }
+
+  // R_SPARC_HI22: (Symbol + Addend) >> 10
+  static inline void
+  hi22(unsigned char* view,
+       typename elfcpp::Elf_types<size>::Elf_Addr value,
+       typename elfcpp::Elf_types<size>::Elf_Addr addend)
+  {
+    This_insn::template rela<32>(view, 10, 0x003fffff, value, addend);
+  }
+
+  // R_SPARC_HI22: (Symbol + Addend) >> 10
+  static inline void
+  hi22(unsigned char* view,
+       const Sized_relobj<size, big_endian>* object,
+       const Symbol_value<size>* psymval,
+       typename elfcpp::Elf_types<size>::Elf_Addr addend)
+  {
+    This_insn::template rela<32>(view, 10, 0x003fffff, object, psymval, addend);
+  }
+
+  // R_SPARC_PCPLT22: (Symbol + Addend - Address) >> 10
+  static inline void
+  pcplt22(unsigned char* view,
+         const Sized_relobj<size, big_endian>* object,
+         const Symbol_value<size>* psymval,
+         typename elfcpp::Elf_types<size>::Elf_Addr addend,
+         typename elfcpp::Elf_types<size>::Elf_Addr address)
+  {
+    This_insn::template pcrela<32>(view, 10, 0x003fffff, object,
+                                  psymval, addend, address);
+  }
+
+  // R_SPARC_LO10: (Symbol + Addend) & 0x3ff
+  static inline void
+  lo10(unsigned char* view,
+       typename elfcpp::Elf_types<size>::Elf_Addr value,
+       typename elfcpp::Elf_types<size>::Elf_Addr addend)
+  {
+    This_insn::template rela<32>(view, 0, 0x000003ff, value, addend);
+  }
+
+  // R_SPARC_LO10: (Symbol + Addend) & 0x3ff
+  static inline void
+  lo10(unsigned char* view,
+       const Sized_relobj<size, big_endian>* object,
+       const Symbol_value<size>* psymval,
+       typename elfcpp::Elf_types<size>::Elf_Addr addend)
+  {
+    This_insn::template rela<32>(view, 0, 0x000003ff, object, psymval, addend);
+  }
+
+  // R_SPARC_LO10: (Symbol + Addend) & 0x3ff
+  static inline void
+  lo10(unsigned char* view,
+       const Sized_relobj<size, big_endian>* object,
+       const Symbol_value<size>* psymval,
+       typename elfcpp::Elf_types<size>::Elf_Addr addend,
+       typename elfcpp::Elf_types<size>::Elf_Addr address)
+  {
+    This_insn::template pcrela<32>(view, 0, 0x000003ff, object,
+                                  psymval, addend, address);
+  }
+
+  // R_SPARC_OLO10: ((Symbol + Addend) & 0x3ff) + Addend2
+  static inline void
+  olo10(unsigned char* view,
+       const Sized_relobj<size, big_endian>* object,
+       const Symbol_value<size>* psymval,
+       typename elfcpp::Elf_types<size>::Elf_Addr addend,
+       typename elfcpp::Elf_types<size>::Elf_Addr addend2)
+  {
+    typedef typename elfcpp::Swap<32, true>::Valtype Valtype;
+    Valtype* wv = reinterpret_cast<Valtype*>(view);
+    Valtype val = elfcpp::Swap<32, true>::readval(wv);
+    Valtype reloc = psymval->value(object, addend);
+
+    val &= ~0x1fff;
+    reloc &= 0x3ff;
+    reloc += addend2;
+    reloc &= 0x1fff;
+
+    elfcpp::Swap<32, true>::writeval(wv, val | reloc);
+  }
+
+  // R_SPARC_22: (Symbol + Addend)
+  static inline void
+  rela32_22(unsigned char* view,
+           const Sized_relobj<size, big_endian>* object,
+           const Symbol_value<size>* psymval,
+           typename elfcpp::Elf_types<size>::Elf_Addr addend)
+  {
+    This_insn::template rela<32>(view, 0, 0x003fffff, object, psymval, addend);
+  }
+
+  // R_SPARC_13: (Symbol + Addend)
+  static inline void
+  rela32_13(unsigned char* view,
+           typename elfcpp::Elf_types<size>::Elf_Addr value,
+           typename elfcpp::Elf_types<size>::Elf_Addr addend)
+  {
+    This_insn::template rela<32>(view, 0, 0x00001fff, value, addend);
+  }
+
+  // R_SPARC_13: (Symbol + Addend)
+  static inline void
+  rela32_13(unsigned char* view,
+           const Sized_relobj<size, big_endian>* object,
+           const Symbol_value<size>* psymval,
+           typename elfcpp::Elf_types<size>::Elf_Addr addend)
+  {
+    This_insn::template rela<32>(view, 0, 0x00001fff, object, psymval, addend);
+  }
+
+  // R_SPARC_UA16: (Symbol + Addend)
+  static inline void
+  ua16(unsigned char* view,
+       const Sized_relobj<size, big_endian>* object,
+       const Symbol_value<size>* psymval,
+       typename elfcpp::Elf_types<size>::Elf_Addr addend)
+  {
+    This::template rela_ua<16>(view, 0, 0xffff, object, psymval, addend);
+  }
+
+  // R_SPARC_UA32: (Symbol + Addend)
+  static inline void
+  ua32(unsigned char* view,
+       const Sized_relobj<size, big_endian>* object,
+       const Symbol_value<size>* psymval,
+       typename elfcpp::Elf_types<size>::Elf_Addr addend)
+  {
+    This::template rela_ua<32>(view, 0, 0xffffffff, object, psymval, addend);
+  }
+
+  // R_SPARC_UA64: (Symbol + Addend)
+  static inline void
+  ua64(unsigned char* view,
+       const Sized_relobj<size, big_endian>* object,
+       const Symbol_value<size>* psymval,
+       typename elfcpp::Elf_types<size>::Elf_Addr addend)
+  {
+    This::template rela_ua<64>(view, 0, ~(elfcpp::Elf_Xword) 0,
+                              object, psymval, addend);
+  }
+
+  // R_SPARC_DISP8: (Symbol + Addend - Address)
+  static inline void
+  disp8(unsigned char* view,
+       const Sized_relobj<size, big_endian>* object,
+       const Symbol_value<size>* psymval,
+       typename elfcpp::Elf_types<size>::Elf_Addr addend,
+       typename elfcpp::Elf_types<size>::Elf_Addr address)
+  {
+    This::template pcrela_unaligned<8>(view, object, psymval,
+                                      addend, address);
+  }
+
+  // R_SPARC_DISP16: (Symbol + Addend - Address)
+  static inline void
+  disp16(unsigned char* view,
+        const Sized_relobj<size, big_endian>* object,
+        const Symbol_value<size>* psymval,
+        typename elfcpp::Elf_types<size>::Elf_Addr addend,
+        typename elfcpp::Elf_types<size>::Elf_Addr address)
+  {
+    This::template pcrela_unaligned<16>(view, object, psymval,
+                                       addend, address);
+  }
+
+  // R_SPARC_DISP32: (Symbol + Addend - Address)
+  static inline void
+  disp32(unsigned char* view,
+        const Sized_relobj<size, big_endian>* object,
+        const Symbol_value<size>* psymval,
+        typename elfcpp::Elf_types<size>::Elf_Addr addend,
+        typename elfcpp::Elf_types<size>::Elf_Addr address)
+  {
+    This::template pcrela_unaligned<32>(view, object, psymval,
+                                       addend, address);
+  }
+
+  // R_SPARC_DISP64: (Symbol + Addend - Address)
+  static inline void
+  disp64(unsigned char* view,
+        const Sized_relobj<size, big_endian>* object,
+        const Symbol_value<size>* psymval,
+        elfcpp::Elf_Xword addend,
+        typename elfcpp::Elf_types<size>::Elf_Addr address)
+  {
+    This::template pcrela_unaligned<64>(view, object, psymval,
+                                       addend, address);
+  }
+
+  // R_SPARC_H44: (Symbol + Addend) >> 22
+  static inline void
+  h44(unsigned char* view,
+      const Sized_relobj<size, big_endian>* object,
+      const Symbol_value<size>* psymval,
+      typename elfcpp::Elf_types<size>::Elf_Addr  addend)
+  {
+    This_insn::template rela<32>(view, 22, 0x003fffff, object, psymval, addend);
+  }
+
+  // R_SPARC_M44: ((Symbol + Addend) >> 12) & 0x3ff
+  static inline void
+  m44(unsigned char* view,
+      const Sized_relobj<size, big_endian>* object,
+      const Symbol_value<size>* psymval,
+      typename elfcpp::Elf_types<size>::Elf_Addr  addend)
+  {
+    This_insn::template rela<32>(view, 12, 0x000003ff, object, psymval, addend);
+  }
+
+  // R_SPARC_L44: (Symbol + Addend) & 0xfff
+  static inline void
+  l44(unsigned char* view,
+      const Sized_relobj<size, big_endian>* object,
+      const Symbol_value<size>* psymval,
+      typename elfcpp::Elf_types<size>::Elf_Addr  addend)
+  {
+    This_insn::template rela<32>(view, 0, 0x00000fff, object, psymval, addend);
+  }
+
+  // R_SPARC_HH22: (Symbol + Addend) >> 42
+  static inline void
+  hh22(unsigned char* view,
+       const Sized_relobj<size, big_endian>* object,
+       const Symbol_value<size>* psymval,
+       typename elfcpp::Elf_types<size>::Elf_Addr addend)
+  {
+    This_insn::template rela<32>(view, 42, 0x003fffff, object, psymval, addend);
+  }
+
+  // R_SPARC_PC_HH22: (Symbol + Addend - Address) >> 42
+  static inline void
+  pc_hh22(unsigned char* view,
+         const Sized_relobj<size, big_endian>* object,
+         const Symbol_value<size>* psymval,
+         typename elfcpp::Elf_types<size>::Elf_Addr addend,
+         typename elfcpp::Elf_types<size>::Elf_Addr address)
+  {
+    This_insn::template pcrela<32>(view, 42, 0x003fffff, object,
+                                  psymval, addend, address);
+  }
+
+  // R_SPARC_HM10: ((Symbol + Addend) >> 32) & 0x3ff
+  static inline void
+  hm10(unsigned char* view,
+       const Sized_relobj<size, big_endian>* object,
+       const Symbol_value<size>* psymval,
+       typename elfcpp::Elf_types<size>::Elf_Addr addend)
+  {
+    This_insn::template rela<32>(view, 32, 0x000003ff, object, psymval, addend);
+  }
+
+  // R_SPARC_PC_HM10: ((Symbol + Addend - Address) >> 32) & 0x3ff
+  static inline void
+  pc_hm10(unsigned char* view,
+         const Sized_relobj<size, big_endian>* object,
+         const Symbol_value<size>* psymval,
+         typename elfcpp::Elf_types<size>::Elf_Addr addend,
+         typename elfcpp::Elf_types<size>::Elf_Addr address)
+  {
+    This_insn::template pcrela<32>(view, 32, 0x000003ff, object,
+                                  psymval, addend, address);
+  }
+
+  // R_SPARC_11: (Symbol + Addend)
+  static inline void
+  rela32_11(unsigned char* view,
+           const Sized_relobj<size, big_endian>* object,
+           const Symbol_value<size>* psymval,
+           typename elfcpp::Elf_types<size>::Elf_Addr addend)
+  {
+    This_insn::template rela<32>(view, 0, 0x000007ff, object, psymval, addend);
+  }
+
+  // R_SPARC_10: (Symbol + Addend)
+  static inline void
+  rela32_10(unsigned char* view,
+           const Sized_relobj<size, big_endian>* object,
+           const Symbol_value<size>* psymval,
+           typename elfcpp::Elf_types<size>::Elf_Addr addend)
+  {
+    This_insn::template rela<32>(view, 0, 0x000003ff, object, psymval, addend);
+  }
+
+  // R_SPARC_7: (Symbol + Addend)
+  static inline void
+  rela32_7(unsigned char* view,
+          const Sized_relobj<size, big_endian>* object,
+          const Symbol_value<size>* psymval,
+          typename elfcpp::Elf_types<size>::Elf_Addr addend)
+  {
+    This_insn::template rela<32>(view, 0, 0x0000007f, object, psymval, addend);
+  }
+
+  // R_SPARC_6: (Symbol + Addend)
+  static inline void
+  rela32_6(unsigned char* view,
+          const Sized_relobj<size, big_endian>* object,
+          const Symbol_value<size>* psymval,
+          typename elfcpp::Elf_types<size>::Elf_Addr addend)
+  {
+    This_insn::template rela<32>(view, 0, 0x0000003f, object, psymval, addend);
+  }
+
+  // R_SPARC_5: (Symbol + Addend)
+  static inline void
+  rela32_5(unsigned char* view,
+          const Sized_relobj<size, big_endian>* object,
+          const Symbol_value<size>* psymval,
+          typename elfcpp::Elf_types<size>::Elf_Addr addend)
+  {
+    This_insn::template rela<32>(view, 0, 0x0000001f, object, psymval, addend);
+  }
+
+  // R_SPARC_TLS_LDO_HIX22: @dtpoff(Symbol + Addend) >> 10
+  static inline void
+  ldo_hix22(unsigned char* view,
+           typename elfcpp::Elf_types<size>::Elf_Addr value,
+           typename elfcpp::Elf_types<size>::Elf_Addr addend)
+  {
+    This_insn::hi22(view, value, addend);
+  }
+
+  // R_SPARC_TLS_LDO_LOX10: @dtpoff(Symbol + Addend) & 0x3ff
+  static inline void
+  ldo_lox10(unsigned char* view,
+           typename elfcpp::Elf_types<size>::Elf_Addr value,
+           typename elfcpp::Elf_types<size>::Elf_Addr addend)
+  {
+    typedef typename elfcpp::Swap<32, true>::Valtype Valtype;
+    Valtype* wv = reinterpret_cast<Valtype*>(view);
+    Valtype val = elfcpp::Swap<32, true>::readval(wv);
+    Valtype reloc = (value + addend);
+
+    val &= ~0x1fff;
+    reloc &= 0x3ff;
+
+    elfcpp::Swap<32, true>::writeval(wv, val | reloc);
+  }
+
+  // R_SPARC_TLS_LE_HIX22: (@tpoff(Symbol + Addend) ^ 0xffffffffffffffff) >> 10
+  static inline void
+  hix22(unsigned char* view,
+       typename elfcpp::Elf_types<size>::Elf_Addr value,
+       typename elfcpp::Elf_types<size>::Elf_Addr addend)
+  {
+    typedef typename elfcpp::Swap<32, true>::Valtype Valtype;
+    Valtype* wv = reinterpret_cast<Valtype*>(view);
+    Valtype val = elfcpp::Swap<32, true>::readval(wv);
+    Valtype reloc = (value + addend);
+
+    val &= ~0x3fffff;
+
+    reloc ^= ~(Valtype)0;
+    reloc >>= 10;
+
+    reloc &= 0x3fffff;
+
+    elfcpp::Swap<32, true>::writeval(wv, val | reloc);
+  }
+
+  // R_SPARC_HIX22: ((Symbol + Addend) ^ 0xffffffffffffffff) >> 10
+  static inline void
+  hix22(unsigned char* view,
+       const Sized_relobj<size, big_endian>* object,
+       const Symbol_value<size>* psymval,
+       typename elfcpp::Elf_types<size>::Elf_Addr addend)
+  {
+    typedef typename elfcpp::Swap<32, true>::Valtype Valtype;
+    Valtype* wv = reinterpret_cast<Valtype*>(view);
+    Valtype val = elfcpp::Swap<32, true>::readval(wv);
+    Valtype reloc = psymval->value(object, addend);
+
+    val &= ~0x3fffff;
+
+    reloc ^= ~(Valtype)0;
+    reloc >>= 10;
+
+    reloc &= 0x3fffff;
+
+    elfcpp::Swap<32, true>::writeval(wv, val | reloc);
+  }
+
+
+  // R_SPARC_TLS_LE_LOX10: (@tpoff(Symbol + Addend) & 0x3ff) | 0x1c00
+  static inline void
+  lox10(unsigned char* view,
+       typename elfcpp::Elf_types<size>::Elf_Addr value,
+       typename elfcpp::Elf_types<size>::Elf_Addr addend)
+  {
+    typedef typename elfcpp::Swap<32, true>::Valtype Valtype;
+    Valtype* wv = reinterpret_cast<Valtype*>(view);
+    Valtype val = elfcpp::Swap<32, true>::readval(wv);
+    Valtype reloc = (value + addend);
+
+    val &= ~0x1fff;
+    reloc &= 0x3ff;
+    reloc |= 0x1c00;
+
+    elfcpp::Swap<32, true>::writeval(wv, val | reloc);
+  }
+
+  // R_SPARC_LOX10: ((Symbol + Addend) & 0x3ff) | 0x1c00
+  static inline void
+  lox10(unsigned char* view,
+       const Sized_relobj<size, big_endian>* object,
+       const Symbol_value<size>* psymval,
+       typename elfcpp::Elf_types<size>::Elf_Addr addend)
+  {
+    typedef typename elfcpp::Swap<32, true>::Valtype Valtype;
+    Valtype* wv = reinterpret_cast<Valtype*>(view);
+    Valtype val = elfcpp::Swap<32, true>::readval(wv);
+    Valtype reloc = psymval->value(object, addend);
+
+    val &= ~0x1fff;
+    reloc &= 0x3ff;
+    reloc |= 0x1c00;
+
+    elfcpp::Swap<32, true>::writeval(wv, val | reloc);
+  }
+};
+
+// Get the GOT section, creating it if necessary.
+
+template<int size, bool big_endian>
+Output_data_got<size, big_endian>*
+Target_sparc<size, big_endian>::got_section(Symbol_table* symtab,
+                                           Layout* layout)
+{
+  if (this->got_ == NULL)
+    {
+      gold_assert(symtab != NULL && layout != NULL);
+
+      this->got_ = new Output_data_got<size, big_endian>();
+
+      layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
+                                     (elfcpp::SHF_ALLOC
+                                      | elfcpp::SHF_WRITE),
+                                     this->got_, ORDER_RELRO, true);
+
+      // Define _GLOBAL_OFFSET_TABLE_ at the start of the .got section.
+      symtab->define_in_output_data("_GLOBAL_OFFSET_TABLE_", NULL,
+                                   Symbol_table::PREDEFINED,
+                                   this->got_,
+                                   0, 0, elfcpp::STT_OBJECT,
+                                   elfcpp::STB_LOCAL,
+                                   elfcpp::STV_HIDDEN, 0,
+                                   false, false);
+    }
+
+  return this->got_;
+}
+
+// Get the dynamic reloc section, creating it if necessary.
+
+template<int size, bool big_endian>
+typename Target_sparc<size, big_endian>::Reloc_section*
+Target_sparc<size, big_endian>::rela_dyn_section(Layout* layout)
+{
+  if (this->rela_dyn_ == NULL)
+    {
+      gold_assert(layout != NULL);
+      this->rela_dyn_ = new Reloc_section(parameters->options().combreloc());
+      layout->add_output_section_data(".rela.dyn", elfcpp::SHT_RELA,
+                                     elfcpp::SHF_ALLOC, this->rela_dyn_,
+                                     ORDER_DYNAMIC_RELOCS, false);
+    }
+  return this->rela_dyn_;
+}
+
+// A class to handle the PLT data.
+
+template<int size, bool big_endian>
+class Output_data_plt_sparc : public Output_section_data
+{
+ public:
+  typedef Output_data_reloc<elfcpp::SHT_RELA, true,
+                           size, big_endian> Reloc_section;
+
+  Output_data_plt_sparc(Layout*);
+
+  // Add an entry to the PLT.
+  void add_entry(Symbol* gsym);
+
+  // Return the .rela.plt section data.
+  const Reloc_section* rel_plt() const
+  {
+    return this->rel_;
+  }
+
+  // Return the number of PLT entries.
+  unsigned int
+  entry_count() const
+  { return this->count_; }
+
+  // Return the offset of the first non-reserved PLT entry.
+  static unsigned int
+  first_plt_entry_offset()
+  { return 4 * base_plt_entry_size; }
+
+  // Return the size of a PLT entry.
+  static unsigned int
+  get_plt_entry_size()
+  { return base_plt_entry_size; }
+
+ protected:
+  void do_adjust_output_section(Output_section* os);
+
+  // Write to a map file.
+  void
+  do_print_to_mapfile(Mapfile* mapfile) const
+  { mapfile->print_output_data(this, _("** PLT")); }
+
+ private:
+  // The size of an entry in the PLT.
+  static const int base_plt_entry_size = (size == 32 ? 12 : 32);
+
+  static const unsigned int plt_entries_per_block = 160;
+  static const unsigned int plt_insn_chunk_size = 24;
+  static const unsigned int plt_pointer_chunk_size = 8;
+  static const unsigned int plt_block_size =
+    (plt_entries_per_block
+     * (plt_insn_chunk_size + plt_pointer_chunk_size));
+
+  // Set the final size.
+  void
+  set_final_data_size()
+  {
+    unsigned int full_count = this->count_ + 4;
+    unsigned int extra = (size == 32 ? 4 : 0);
+
+    if (size == 32 || full_count < 32768)
+      this->set_data_size((full_count * base_plt_entry_size) + extra);
+    else
+      {
+       unsigned int ext_cnt = full_count - 32768;
+
+       this->set_data_size((32768 * base_plt_entry_size)
+                           + (ext_cnt
+                              * (plt_insn_chunk_size
+                                 + plt_pointer_chunk_size)));
+      }
+  }
+
+  // Write out the PLT data.
+  void
+  do_write(Output_file*);
+
+  // The reloc section.
+  Reloc_section* rel_;
+  // The number of PLT entries.
+  unsigned int count_;
+};
+
+// Define the constants as required by C++ standard.
+
+template<int size, bool big_endian>
+const int Output_data_plt_sparc<size, big_endian>::base_plt_entry_size;
+
+template<int size, bool big_endian>
+const unsigned int
+Output_data_plt_sparc<size, big_endian>::plt_entries_per_block;
+
+template<int size, bool big_endian>
+const unsigned int Output_data_plt_sparc<size, big_endian>::plt_insn_chunk_size;
+
+template<int size, bool big_endian>
+const unsigned int
+Output_data_plt_sparc<size, big_endian>::plt_pointer_chunk_size;
+
+template<int size, bool big_endian>
+const unsigned int Output_data_plt_sparc<size, big_endian>::plt_block_size;
+
+// Create the PLT section.  The ordinary .got section is an argument,
+// since we need to refer to the start.
+
+template<int size, bool big_endian>
+Output_data_plt_sparc<size, big_endian>::Output_data_plt_sparc(Layout* layout)
+  : Output_section_data(size == 32 ? 4 : 8), count_(0)
+{
+  this->rel_ = new Reloc_section(false);
+  layout->add_output_section_data(".rela.plt", elfcpp::SHT_RELA,
+                                 elfcpp::SHF_ALLOC, this->rel_,
+                                 ORDER_DYNAMIC_PLT_RELOCS, false);
+}
+
+template<int size, bool big_endian>
+void
+Output_data_plt_sparc<size, big_endian>::do_adjust_output_section(Output_section* os)
+{
+  os->set_entsize(0);
+}
+
+// Add an entry to the PLT.
+
+template<int size, bool big_endian>
+void
+Output_data_plt_sparc<size, big_endian>::add_entry(Symbol* gsym)
+{
+  gold_assert(!gsym->has_plt_offset());
+
+  unsigned int index = this->count_ + 4;
+  section_offset_type plt_offset;
+
+  if (size == 32 || index < 32768)
+    plt_offset = index * base_plt_entry_size;
+  else
+    {
+       unsigned int ext_index = index - 32768;
+
+       plt_offset = (32768 * base_plt_entry_size)
+         + ((ext_index / plt_entries_per_block)
+            * plt_block_size)
+         + ((ext_index % plt_entries_per_block)
+            * plt_insn_chunk_size);
+    }
+
+  gsym->set_plt_offset(plt_offset);
+
+  ++this->count_;
+
+  // Every PLT entry needs a reloc.
+  gsym->set_needs_dynsym_entry();
+  this->rel_->add_global(gsym, elfcpp::R_SPARC_JMP_SLOT, this,
+                        plt_offset, 0);
+
+  // Note that we don't need to save the symbol.  The contents of the
+  // PLT are independent of which symbols are used.  The symbols only
+  // appear in the relocations.
+}
+
+static const unsigned int sparc_nop = 0x01000000;
+static const unsigned int sparc_sethi_g1 = 0x03000000;
+static const unsigned int sparc_branch_always = 0x30800000;
+static const unsigned int sparc_branch_always_pt = 0x30680000;
+static const unsigned int sparc_mov = 0x80100000;
+static const unsigned int sparc_mov_g0_o0 = 0x90100000;
+static const unsigned int sparc_mov_o7_g5 = 0x8a10000f;
+static const unsigned int sparc_call_plus_8 = 0x40000002;
+static const unsigned int sparc_ldx_o7_imm_g1 = 0xc25be000;
+static const unsigned int sparc_jmpl_o7_g1_g1 = 0x83c3c001;
+static const unsigned int sparc_mov_g5_o7 = 0x9e100005;
+
+// Write out the PLT.
+
+template<int size, bool big_endian>
+void
+Output_data_plt_sparc<size, big_endian>::do_write(Output_file* of)
+{
+  const off_t offset = this->offset();
+  const section_size_type oview_size =
+    convert_to_section_size_type(this->data_size());
+  unsigned char* const oview = of->get_output_view(offset, oview_size);
+  unsigned char* pov = oview;
+
+  memset(pov, 0, base_plt_entry_size * 4);
+  pov += base_plt_entry_size * 4;
+
+  unsigned int plt_offset = base_plt_entry_size * 4;
+  const unsigned int count = this->count_;
+
+  if (size == 64)
+    {
+      unsigned int limit;
+
+      limit = (count > 32768 ? 32768 : count);
+
+      for (unsigned int i = 0; i < limit; ++i)
+       {
+         elfcpp::Swap<32, true>::writeval(pov + 0x00,
+                                          sparc_sethi_g1 + plt_offset);
+         elfcpp::Swap<32, true>::writeval(pov + 0x04,
+                                          sparc_branch_always_pt +
+                                          (((base_plt_entry_size -
+                                             (plt_offset + 4)) >> 2) &
+                                           0x7ffff));
+         elfcpp::Swap<32, true>::writeval(pov + 0x08, sparc_nop);
+         elfcpp::Swap<32, true>::writeval(pov + 0x0c, sparc_nop);
+         elfcpp::Swap<32, true>::writeval(pov + 0x10, sparc_nop);
+         elfcpp::Swap<32, true>::writeval(pov + 0x14, sparc_nop);
+         elfcpp::Swap<32, true>::writeval(pov + 0x18, sparc_nop);
+         elfcpp::Swap<32, true>::writeval(pov + 0x1c, sparc_nop);
+
+         pov += base_plt_entry_size;
+         plt_offset += base_plt_entry_size;
+       }
+
+      if (count > 32768)
+       {
+         unsigned int ext_cnt = count - 32768;
+         unsigned int blks = ext_cnt / plt_entries_per_block;
+
+         for (unsigned int i = 0; i < blks; ++i)
+           {
+             unsigned int data_off = (plt_entries_per_block
+                                      * plt_insn_chunk_size) - 4;
+
+             for (unsigned int j = 0; j < plt_entries_per_block; ++j)
+               {
+                 elfcpp::Swap<32, true>::writeval(pov + 0x00,
+                                                  sparc_mov_o7_g5);
+                 elfcpp::Swap<32, true>::writeval(pov + 0x04,
+                                                  sparc_call_plus_8);
+                 elfcpp::Swap<32, true>::writeval(pov + 0x08,
+                                                  sparc_nop);
+                 elfcpp::Swap<32, true>::writeval(pov + 0x0c,
+                                                  sparc_ldx_o7_imm_g1 +
+                                                  (data_off & 0x1fff));
+                 elfcpp::Swap<32, true>::writeval(pov + 0x10,
+                                                  sparc_jmpl_o7_g1_g1);
+                 elfcpp::Swap<32, true>::writeval(pov + 0x14,
+                                                  sparc_mov_g5_o7);
+
+                 elfcpp::Swap<64, big_endian>::writeval(
+                               pov + 0x4 + data_off,
+                               (elfcpp::Elf_Xword) (oview - (pov + 0x04)));
+
+                 pov += plt_insn_chunk_size;
+                 data_off -= 16;
+               }
+           }
+
+         unsigned int sub_blk_cnt = ext_cnt % plt_entries_per_block;
+         for (unsigned int i = 0; i < sub_blk_cnt; ++i)
+           {
+             unsigned int data_off = (sub_blk_cnt
+                                      * plt_insn_chunk_size) - 4;
+
+             for (unsigned int j = 0; j < plt_entries_per_block; ++j)
+               {
+                 elfcpp::Swap<32, true>::writeval(pov + 0x00,
+                                                  sparc_mov_o7_g5);
+                 elfcpp::Swap<32, true>::writeval(pov + 0x04,
+                                                  sparc_call_plus_8);
+                 elfcpp::Swap<32, true>::writeval(pov + 0x08,
+                                                  sparc_nop);
+                 elfcpp::Swap<32, true>::writeval(pov + 0x0c,
+                                                  sparc_ldx_o7_imm_g1 +
+                                                  (data_off & 0x1fff));
+                 elfcpp::Swap<32, true>::writeval(pov + 0x10,
+                                                  sparc_jmpl_o7_g1_g1);
+                 elfcpp::Swap<32, true>::writeval(pov + 0x14,
+                                                  sparc_mov_g5_o7);
+
+                 elfcpp::Swap<64, big_endian>::writeval(
+                               pov + 0x4 + data_off,
+                               (elfcpp::Elf_Xword) (oview - (pov + 0x04)));
+
+                 pov += plt_insn_chunk_size;
+                 data_off -= 16;
+               }
+           }
+       }
+    }
+  else
+    {
+      for (unsigned int i = 0; i < count; ++i)
+       {
+         elfcpp::Swap<32, true>::writeval(pov + 0x00,
+                                          sparc_sethi_g1 + plt_offset);
+         elfcpp::Swap<32, true>::writeval(pov + 0x04,
+                                          sparc_branch_always +
+                                          (((- (plt_offset + 4)) >> 2) &
+                                           0x003fffff));
+         elfcpp::Swap<32, true>::writeval(pov + 0x08, sparc_nop);
+
+         pov += base_plt_entry_size;
+         plt_offset += base_plt_entry_size;
+       }
+
+      elfcpp::Swap<32, true>::writeval(pov, sparc_nop);
+      pov += 4;
+    }
+
+  gold_assert(static_cast<section_size_type>(pov - oview) == oview_size);
+
+  of->write_output_view(offset, oview_size, oview);
+}
+
+// Create a PLT entry for a global symbol.
+
+template<int size, bool big_endian>
+void
+Target_sparc<size, big_endian>::make_plt_entry(Symbol_table* symtab,
+                                              Layout* layout,
+                                              Symbol* gsym)
+{
+  if (gsym->has_plt_offset())
+    return;
+
+  if (this->plt_ == NULL)
+    {
+      // Create the GOT sections first.
+      this->got_section(symtab, layout);
+
+      // Ensure that .rela.dyn always appears before .rela.plt  This is
+      // necessary due to how, on Sparc and some other targets, .rela.dyn
+      // needs to include .rela.plt in it's range.
+      this->rela_dyn_section(layout);
+
+      this->plt_ = new Output_data_plt_sparc<size, big_endian>(layout);
+      layout->add_output_section_data(".plt", elfcpp::SHT_PROGBITS,
+                                     (elfcpp::SHF_ALLOC
+                                      | elfcpp::SHF_EXECINSTR
+                                      | elfcpp::SHF_WRITE),
+                                     this->plt_, ORDER_PLT, false);
+
+      // Define _PROCEDURE_LINKAGE_TABLE_ at the start of the .plt section.
+      symtab->define_in_output_data("_PROCEDURE_LINKAGE_TABLE_", NULL,
+                                   Symbol_table::PREDEFINED,
+                                   this->plt_,
+                                   0, 0, elfcpp::STT_OBJECT,
+                                   elfcpp::STB_LOCAL,
+                                   elfcpp::STV_HIDDEN, 0,
+                                   false, false);
+    }
+
+  this->plt_->add_entry(gsym);
+}
+
+// Return the number of entries in the PLT.
+
+template<int size, bool big_endian>
+unsigned int
+Target_sparc<size, big_endian>::plt_entry_count() const
+{
+  if (this->plt_ == NULL)
+    return 0;
+  return this->plt_->entry_count();
+}
+
+// Return the offset of the first non-reserved PLT entry.
+
+template<int size, bool big_endian>
+unsigned int
+Target_sparc<size, big_endian>::first_plt_entry_offset() const
+{
+  return Output_data_plt_sparc<size, big_endian>::first_plt_entry_offset();
+}
+
+// Return the size of each PLT entry.
+
+template<int size, bool big_endian>
+unsigned int
+Target_sparc<size, big_endian>::plt_entry_size() const
+{
+  return Output_data_plt_sparc<size, big_endian>::get_plt_entry_size();
+}
+
+// Create a GOT entry for the TLS module index.
+
+template<int size, bool big_endian>
+unsigned int
+Target_sparc<size, big_endian>::got_mod_index_entry(Symbol_table* symtab,
+                                                   Layout* layout,
+                                                   Sized_relobj<size, big_endian>* object)
+{
+  if (this->got_mod_index_offset_ == -1U)
+    {
+      gold_assert(symtab != NULL && layout != NULL && object != NULL);
+      Reloc_section* rela_dyn = this->rela_dyn_section(layout);
+      Output_data_got<size, big_endian>* got;
+      unsigned int got_offset;
+
+      got = this->got_section(symtab, layout);
+      got_offset = got->add_constant(0);
+      rela_dyn->add_local(object, 0,
+                         (size == 64 ?
+                          elfcpp::R_SPARC_TLS_DTPMOD64 :
+                          elfcpp::R_SPARC_TLS_DTPMOD32), got,
+                         got_offset, 0);
+      got->add_constant(0);
+      this->got_mod_index_offset_ = got_offset;
+    }
+  return this->got_mod_index_offset_;
+}
+
+// Optimize the TLS relocation type based on what we know about the
+// symbol.  IS_FINAL is true if the final address of this symbol is
+// known at link time.
+
+static tls::Tls_optimization
+optimize_tls_reloc(bool is_final, int r_type)
+{
+  // If we are generating a shared library, then we can't do anything
+  // in the linker.
+  if (parameters->options().shared())
+    return tls::TLSOPT_NONE;
+
+  switch (r_type)
+    {
+    case elfcpp::R_SPARC_TLS_GD_HI22: // Global-dynamic
+    case elfcpp::R_SPARC_TLS_GD_LO10:
+    case elfcpp::R_SPARC_TLS_GD_ADD:
+    case elfcpp::R_SPARC_TLS_GD_CALL:
+      // These are General-Dynamic which permits fully general TLS
+      // access.  Since we know that we are generating an executable,
+      // we can convert this to Initial-Exec.  If we also know that
+      // this is a local symbol, we can further switch to Local-Exec.
+      if (is_final)
+       return tls::TLSOPT_TO_LE;
+      return tls::TLSOPT_TO_IE;
+
+    case elfcpp::R_SPARC_TLS_LDM_HI22: // Local-dynamic
+    case elfcpp::R_SPARC_TLS_LDM_LO10:
+    case elfcpp::R_SPARC_TLS_LDM_ADD:
+    case elfcpp::R_SPARC_TLS_LDM_CALL:
+      // This is Local-Dynamic, which refers to a local symbol in the
+      // dynamic TLS block.  Since we know that we generating an
+      // executable, we can switch to Local-Exec.
+      return tls::TLSOPT_TO_LE;
+
+    case elfcpp::R_SPARC_TLS_LDO_HIX22:        // Alternate local-dynamic
+    case elfcpp::R_SPARC_TLS_LDO_LOX10:
+    case elfcpp::R_SPARC_TLS_LDO_ADD:
+      // Another type of Local-Dynamic relocation.
+      return tls::TLSOPT_TO_LE;
+
+    case elfcpp::R_SPARC_TLS_IE_HI22:  // Initial-exec
+    case elfcpp::R_SPARC_TLS_IE_LO10:
+    case elfcpp::R_SPARC_TLS_IE_LD:
+    case elfcpp::R_SPARC_TLS_IE_LDX:
+    case elfcpp::R_SPARC_TLS_IE_ADD:
+      // These are Initial-Exec relocs which get the thread offset
+      // from the GOT.  If we know that we are linking against the
+      // local symbol, we can switch to Local-Exec, which links the
+      // thread offset into the instruction.
+      if (is_final)
+       return tls::TLSOPT_TO_LE;
+      return tls::TLSOPT_NONE;
+
+    case elfcpp::R_SPARC_TLS_LE_HIX22: // Local-exec
+    case elfcpp::R_SPARC_TLS_LE_LOX10:
+      // When we already have Local-Exec, there is nothing further we
+      // can do.
+      return tls::TLSOPT_NONE;
+
+    default:
+      gold_unreachable();
+    }
+}
+
+// Generate a PLT entry slot for a call to __tls_get_addr
+template<int size, bool big_endian>
+void
+Target_sparc<size, big_endian>::Scan::generate_tls_call(Symbol_table* symtab,
+                                                       Layout* layout,
+                                                       Target_sparc<size, big_endian>* target)
+{
+  Symbol* gsym = target->tls_get_addr_sym(symtab);
+
+  target->make_plt_entry(symtab, layout, gsym);
+}
+
+// Report an unsupported relocation against a local symbol.
+
+template<int size, bool big_endian>
+void
+Target_sparc<size, big_endian>::Scan::unsupported_reloc_local(
+                       Sized_relobj<size, big_endian>* object,
+                       unsigned int r_type)
+{
+  gold_error(_("%s: unsupported reloc %u against local symbol"),
+            object->name().c_str(), r_type);
+}
+
+// We are about to emit a dynamic relocation of type R_TYPE.  If the
+// dynamic linker does not support it, issue an error.
+
+template<int size, bool big_endian>
+void
+Target_sparc<size, big_endian>::Scan::check_non_pic(Relobj* object, unsigned int r_type)
+{
+  gold_assert(r_type != elfcpp::R_SPARC_NONE);
+
+  if (size == 64)
+    {
+      switch (r_type)
+       {
+         // These are the relocation types supported by glibc for sparc 64-bit.
+       case elfcpp::R_SPARC_RELATIVE:
+       case elfcpp::R_SPARC_COPY:
+       case elfcpp::R_SPARC_64:
+       case elfcpp::R_SPARC_GLOB_DAT:
+       case elfcpp::R_SPARC_JMP_SLOT:
+       case elfcpp::R_SPARC_TLS_DTPMOD64:
+       case elfcpp::R_SPARC_TLS_DTPOFF64:
+       case elfcpp::R_SPARC_TLS_TPOFF64:
+       case elfcpp::R_SPARC_TLS_LE_HIX22:
+       case elfcpp::R_SPARC_TLS_LE_LOX10:
+       case elfcpp::R_SPARC_8:
+       case elfcpp::R_SPARC_16:
+       case elfcpp::R_SPARC_DISP8:
+       case elfcpp::R_SPARC_DISP16:
+       case elfcpp::R_SPARC_DISP32:
+       case elfcpp::R_SPARC_WDISP30:
+       case elfcpp::R_SPARC_LO10:
+       case elfcpp::R_SPARC_HI22:
+       case elfcpp::R_SPARC_OLO10:
+       case elfcpp::R_SPARC_H44:
+       case elfcpp::R_SPARC_M44:
+       case elfcpp::R_SPARC_L44:
+       case elfcpp::R_SPARC_HH22:
+       case elfcpp::R_SPARC_HM10:
+       case elfcpp::R_SPARC_LM22:
+       case elfcpp::R_SPARC_UA16:
+       case elfcpp::R_SPARC_UA32:
+       case elfcpp::R_SPARC_UA64:
+         return;
+
+       default:
+         break;
+       }
+    }
+  else
+    {
+      switch (r_type)
+       {
+         // These are the relocation types supported by glibc for sparc 32-bit.
+       case elfcpp::R_SPARC_RELATIVE:
+       case elfcpp::R_SPARC_COPY:
+       case elfcpp::R_SPARC_GLOB_DAT:
+       case elfcpp::R_SPARC_32:
+       case elfcpp::R_SPARC_JMP_SLOT:
+       case elfcpp::R_SPARC_TLS_DTPMOD32:
+       case elfcpp::R_SPARC_TLS_DTPOFF32:
+       case elfcpp::R_SPARC_TLS_TPOFF32:
+       case elfcpp::R_SPARC_TLS_LE_HIX22:
+       case elfcpp::R_SPARC_TLS_LE_LOX10:
+       case elfcpp::R_SPARC_8:
+       case elfcpp::R_SPARC_16:
+       case elfcpp::R_SPARC_DISP8:
+       case elfcpp::R_SPARC_DISP16:
+       case elfcpp::R_SPARC_DISP32:
+       case elfcpp::R_SPARC_LO10:
+       case elfcpp::R_SPARC_WDISP30:
+       case elfcpp::R_SPARC_HI22:
+       case elfcpp::R_SPARC_UA16:
+       case elfcpp::R_SPARC_UA32:
+         return;
+
+       default:
+         break;
+       }
+    }
+
+  // This prevents us from issuing more than one error per reloc
+  // section.  But we can still wind up issuing more than one
+  // error per object file.
+  if (this->issued_non_pic_error_)
+    return;
+  gold_assert(parameters->options().output_is_position_independent());
+  object->error(_("requires unsupported dynamic reloc; "
+                 "recompile with -fPIC"));
+  this->issued_non_pic_error_ = true;
+  return;
+}
+
+// Scan a relocation for a local symbol.
+
+template<int size, bool big_endian>
+inline void
+Target_sparc<size, big_endian>::Scan::local(
+                       Symbol_table* symtab,
+                       Layout* layout,
+                       Target_sparc<size, big_endian>* target,
+                       Sized_relobj<size, big_endian>* object,
+                       unsigned int data_shndx,
+                       Output_section* output_section,
+                       const elfcpp::Rela<size, big_endian>& reloc,
+                       unsigned int r_type,
+                       const elfcpp::Sym<size, big_endian>& lsym)
+{
+  unsigned int orig_r_type = r_type;
+
+  r_type &= 0xff;
+  switch (r_type)
+    {
+    case elfcpp::R_SPARC_NONE:
+    case elfcpp::R_SPARC_REGISTER:
+    case elfcpp::R_SPARC_GNU_VTINHERIT:
+    case elfcpp::R_SPARC_GNU_VTENTRY:
+      break;
+
+    case elfcpp::R_SPARC_64:
+    case elfcpp::R_SPARC_32:
+      // If building a shared library (or a position-independent
+      // executable), we need to create a dynamic relocation for
+      // this location. The relocation applied at link time will
+      // apply the link-time value, so we flag the location with
+      // an R_SPARC_RELATIVE relocation so the dynamic loader can
+      // relocate it easily.
+      if (parameters->options().output_is_position_independent())
+        {
+          Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+          unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+          rela_dyn->add_local_relative(object, r_sym, elfcpp::R_SPARC_RELATIVE,
+                                      output_section, data_shndx,
+                                      reloc.get_r_offset(),
+                                      reloc.get_r_addend());
+        }
+      break;
+
+    case elfcpp::R_SPARC_HIX22:
+    case elfcpp::R_SPARC_LOX10:
+    case elfcpp::R_SPARC_H44:
+    case elfcpp::R_SPARC_M44:
+    case elfcpp::R_SPARC_L44:
+    case elfcpp::R_SPARC_HH22:
+    case elfcpp::R_SPARC_HM10:
+    case elfcpp::R_SPARC_LM22:
+    case elfcpp::R_SPARC_UA64:
+    case elfcpp::R_SPARC_UA32:
+    case elfcpp::R_SPARC_UA16:
+    case elfcpp::R_SPARC_HI22:
+    case elfcpp::R_SPARC_LO10:
+    case elfcpp::R_SPARC_OLO10:
+    case elfcpp::R_SPARC_16:
+    case elfcpp::R_SPARC_11:
+    case elfcpp::R_SPARC_10:
+    case elfcpp::R_SPARC_8:
+    case elfcpp::R_SPARC_7:
+    case elfcpp::R_SPARC_6:
+    case elfcpp::R_SPARC_5:
+      // If building a shared library (or a position-independent
+      // executable), we need to create a dynamic relocation for
+      // this location.
+      if (parameters->options().output_is_position_independent())
+        {
+          Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+          unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+
+         check_non_pic(object, r_type);
+          if (lsym.get_st_type() != elfcpp::STT_SECTION)
+            {
+              rela_dyn->add_local(object, r_sym, orig_r_type, output_section,
+                                 data_shndx, reloc.get_r_offset(),
+                                 reloc.get_r_addend());
+            }
+          else
+            {
+              gold_assert(lsym.get_st_value() == 0);
+             rela_dyn->add_symbolless_local_addend(object, r_sym, orig_r_type,
+                                                   output_section, data_shndx,
+                                                   reloc.get_r_offset(),
+                                                   reloc.get_r_addend());
+            }
+        }
+      break;
+
+    case elfcpp::R_SPARC_WDISP30:
+    case elfcpp::R_SPARC_WPLT30:
+    case elfcpp::R_SPARC_WDISP22:
+    case elfcpp::R_SPARC_WDISP19:
+    case elfcpp::R_SPARC_WDISP16:
+    case elfcpp::R_SPARC_DISP8:
+    case elfcpp::R_SPARC_DISP16:
+    case elfcpp::R_SPARC_DISP32:
+    case elfcpp::R_SPARC_DISP64:
+    case elfcpp::R_SPARC_PC10:
+    case elfcpp::R_SPARC_PC22:
+      break;
+
+    case elfcpp::R_SPARC_GOTDATA_OP:
+    case elfcpp::R_SPARC_GOTDATA_OP_HIX22:
+    case elfcpp::R_SPARC_GOTDATA_OP_LOX10:
+    case elfcpp::R_SPARC_GOT10:
+    case elfcpp::R_SPARC_GOT13:
+    case elfcpp::R_SPARC_GOT22:
+      {
+        // The symbol requires a GOT entry.
+        Output_data_got<size, big_endian>* got;
+        unsigned int r_sym;
+
+       got = target->got_section(symtab, layout);
+       r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+
+       // If we are generating a shared object, we need to add a
+       // dynamic relocation for this symbol's GOT entry.
+       if (parameters->options().output_is_position_independent())
+         {
+           if (!object->local_has_got_offset(r_sym, GOT_TYPE_STANDARD))
+             {
+               Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+               unsigned int off;
+
+               off = got->add_constant(0);
+               object->set_local_got_offset(r_sym, GOT_TYPE_STANDARD, off);
+               rela_dyn->add_local_relative(object, r_sym,
+                                            elfcpp::R_SPARC_RELATIVE,
+                                            got, off, 0);
+             }
+         }
+       else
+         got->add_local(object, r_sym, GOT_TYPE_STANDARD);
+      }
+      break;
+
+      // These are initial TLS relocs, which are expected when
+      // linking.
+    case elfcpp::R_SPARC_TLS_GD_HI22: // Global-dynamic
+    case elfcpp::R_SPARC_TLS_GD_LO10:
+    case elfcpp::R_SPARC_TLS_GD_ADD:
+    case elfcpp::R_SPARC_TLS_GD_CALL:
+    case elfcpp::R_SPARC_TLS_LDM_HI22 :        // Local-dynamic
+    case elfcpp::R_SPARC_TLS_LDM_LO10:
+    case elfcpp::R_SPARC_TLS_LDM_ADD:
+    case elfcpp::R_SPARC_TLS_LDM_CALL:
+    case elfcpp::R_SPARC_TLS_LDO_HIX22:        // Alternate local-dynamic
+    case elfcpp::R_SPARC_TLS_LDO_LOX10:
+    case elfcpp::R_SPARC_TLS_LDO_ADD:
+    case elfcpp::R_SPARC_TLS_IE_HI22:  // Initial-exec
+    case elfcpp::R_SPARC_TLS_IE_LO10:
+    case elfcpp::R_SPARC_TLS_IE_LD:
+    case elfcpp::R_SPARC_TLS_IE_LDX:
+    case elfcpp::R_SPARC_TLS_IE_ADD:
+    case elfcpp::R_SPARC_TLS_LE_HIX22: // Local-exec
+    case elfcpp::R_SPARC_TLS_LE_LOX10:
+      {
+       bool output_is_shared = parameters->options().shared();
+       const tls::Tls_optimization optimized_type
+            = optimize_tls_reloc(!output_is_shared, r_type);
+       switch (r_type)
+         {
+         case elfcpp::R_SPARC_TLS_GD_HI22: // Global-dynamic
+         case elfcpp::R_SPARC_TLS_GD_LO10:
+         case elfcpp::R_SPARC_TLS_GD_ADD:
+         case elfcpp::R_SPARC_TLS_GD_CALL:
+           if (optimized_type == tls::TLSOPT_NONE)
+             {
+               // Create a pair of GOT entries for the module index and
+               // dtv-relative offset.
+                Output_data_got<size, big_endian>* got
+                    = target->got_section(symtab, layout);
+                unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+               unsigned int shndx = lsym.get_st_shndx();
+               bool is_ordinary;
+               shndx = object->adjust_sym_shndx(r_sym, shndx, &is_ordinary);
+               if (!is_ordinary)
+                 object->error(_("local symbol %u has bad shndx %u"),
+                               r_sym, shndx);
+               else
+                 got->add_local_pair_with_rela(object, r_sym, 
+                                               lsym.get_st_shndx(),
+                                               GOT_TYPE_TLS_PAIR,
+                                               target->rela_dyn_section(layout),
+                                               (size == 64
+                                                ? elfcpp::R_SPARC_TLS_DTPMOD64
+                                                : elfcpp::R_SPARC_TLS_DTPMOD32),
+                                                0);
+               if (r_type == elfcpp::R_SPARC_TLS_GD_CALL)
+                 generate_tls_call(symtab, layout, target);
+             }
+           else if (optimized_type != tls::TLSOPT_TO_LE)
+             unsupported_reloc_local(object, r_type);
+           break;
+
+         case elfcpp::R_SPARC_TLS_LDM_HI22 :   // Local-dynamic
+         case elfcpp::R_SPARC_TLS_LDM_LO10:
+         case elfcpp::R_SPARC_TLS_LDM_ADD:
+         case elfcpp::R_SPARC_TLS_LDM_CALL:
+           if (optimized_type == tls::TLSOPT_NONE)
+             {
+               // Create a GOT entry for the module index.
+               target->got_mod_index_entry(symtab, layout, object);
+
+               if (r_type == elfcpp::R_SPARC_TLS_LDM_CALL)
+                 generate_tls_call(symtab, layout, target);
+             }
+           else if (optimized_type != tls::TLSOPT_TO_LE)
+             unsupported_reloc_local(object, r_type);
+           break;
+
+         case elfcpp::R_SPARC_TLS_LDO_HIX22:   // Alternate local-dynamic
+         case elfcpp::R_SPARC_TLS_LDO_LOX10:
+         case elfcpp::R_SPARC_TLS_LDO_ADD:
+           break;
+
+         case elfcpp::R_SPARC_TLS_IE_HI22:     // Initial-exec
+         case elfcpp::R_SPARC_TLS_IE_LO10:
+         case elfcpp::R_SPARC_TLS_IE_LD:
+         case elfcpp::R_SPARC_TLS_IE_LDX:
+         case elfcpp::R_SPARC_TLS_IE_ADD:
+           layout->set_has_static_tls();
+           if (optimized_type == tls::TLSOPT_NONE)
+             {
+               // Create a GOT entry for the tp-relative offset.
+               Output_data_got<size, big_endian>* got
+                 = target->got_section(symtab, layout);
+               unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+
+               if (!object->local_has_got_offset(r_sym, GOT_TYPE_TLS_OFFSET))
+                 {
+                   Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+                   unsigned int off = got->add_constant(0);
+
+                   object->set_local_got_offset(r_sym, GOT_TYPE_TLS_OFFSET, off);
+
+                   rela_dyn->add_symbolless_local_addend(object, r_sym,
+                                                         (size == 64 ?
+                                                          elfcpp::R_SPARC_TLS_TPOFF64 :
+                                                          elfcpp::R_SPARC_TLS_TPOFF32),
+                                                         got, off, 0);
+                 }
+             }
+           else if (optimized_type != tls::TLSOPT_TO_LE)
+             unsupported_reloc_local(object, r_type);
+           break;
+
+         case elfcpp::R_SPARC_TLS_LE_HIX22:    // Local-exec
+         case elfcpp::R_SPARC_TLS_LE_LOX10:
+           layout->set_has_static_tls();
+           if (output_is_shared)
+             {
+               // We need to create a dynamic relocation.
+                gold_assert(lsym.get_st_type() != elfcpp::STT_SECTION);
+                unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+                Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+                rela_dyn->add_symbolless_local_addend(object, r_sym, r_type,
+                                                     output_section, data_shndx,
+                                                     reloc.get_r_offset(), 0);
+             }
+           break;
+         }
+      }
+      break;
+
+      // These are relocations which should only be seen by the
+      // dynamic linker, and should never be seen here.
+    case elfcpp::R_SPARC_COPY:
+    case elfcpp::R_SPARC_GLOB_DAT:
+    case elfcpp::R_SPARC_JMP_SLOT:
+    case elfcpp::R_SPARC_RELATIVE:
+    case elfcpp::R_SPARC_TLS_DTPMOD64:
+    case elfcpp::R_SPARC_TLS_DTPMOD32:
+    case elfcpp::R_SPARC_TLS_DTPOFF64:
+    case elfcpp::R_SPARC_TLS_DTPOFF32:
+    case elfcpp::R_SPARC_TLS_TPOFF64:
+    case elfcpp::R_SPARC_TLS_TPOFF32:
+      gold_error(_("%s: unexpected reloc %u in object file"),
+                object->name().c_str(), r_type);
+      break;
+
+    default:
+      unsupported_reloc_local(object, r_type);
+      break;
+    }
+}
+
+// Report an unsupported relocation against a global symbol.
+
+template<int size, bool big_endian>
+void
+Target_sparc<size, big_endian>::Scan::unsupported_reloc_global(
+                       Sized_relobj<size, big_endian>* object,
+                       unsigned int r_type,
+                       Symbol* gsym)
+{
+  gold_error(_("%s: unsupported reloc %u against global symbol %s"),
+            object->name().c_str(), r_type, gsym->demangled_name().c_str());
+}
+
+// Scan a relocation for a global symbol.
+
+template<int size, bool big_endian>
+inline void
+Target_sparc<size, big_endian>::Scan::global(
+                               Symbol_table* symtab,
+                               Layout* layout,
+                               Target_sparc<size, big_endian>* target,
+                               Sized_relobj<size, big_endian>* object,
+                               unsigned int data_shndx,
+                               Output_section* output_section,
+                               const elfcpp::Rela<size, big_endian>& reloc,
+                               unsigned int r_type,
+                               Symbol* gsym)
+{
+  unsigned int orig_r_type = r_type;
+
+  // A reference to _GLOBAL_OFFSET_TABLE_ implies that we need a got
+  // section.  We check here to avoid creating a dynamic reloc against
+  // _GLOBAL_OFFSET_TABLE_.
+  if (!target->has_got_section()
+      && strcmp(gsym->name(), "_GLOBAL_OFFSET_TABLE_") == 0)
+    target->got_section(symtab, layout);
+
+  r_type &= 0xff;
+  switch (r_type)
+    {
+    case elfcpp::R_SPARC_NONE:
+    case elfcpp::R_SPARC_REGISTER:
+    case elfcpp::R_SPARC_GNU_VTINHERIT:
+    case elfcpp::R_SPARC_GNU_VTENTRY:
+      break;
+
+    case elfcpp::R_SPARC_PLT64:
+    case elfcpp::R_SPARC_PLT32:
+    case elfcpp::R_SPARC_HIPLT22:
+    case elfcpp::R_SPARC_LOPLT10:
+    case elfcpp::R_SPARC_PCPLT32:
+    case elfcpp::R_SPARC_PCPLT22:
+    case elfcpp::R_SPARC_PCPLT10:
+    case elfcpp::R_SPARC_WPLT30:
+      // If the symbol is fully resolved, this is just a PC32 reloc.
+      // Otherwise we need a PLT entry.
+      if (gsym->final_value_is_known())
+       break;
+      // If building a shared library, we can also skip the PLT entry
+      // if the symbol is defined in the output file and is protected
+      // or hidden.
+      if (gsym->is_defined()
+          && !gsym->is_from_dynobj()
+          && !gsym->is_preemptible())
+       break;
+      target->make_plt_entry(symtab, layout, gsym);
+      break;
+
+    case elfcpp::R_SPARC_DISP8:
+    case elfcpp::R_SPARC_DISP16:
+    case elfcpp::R_SPARC_DISP32:
+    case elfcpp::R_SPARC_DISP64:
+    case elfcpp::R_SPARC_PC_HH22:
+    case elfcpp::R_SPARC_PC_HM10:
+    case elfcpp::R_SPARC_PC_LM22:
+    case elfcpp::R_SPARC_PC10:
+    case elfcpp::R_SPARC_PC22:
+    case elfcpp::R_SPARC_WDISP30:
+    case elfcpp::R_SPARC_WDISP22:
+    case elfcpp::R_SPARC_WDISP19:
+    case elfcpp::R_SPARC_WDISP16:
+      {
+       if (gsym->needs_plt_entry())
+         target->make_plt_entry(symtab, layout, gsym);
+       // Make a dynamic relocation if necessary.
+       int flags = Symbol::NON_PIC_REF;
+       if (gsym->type() == elfcpp::STT_FUNC)
+         flags |= Symbol::FUNCTION_CALL;
+       if (gsym->needs_dynamic_reloc(flags))
+         {
+           if (gsym->may_need_copy_reloc())
+             {
+               target->copy_reloc(symtab, layout, object,
+                                  data_shndx, output_section, gsym,
+                                  reloc);
+             }
+           else
+             {
+               Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+               check_non_pic(object, r_type);
+               rela_dyn->add_global(gsym, orig_r_type, output_section, object,
+                                    data_shndx, reloc.get_r_offset(),
+                                    reloc.get_r_addend());
+             }
+         }
+      }
+      break;
+
+    case elfcpp::R_SPARC_UA64:
+    case elfcpp::R_SPARC_64:
+    case elfcpp::R_SPARC_HIX22:
+    case elfcpp::R_SPARC_LOX10:
+    case elfcpp::R_SPARC_H44:
+    case elfcpp::R_SPARC_M44:
+    case elfcpp::R_SPARC_L44:
+    case elfcpp::R_SPARC_HH22:
+    case elfcpp::R_SPARC_HM10:
+    case elfcpp::R_SPARC_LM22:
+    case elfcpp::R_SPARC_HI22:
+    case elfcpp::R_SPARC_LO10:
+    case elfcpp::R_SPARC_OLO10:
+    case elfcpp::R_SPARC_UA32:
+    case elfcpp::R_SPARC_32:
+    case elfcpp::R_SPARC_UA16:
+    case elfcpp::R_SPARC_16:
+    case elfcpp::R_SPARC_11:
+    case elfcpp::R_SPARC_10:
+    case elfcpp::R_SPARC_8:
+    case elfcpp::R_SPARC_7:
+    case elfcpp::R_SPARC_6:
+    case elfcpp::R_SPARC_5:
+      {
+        // Make a PLT entry if necessary.
+        if (gsym->needs_plt_entry())
+          {
+            target->make_plt_entry(symtab, layout, gsym);
+            // Since this is not a PC-relative relocation, we may be
+            // taking the address of a function. In that case we need to
+            // set the entry in the dynamic symbol table to the address of
+            // the PLT entry.
+            if (gsym->is_from_dynobj() && !parameters->options().shared())
+              gsym->set_needs_dynsym_value();
+          }
+        // Make a dynamic relocation if necessary.
+        if (gsym->needs_dynamic_reloc(Symbol::ABSOLUTE_REF))
+          {
+           unsigned int r_off = reloc.get_r_offset();
+
+           // The assembler can sometimes emit unaligned relocations
+           // for dwarf2 cfi directives. 
+           switch (r_type)
+             {
+             case elfcpp::R_SPARC_16:
+               if (r_off & 0x1)
+                 orig_r_type = r_type = elfcpp::R_SPARC_UA16;
+               break;
+             case elfcpp::R_SPARC_32:
+               if (r_off & 0x3)
+                 orig_r_type = r_type = elfcpp::R_SPARC_UA32;
+               break;
+             case elfcpp::R_SPARC_64:
+               if (r_off & 0x7)
+                 orig_r_type = r_type = elfcpp::R_SPARC_UA64;
+               break;
+             case elfcpp::R_SPARC_UA16:
+               if (!(r_off & 0x1))
+                 orig_r_type = r_type = elfcpp::R_SPARC_16;
+               break;
+             case elfcpp::R_SPARC_UA32:
+               if (!(r_off & 0x3))
+                 orig_r_type = r_type = elfcpp::R_SPARC_32;
+               break;
+             case elfcpp::R_SPARC_UA64:
+               if (!(r_off & 0x7))
+                 orig_r_type = r_type = elfcpp::R_SPARC_64;
+               break;
+             }
+
+            if (gsym->may_need_copy_reloc())
+              {
+               target->copy_reloc(symtab, layout, object,
+                                  data_shndx, output_section, gsym, reloc);
+              }
+            else if ((r_type == elfcpp::R_SPARC_32
+                     || r_type == elfcpp::R_SPARC_64)
+                     && gsym->can_use_relative_reloc(false))
+              {
+                Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+                rela_dyn->add_global_relative(gsym, elfcpp::R_SPARC_RELATIVE,
+                                             output_section, object,
+                                             data_shndx, reloc.get_r_offset(),
+                                             reloc.get_r_addend());
+              }
+            else
+              {
+                Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+
+               check_non_pic(object, r_type);
+               if (gsym->is_from_dynobj()
+                   || gsym->is_undefined()
+                   || gsym->is_preemptible())
+                 rela_dyn->add_global(gsym, orig_r_type, output_section,
+                                      object, data_shndx,
+                                      reloc.get_r_offset(),
+                                      reloc.get_r_addend());
+               else
+                 rela_dyn->add_symbolless_global_addend(gsym, orig_r_type,
+                                                        output_section,
+                                                        object, data_shndx,
+                                                        reloc.get_r_offset(),
+                                                        reloc.get_r_addend());
+              }
+          }
+      }
+      break;
+
+    case elfcpp::R_SPARC_GOTDATA_OP:
+    case elfcpp::R_SPARC_GOTDATA_OP_HIX22:
+    case elfcpp::R_SPARC_GOTDATA_OP_LOX10:
+    case elfcpp::R_SPARC_GOT10:
+    case elfcpp::R_SPARC_GOT13:
+    case elfcpp::R_SPARC_GOT22:
+      {
+        // The symbol requires a GOT entry.
+        Output_data_got<size, big_endian>* got;
+
+       got = target->got_section(symtab, layout);
+        if (gsym->final_value_is_known())
+          got->add_global(gsym, GOT_TYPE_STANDARD);
+        else
+          {
+            // If this symbol is not fully resolved, we need to add a
+            // dynamic relocation for it.
+            Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+            if (gsym->is_from_dynobj()
+                || gsym->is_undefined()
+                || gsym->is_preemptible())
+              got->add_global_with_rela(gsym, GOT_TYPE_STANDARD, rela_dyn,
+                                        elfcpp::R_SPARC_GLOB_DAT);
+            else if (!gsym->has_got_offset(GOT_TYPE_STANDARD))
+              {
+               unsigned int off = got->add_constant(0);
+
+               gsym->set_got_offset(GOT_TYPE_STANDARD, off);
+               rela_dyn->add_global_relative(gsym, elfcpp::R_SPARC_RELATIVE,
+                                             got, off, 0);
+             }
+          }
+      }
+      break;
+
+      // These are initial tls relocs, which are expected when
+      // linking.
+    case elfcpp::R_SPARC_TLS_GD_HI22: // Global-dynamic
+    case elfcpp::R_SPARC_TLS_GD_LO10:
+    case elfcpp::R_SPARC_TLS_GD_ADD:
+    case elfcpp::R_SPARC_TLS_GD_CALL:
+    case elfcpp::R_SPARC_TLS_LDM_HI22: // Local-dynamic
+    case elfcpp::R_SPARC_TLS_LDM_LO10:
+    case elfcpp::R_SPARC_TLS_LDM_ADD:
+    case elfcpp::R_SPARC_TLS_LDM_CALL:
+    case elfcpp::R_SPARC_TLS_LDO_HIX22:        // Alternate local-dynamic
+    case elfcpp::R_SPARC_TLS_LDO_LOX10:
+    case elfcpp::R_SPARC_TLS_LDO_ADD:
+    case elfcpp::R_SPARC_TLS_LE_HIX22:
+    case elfcpp::R_SPARC_TLS_LE_LOX10:
+    case elfcpp::R_SPARC_TLS_IE_HI22:  // Initial-exec
+    case elfcpp::R_SPARC_TLS_IE_LO10:
+    case elfcpp::R_SPARC_TLS_IE_LD:
+    case elfcpp::R_SPARC_TLS_IE_LDX:
+    case elfcpp::R_SPARC_TLS_IE_ADD:
+      {
+       const bool is_final = gsym->final_value_is_known();
+       const tls::Tls_optimization optimized_type
+            = optimize_tls_reloc(is_final, r_type);
+       switch (r_type)
+         {
+         case elfcpp::R_SPARC_TLS_GD_HI22: // Global-dynamic
+         case elfcpp::R_SPARC_TLS_GD_LO10:
+         case elfcpp::R_SPARC_TLS_GD_ADD:
+         case elfcpp::R_SPARC_TLS_GD_CALL:
+           if (optimized_type == tls::TLSOPT_NONE)
+             {
+                // Create a pair of GOT entries for the module index and
+                // dtv-relative offset.
+                Output_data_got<size, big_endian>* got
+                    = target->got_section(symtab, layout);
+                got->add_global_pair_with_rela(gsym, GOT_TYPE_TLS_PAIR,
+                                               target->rela_dyn_section(layout),
+                                              (size == 64 ?
+                                               elfcpp::R_SPARC_TLS_DTPMOD64 :
+                                               elfcpp::R_SPARC_TLS_DTPMOD32),
+                                              (size == 64 ?
+                                               elfcpp::R_SPARC_TLS_DTPOFF64 :
+                                               elfcpp::R_SPARC_TLS_DTPOFF32));
+
+               // Emit R_SPARC_WPLT30 against "__tls_get_addr"
+               if (r_type == elfcpp::R_SPARC_TLS_GD_CALL)
+                 generate_tls_call(symtab, layout, target);
+             }
+           else if (optimized_type == tls::TLSOPT_TO_IE)
+             {
+                // Create a GOT entry for the tp-relative offset.
+                Output_data_got<size, big_endian>* got
+                    = target->got_section(symtab, layout);
+                got->add_global_with_rela(gsym, GOT_TYPE_TLS_OFFSET,
+                                          target->rela_dyn_section(layout),
+                                         (size == 64 ?
+                                          elfcpp::R_SPARC_TLS_TPOFF64 :
+                                          elfcpp::R_SPARC_TLS_TPOFF32));
+             }
+           else if (optimized_type != tls::TLSOPT_TO_LE)
+             unsupported_reloc_global(object, r_type, gsym);
+           break;
+
+         case elfcpp::R_SPARC_TLS_LDM_HI22:    // Local-dynamic
+         case elfcpp::R_SPARC_TLS_LDM_LO10:
+         case elfcpp::R_SPARC_TLS_LDM_ADD:
+         case elfcpp::R_SPARC_TLS_LDM_CALL:
+           if (optimized_type == tls::TLSOPT_NONE)
+             {
+               // Create a GOT entry for the module index.
+               target->got_mod_index_entry(symtab, layout, object);
+
+               if (r_type == elfcpp::R_SPARC_TLS_LDM_CALL)
+                 generate_tls_call(symtab, layout, target);
+             }
+           else if (optimized_type != tls::TLSOPT_TO_LE)
+             unsupported_reloc_global(object, r_type, gsym);
+           break;
+
+         case elfcpp::R_SPARC_TLS_LDO_HIX22:   // Alternate local-dynamic
+         case elfcpp::R_SPARC_TLS_LDO_LOX10:
+         case elfcpp::R_SPARC_TLS_LDO_ADD:
+           break;
+
+         case elfcpp::R_SPARC_TLS_LE_HIX22:
+         case elfcpp::R_SPARC_TLS_LE_LOX10:
+           layout->set_has_static_tls();
+           if (parameters->options().shared())
+             {
+               Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+               rela_dyn->add_symbolless_global_addend(gsym, orig_r_type,
+                                                      output_section, object,
+                                                      data_shndx, reloc.get_r_offset(),
+                                                      0);
+             }
+           break;
+
+         case elfcpp::R_SPARC_TLS_IE_HI22:     // Initial-exec
+         case elfcpp::R_SPARC_TLS_IE_LO10:
+         case elfcpp::R_SPARC_TLS_IE_LD:
+         case elfcpp::R_SPARC_TLS_IE_LDX:
+         case elfcpp::R_SPARC_TLS_IE_ADD:
+           layout->set_has_static_tls();
+           if (optimized_type == tls::TLSOPT_NONE)
+             {
+               // Create a GOT entry for the tp-relative offset.
+               Output_data_got<size, big_endian>* got
+                 = target->got_section(symtab, layout);
+               got->add_global_with_rela(gsym, GOT_TYPE_TLS_OFFSET,
+                                         target->rela_dyn_section(layout),
+                                         (size == 64 ?
+                                          elfcpp::R_SPARC_TLS_TPOFF64 :
+                                          elfcpp::R_SPARC_TLS_TPOFF32));
+             }
+           else if (optimized_type != tls::TLSOPT_TO_LE)
+             unsupported_reloc_global(object, r_type, gsym);
+           break;
+         }
+      }
+      break;
+
+      // These are relocations which should only be seen by the
+      // dynamic linker, and should never be seen here.
+    case elfcpp::R_SPARC_COPY:
+    case elfcpp::R_SPARC_GLOB_DAT:
+    case elfcpp::R_SPARC_JMP_SLOT:
+    case elfcpp::R_SPARC_RELATIVE:
+    case elfcpp::R_SPARC_TLS_DTPMOD64:
+    case elfcpp::R_SPARC_TLS_DTPMOD32:
+    case elfcpp::R_SPARC_TLS_DTPOFF64:
+    case elfcpp::R_SPARC_TLS_DTPOFF32:
+    case elfcpp::R_SPARC_TLS_TPOFF64:
+    case elfcpp::R_SPARC_TLS_TPOFF32:
+      gold_error(_("%s: unexpected reloc %u in object file"),
+                object->name().c_str(), r_type);
+      break;
+
+    default:
+      unsupported_reloc_global(object, r_type, gsym);
+      break;
+    }
+}
+
+// Process relocations for gc.
+
+template<int size, bool big_endian>
+void
+Target_sparc<size, big_endian>::gc_process_relocs(
+                       Symbol_table* symtab,
+                       Layout* layout,
+                       Sized_relobj<size, big_endian>* object,
+                       unsigned int data_shndx,
+                       unsigned int,
+                       const unsigned char* prelocs,
+                       size_t reloc_count,
+                       Output_section* output_section,
+                       bool needs_special_offset_handling,
+                       size_t local_symbol_count,
+                       const unsigned char* plocal_symbols)
+{
+  typedef Target_sparc<size, big_endian> Sparc;
+  typedef typename Target_sparc<size, big_endian>::Scan Scan;
+
+  gold::gc_process_relocs<size, big_endian, Sparc, elfcpp::SHT_RELA, Scan,
+                         typename Target_sparc::Relocatable_size_for_reloc>(
+    symtab,
+    layout,
+    this,
+    object,
+    data_shndx,
+    prelocs,
+    reloc_count,
+    output_section,
+    needs_special_offset_handling,
+    local_symbol_count,
+    plocal_symbols);
+}
+
+// Scan relocations for a section.
+
+template<int size, bool big_endian>
+void
+Target_sparc<size, big_endian>::scan_relocs(
+                       Symbol_table* symtab,
+                       Layout* layout,
+                       Sized_relobj<size, big_endian>* object,
+                       unsigned int data_shndx,
+                       unsigned int sh_type,
+                       const unsigned char* prelocs,
+                       size_t reloc_count,
+                       Output_section* output_section,
+                       bool needs_special_offset_handling,
+                       size_t local_symbol_count,
+                       const unsigned char* plocal_symbols)
+{
+  typedef Target_sparc<size, big_endian> Sparc;
+  typedef typename Target_sparc<size, big_endian>::Scan Scan;
+
+  if (sh_type == elfcpp::SHT_REL)
+    {
+      gold_error(_("%s: unsupported REL reloc section"),
+                object->name().c_str());
+      return;
+    }
+
+  gold::scan_relocs<size, big_endian, Sparc, elfcpp::SHT_RELA, Scan>(
+    symtab,
+    layout,
+    this,
+    object,
+    data_shndx,
+    prelocs,
+    reloc_count,
+    output_section,
+    needs_special_offset_handling,
+    local_symbol_count,
+    plocal_symbols);
+}
+
+// Finalize the sections.
+
+template<int size, bool big_endian>
+void
+Target_sparc<size, big_endian>::do_finalize_sections(
+    Layout* layout,
+    const Input_objects*,
+    Symbol_table*)
+{
+  // Fill in some more dynamic tags.
+  const Reloc_section* rel_plt = (this->plt_ == NULL
+                                 ? NULL
+                                 : this->plt_->rel_plt());
+  layout->add_target_dynamic_tags(false, this->plt_, rel_plt,
+                                 this->rela_dyn_, true, true);
+
+  // Emit any relocs we saved in an attempt to avoid generating COPY
+  // relocs.
+  if (this->copy_relocs_.any_saved_relocs())
+    this->copy_relocs_.emit(this->rela_dyn_section(layout));
+}
+
+// Perform a relocation.
+
+template<int size, bool big_endian>
+inline bool
+Target_sparc<size, big_endian>::Relocate::relocate(
+                       const Relocate_info<size, big_endian>* relinfo,
+                       Target_sparc* target,
+                       Output_section*,
+                       size_t relnum,
+                       const elfcpp::Rela<size, big_endian>& rela,
+                       unsigned int r_type,
+                       const Sized_symbol<size>* gsym,
+                       const Symbol_value<size>* psymval,
+                       unsigned char* view,
+                       typename elfcpp::Elf_types<size>::Elf_Addr address,
+                       section_size_type view_size)
+{
+  r_type &= 0xff;
+
+  if (this->ignore_gd_add_)
+    {
+      if (r_type != elfcpp::R_SPARC_TLS_GD_ADD)
+       gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
+                              _("missing expected TLS relocation"));
+      else
+       {
+         this->ignore_gd_add_ = false;
+         return false;
+       }
+    }
+
+  typedef Sparc_relocate_functions<size, big_endian> Reloc;
+
+  // Pick the value to use for symbols defined in shared objects.
+  Symbol_value<size> symval;
+  if (gsym != NULL
+      && gsym->use_plt_offset(r_type == elfcpp::R_SPARC_DISP8
+                             || r_type == elfcpp::R_SPARC_DISP16
+                             || r_type == elfcpp::R_SPARC_DISP32
+                             || r_type == elfcpp::R_SPARC_DISP64
+                             || r_type == elfcpp::R_SPARC_PC_HH22
+                             || r_type == elfcpp::R_SPARC_PC_HM10
+                             || r_type == elfcpp::R_SPARC_PC_LM22
+                             || r_type == elfcpp::R_SPARC_PC10
+                             || r_type == elfcpp::R_SPARC_PC22
+                             || r_type == elfcpp::R_SPARC_WDISP30
+                             || r_type == elfcpp::R_SPARC_WDISP22
+                             || r_type == elfcpp::R_SPARC_WDISP19
+                             || r_type == elfcpp::R_SPARC_WDISP16))
+    {
+      elfcpp::Elf_Xword value;
+
+      value = target->plt_section()->address() + gsym->plt_offset();
+
+      symval.set_output_value(value);
+
+      psymval = &symval;
+    }
+
+  const Sized_relobj<size, big_endian>* object = relinfo->object;
+  const elfcpp::Elf_Xword addend = rela.get_r_addend();
+
+  // Get the GOT offset if needed.  Unlike i386 and x86_64, our GOT
+  // pointer points to the beginning, not the end, of the table.
+  // So we just use the plain offset.
+  unsigned int got_offset = 0;
+  switch (r_type)
+    {
+    case elfcpp::R_SPARC_GOTDATA_OP:
+    case elfcpp::R_SPARC_GOTDATA_OP_HIX22:
+    case elfcpp::R_SPARC_GOTDATA_OP_LOX10:
+    case elfcpp::R_SPARC_GOT10:
+    case elfcpp::R_SPARC_GOT13:
+    case elfcpp::R_SPARC_GOT22:
+      if (gsym != NULL)
+        {
+          gold_assert(gsym->has_got_offset(GOT_TYPE_STANDARD));
+          got_offset = gsym->got_offset(GOT_TYPE_STANDARD);
+        }
+      else
+        {
+          unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
+          gold_assert(object->local_has_got_offset(r_sym, GOT_TYPE_STANDARD));
+          got_offset = object->local_got_offset(r_sym, GOT_TYPE_STANDARD);
+        }
+      break;
+
+    default:
+      break;
+    }
+
+  switch (r_type)
+    {
+    case elfcpp::R_SPARC_NONE:
+    case elfcpp::R_SPARC_REGISTER:
+    case elfcpp::R_SPARC_GNU_VTINHERIT:
+    case elfcpp::R_SPARC_GNU_VTENTRY:
+      break;
+
+    case elfcpp::R_SPARC_8:
+      Relocate_functions<size, big_endian>::rela8(view, object,
+                                                 psymval, addend);
+      break;
+
+    case elfcpp::R_SPARC_16:
+      if (rela.get_r_offset() & 0x1)
+       {
+         // The assembler can sometimes emit unaligned relocations
+         // for dwarf2 cfi directives. 
+         Reloc::ua16(view, object, psymval, addend);
+       }
+      else
+       Relocate_functions<size, big_endian>::rela16(view, object,
+                                                    psymval, addend);
+      break;
+
+    case elfcpp::R_SPARC_32:
+      if (!parameters->options().output_is_position_independent())
+       {
+         if (rela.get_r_offset() & 0x3)
+           {
+             // The assembler can sometimes emit unaligned relocations
+             // for dwarf2 cfi directives. 
+             Reloc::ua32(view, object, psymval, addend);
+           }
+         else
+           Relocate_functions<size, big_endian>::rela32(view, object,
+                                                        psymval, addend);
+       }
+      break;
+
+    case elfcpp::R_SPARC_DISP8:
+      Reloc::disp8(view, object, psymval, addend, address);
+      break;
+
+    case elfcpp::R_SPARC_DISP16:
+      Reloc::disp16(view, object, psymval, addend, address);
+      break;
+
+    case elfcpp::R_SPARC_DISP32:
+      Reloc::disp32(view, object, psymval, addend, address);
+      break;
+
+    case elfcpp::R_SPARC_DISP64:
+      Reloc::disp64(view, object, psymval, addend, address);
+      break;
+
+    case elfcpp::R_SPARC_WDISP30:
+    case elfcpp::R_SPARC_WPLT30:
+      Reloc::wdisp30(view, object, psymval, addend, address);
+      break;
+
+    case elfcpp::R_SPARC_WDISP22:
+      Reloc::wdisp22(view, object, psymval, addend, address);
+      break;
+
+    case elfcpp::R_SPARC_WDISP19:
+      Reloc::wdisp19(view, object, psymval, addend, address);
+      break;
+
+    case elfcpp::R_SPARC_WDISP16:
+      Reloc::wdisp16(view, object, psymval, addend, address);
+      break;
+
+    case elfcpp::R_SPARC_HI22:
+      Reloc::hi22(view, object, psymval, addend);
+      break;
+
+    case elfcpp::R_SPARC_22:
+      Reloc::rela32_22(view, object, psymval, addend);
+      break;
+
+    case elfcpp::R_SPARC_13:
+      Reloc::rela32_13(view, object, psymval, addend);
+      break;
+
+    case elfcpp::R_SPARC_LO10:
+      Reloc::lo10(view, object, psymval, addend);
+      break;
+
+    case elfcpp::R_SPARC_GOT10:
+      Reloc::lo10(view, got_offset, addend);
+      break;
+
+    case elfcpp::R_SPARC_GOTDATA_OP:
+      break;
+
+    case elfcpp::R_SPARC_GOTDATA_OP_LOX10:
+    case elfcpp::R_SPARC_GOT13:
+      Reloc::rela32_13(view, got_offset, addend);
+      break;
+
+    case elfcpp::R_SPARC_GOTDATA_OP_HIX22:
+    case elfcpp::R_SPARC_GOT22:
+      Reloc::hi22(view, got_offset, addend);
+      break;
+
+    case elfcpp::R_SPARC_PC10:
+      Reloc::pc10(view, object, psymval, addend, address);
+      break;
+
+    case elfcpp::R_SPARC_PC22:
+      Reloc::pc22(view, object, psymval, addend, address);
+      break;
+
+    case elfcpp::R_SPARC_TLS_DTPOFF32:
+    case elfcpp::R_SPARC_UA32:
+      Reloc::ua32(view, object, psymval, addend);
+      break;
+
+    case elfcpp::R_SPARC_PLT64:
+      Relocate_functions<size, big_endian>::rela64(view, object,
+                                                  psymval, addend);
+      break;
+
+    case elfcpp::R_SPARC_PLT32:
+      Relocate_functions<size, big_endian>::rela32(view, object,
+                                                  psymval, addend);
+      break;
+
+    case elfcpp::R_SPARC_HIPLT22:
+      Reloc::hi22(view, object, psymval, addend);
+      break;
+
+    case elfcpp::R_SPARC_LOPLT10:
+      Reloc::lo10(view, object, psymval, addend);
+      break;
+
+    case elfcpp::R_SPARC_PCPLT32:
+      Reloc::disp32(view, object, psymval, addend, address);
+      break;
+
+    case elfcpp::R_SPARC_PCPLT22:
+      Reloc::pcplt22(view, object, psymval, addend, address);
+      break;
+
+    case elfcpp::R_SPARC_PCPLT10:
+      Reloc::lo10(view, object, psymval, addend, address);
+      break;
+
+    case elfcpp::R_SPARC_64:
+      if (!parameters->options().output_is_position_independent())
+       {
+         if (rela.get_r_offset() & 0x7)
+           {
+             // The assembler can sometimes emit unaligned relocations
+             // for dwarf2 cfi directives. 
+             Reloc::ua64(view, object, psymval, addend);
+           }
+         else
+           Relocate_functions<size, big_endian>::rela64(view, object,
+                                                        psymval, addend);
+       }
+      break;
+
+    case elfcpp::R_SPARC_OLO10:
+      {
+       unsigned int addend2 = rela.get_r_info() & 0xffffffff;
+       addend2 = ((addend2 >> 8) ^ 0x800000) - 0x800000;
+       Reloc::olo10(view, object, psymval, addend, addend2);
+      }
+      break;
+
+    case elfcpp::R_SPARC_HH22:
+      Reloc::hh22(view, object, psymval, addend);
+      break;
+
+    case elfcpp::R_SPARC_PC_HH22:
+      Reloc::pc_hh22(view, object, psymval, addend, address);
+      break;
+
+    case elfcpp::R_SPARC_HM10:
+      Reloc::hm10(view, object, psymval, addend);
+      break;
+
+    case elfcpp::R_SPARC_PC_HM10:
+      Reloc::pc_hm10(view, object, psymval, addend, address);
+      break;
+
+    case elfcpp::R_SPARC_LM22:
+      Reloc::hi22(view, object, psymval, addend);
+      break;
+
+    case elfcpp::R_SPARC_PC_LM22:
+      Reloc::pcplt22(view, object, psymval, addend, address);
+      break;
+
+    case elfcpp::R_SPARC_11:
+      Reloc::rela32_11(view, object, psymval, addend);
+      break;
+
+    case elfcpp::R_SPARC_10:
+      Reloc::rela32_10(view, object, psymval, addend);
+      break;
+
+    case elfcpp::R_SPARC_7:
+      Reloc::rela32_7(view, object, psymval, addend);
+      break;
+
+    case elfcpp::R_SPARC_6:
+      Reloc::rela32_6(view, object, psymval, addend);
+      break;
+
+    case elfcpp::R_SPARC_5:
+      Reloc::rela32_5(view, object, psymval, addend);
+      break;
+
+    case elfcpp::R_SPARC_HIX22:
+      Reloc::hix22(view, object, psymval, addend);
+      break;
+
+    case elfcpp::R_SPARC_LOX10:
+      Reloc::lox10(view, object, psymval, addend);
+      break;
+
+    case elfcpp::R_SPARC_H44:
+      Reloc::h44(view, object, psymval, addend);
+      break;
+
+    case elfcpp::R_SPARC_M44:
+      Reloc::m44(view, object, psymval, addend);
+      break;
+
+    case elfcpp::R_SPARC_L44:
+      Reloc::l44(view, object, psymval, addend);
+      break;
+
+    case elfcpp::R_SPARC_TLS_DTPOFF64:
+    case elfcpp::R_SPARC_UA64:
+      Reloc::ua64(view, object, psymval, addend);
+      break;
+
+    case elfcpp::R_SPARC_UA16:
+      Reloc::ua16(view, object, psymval, addend);
+      break;
+
+    case elfcpp::R_SPARC_TLS_GD_HI22:
+    case elfcpp::R_SPARC_TLS_GD_LO10:
+    case elfcpp::R_SPARC_TLS_GD_ADD:
+    case elfcpp::R_SPARC_TLS_GD_CALL:
+    case elfcpp::R_SPARC_TLS_LDM_HI22:
+    case elfcpp::R_SPARC_TLS_LDM_LO10:
+    case elfcpp::R_SPARC_TLS_LDM_ADD:
+    case elfcpp::R_SPARC_TLS_LDM_CALL:
+    case elfcpp::R_SPARC_TLS_LDO_HIX22:
+    case elfcpp::R_SPARC_TLS_LDO_LOX10:
+    case elfcpp::R_SPARC_TLS_LDO_ADD:
+    case elfcpp::R_SPARC_TLS_IE_HI22:
+    case elfcpp::R_SPARC_TLS_IE_LO10:
+    case elfcpp::R_SPARC_TLS_IE_LD:
+    case elfcpp::R_SPARC_TLS_IE_LDX:
+    case elfcpp::R_SPARC_TLS_IE_ADD:
+    case elfcpp::R_SPARC_TLS_LE_HIX22:
+    case elfcpp::R_SPARC_TLS_LE_LOX10:
+      this->relocate_tls(relinfo, target, relnum, rela,
+                        r_type, gsym, psymval, view,
+                        address, view_size);
+      break;
+
+    case elfcpp::R_SPARC_COPY:
+    case elfcpp::R_SPARC_GLOB_DAT:
+    case elfcpp::R_SPARC_JMP_SLOT:
+    case elfcpp::R_SPARC_RELATIVE:
+      // These are outstanding tls relocs, which are unexpected when
+      // linking.
+    case elfcpp::R_SPARC_TLS_DTPMOD64:
+    case elfcpp::R_SPARC_TLS_DTPMOD32:
+    case elfcpp::R_SPARC_TLS_TPOFF64:
+    case elfcpp::R_SPARC_TLS_TPOFF32:
+      gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
+                            _("unexpected reloc %u in object file"),
+                            r_type);
+      break;
+
+    default:
+      gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
+                            _("unsupported reloc %u"),
+                            r_type);
+      break;
+    }
+
+  return true;
+}
+
+// Perform a TLS relocation.
+
+template<int size, bool big_endian>
+inline void
+Target_sparc<size, big_endian>::Relocate::relocate_tls(
+                       const Relocate_info<size, big_endian>* relinfo,
+                       Target_sparc<size, big_endian>* target,
+                       size_t relnum,
+                       const elfcpp::Rela<size, big_endian>& rela,
+                       unsigned int r_type,
+                       const Sized_symbol<size>* gsym,
+                       const Symbol_value<size>* psymval,
+                       unsigned char* view,
+                       typename elfcpp::Elf_types<size>::Elf_Addr address,
+                       section_size_type)
+{
+  Output_segment* tls_segment = relinfo->layout->tls_segment();
+  typedef Sparc_relocate_functions<size, big_endian> Reloc;
+  const Sized_relobj<size, big_endian>* object = relinfo->object;
+  typedef typename elfcpp::Swap<32, true>::Valtype Insntype;
+
+  const elfcpp::Elf_Xword addend = rela.get_r_addend();
+  typename elfcpp::Elf_types<size>::Elf_Addr value = psymval->value(object, 0);
+
+  const bool is_final =
+    (gsym == NULL
+     ? !parameters->options().output_is_position_independent()
+     : gsym->final_value_is_known());
+  const tls::Tls_optimization optimized_type
+      = optimize_tls_reloc(is_final, r_type);
+
+  switch (r_type)
+    {
+    case elfcpp::R_SPARC_TLS_GD_HI22:
+    case elfcpp::R_SPARC_TLS_GD_LO10:
+    case elfcpp::R_SPARC_TLS_GD_ADD:
+    case elfcpp::R_SPARC_TLS_GD_CALL:
+      if (optimized_type == tls::TLSOPT_TO_LE)
+       {
+         Insntype* wv = reinterpret_cast<Insntype*>(view);
+         Insntype val;
+
+         value -= tls_segment->memsz();
+
+         switch (r_type)
+           {
+           case elfcpp::R_SPARC_TLS_GD_HI22:
+             // TLS_GD_HI22 --> TLS_LE_HIX22
+             Reloc::hix22(view, value, addend);
+             break;
+
+           case elfcpp::R_SPARC_TLS_GD_LO10:
+             // TLS_GD_LO10 --> TLS_LE_LOX10
+             Reloc::lox10(view, value, addend);
+             break;
+
+           case elfcpp::R_SPARC_TLS_GD_ADD:
+             // add %reg1, %reg2, %reg3 --> mov %g7, %reg2, %reg3
+             val = elfcpp::Swap<32, true>::readval(wv);
+             val = (val & ~0x7c000) | 0x1c000;
+             elfcpp::Swap<32, true>::writeval(wv, val);
+             break;
+           case elfcpp::R_SPARC_TLS_GD_CALL:
+             // call __tls_get_addr --> nop
+             elfcpp::Swap<32, true>::writeval(wv, sparc_nop);
+             break;
+           }
+         break;
+       }
+      else
+        {
+          unsigned int got_type = (optimized_type == tls::TLSOPT_TO_IE
+                                   ? GOT_TYPE_TLS_OFFSET
+                                   : GOT_TYPE_TLS_PAIR);
+          if (gsym != NULL)
+            {
+              gold_assert(gsym->has_got_offset(got_type));
+              value = gsym->got_offset(got_type);
+            }
+          else
+            {
+              unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
+              gold_assert(object->local_has_got_offset(r_sym, got_type));
+              value = object->local_got_offset(r_sym, got_type);
+            }
+          if (optimized_type == tls::TLSOPT_TO_IE)
+           {
+             Insntype* wv = reinterpret_cast<Insntype*>(view);
+             Insntype val;
+
+             switch (r_type)
+               {
+               case elfcpp::R_SPARC_TLS_GD_HI22:
+                 // TLS_GD_HI22 --> TLS_IE_HI22
+                 Reloc::hi22(view, value, addend);
+                 break;
+
+               case elfcpp::R_SPARC_TLS_GD_LO10:
+                 // TLS_GD_LO10 --> TLS_IE_LO10
+                 Reloc::lo10(view, value, addend);
+                 break;
+
+               case elfcpp::R_SPARC_TLS_GD_ADD:
+                 // add %reg1, %reg2, %reg3 --> ld [%reg1 + %reg2], %reg3
+                 val = elfcpp::Swap<32, true>::readval(wv);
+
+                 if (size == 64)
+                   val |= 0xc0580000;
+                 else
+                   val |= 0xc0000000;
+
+                 elfcpp::Swap<32, true>::writeval(wv, val);
+                 break;
+
+               case elfcpp::R_SPARC_TLS_GD_CALL:
+                 // The compiler can put the TLS_GD_ADD instruction
+                 // into the delay slot of the call.  If so, we need
+                 // to transpose the two instructions so that the
+                 // the new sequence works properly.
+                 //
+                 // The test we use is if the instruction in the
+                 // delay slot is an add with destination register
+                 // equal to %o0
+                 val = elfcpp::Swap<32, true>::readval(wv + 1);
+                 if ((val & 0x81f80000) == 0x80000000
+                     && ((val >> 25) & 0x1f) == 0x8)
+                   {
+                     if (size == 64)
+                       val |= 0xc0580000;
+                     else
+                       val |= 0xc0000000;
+
+                     elfcpp::Swap<32, true>::writeval(wv, val);
+
+                     wv += 1;
+                     this->ignore_gd_add_ = true;
+                   }
+
+                 // call __tls_get_addr --> add %g7, %o0, %o0
+                 elfcpp::Swap<32, true>::writeval(wv, 0x9001c008);
+                 break;
+               }
+              break;
+           }
+          else if (optimized_type == tls::TLSOPT_NONE)
+            {
+             switch (r_type)
+               {
+               case elfcpp::R_SPARC_TLS_GD_HI22:
+                 Reloc::hi22(view, value, addend);
+                 break;
+               case elfcpp::R_SPARC_TLS_GD_LO10:
+                 Reloc::lo10(view, value, addend);
+                 break;
+               case elfcpp::R_SPARC_TLS_GD_ADD:
+                 break;
+               case elfcpp::R_SPARC_TLS_GD_CALL:
+                 {
+                   Symbol_value<size> symval;
+                   elfcpp::Elf_Xword value;
+                   Symbol* tsym;
+
+                   tsym = target->tls_get_addr_sym_;
+                   gold_assert(tsym);
+                   value = (target->plt_section()->address() +
+                            tsym->plt_offset());
+                   symval.set_output_value(value);
+                   Reloc::wdisp30(view, object, &symval, addend, address);
+                 }
+                 break;
+               }
+             break;
+            }
+        }
+      gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
+                            _("unsupported reloc %u"),
+                            r_type);
+      break;
+
+    case elfcpp::R_SPARC_TLS_LDM_HI22:
+    case elfcpp::R_SPARC_TLS_LDM_LO10:
+    case elfcpp::R_SPARC_TLS_LDM_ADD:
+    case elfcpp::R_SPARC_TLS_LDM_CALL:
+      if (optimized_type == tls::TLSOPT_TO_LE)
+       {
+         Insntype* wv = reinterpret_cast<Insntype*>(view);
+
+         switch (r_type)
+           {
+           case elfcpp::R_SPARC_TLS_LDM_HI22:
+           case elfcpp::R_SPARC_TLS_LDM_LO10:
+           case elfcpp::R_SPARC_TLS_LDM_ADD:
+             elfcpp::Swap<32, true>::writeval(wv, sparc_nop);
+             break;
+
+           case elfcpp::R_SPARC_TLS_LDM_CALL:
+             elfcpp::Swap<32, true>::writeval(wv, sparc_mov_g0_o0);
+             break;
+           }
+         break;
+       }
+      else if (optimized_type == tls::TLSOPT_NONE)
+        {
+          // Relocate the field with the offset of the GOT entry for
+          // the module index.
+          unsigned int got_offset;
+
+         got_offset = target->got_mod_index_entry(NULL, NULL, NULL);
+         switch (r_type)
+           {
+           case elfcpp::R_SPARC_TLS_LDM_HI22:
+             Reloc::hi22(view, got_offset, addend);
+             break;
+           case elfcpp::R_SPARC_TLS_LDM_LO10:
+             Reloc::lo10(view, got_offset, addend);
+             break;
+           case elfcpp::R_SPARC_TLS_LDM_ADD:
+             break;
+           case elfcpp::R_SPARC_TLS_LDM_CALL:
+             {
+               Symbol_value<size> symval;
+               elfcpp::Elf_Xword value;
+               Symbol* tsym;
+
+               tsym = target->tls_get_addr_sym_;
+               gold_assert(tsym);
+               value = (target->plt_section()->address() +
+                        tsym->plt_offset());
+               symval.set_output_value(value);
+               Reloc::wdisp30(view, object, &symval, addend, address);
+             }
+             break;
+           }
+          break;
+        }
+      gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
+                            _("unsupported reloc %u"),
+                            r_type);
+      break;
+
+      // These relocs can appear in debugging sections, in which case
+      // we won't see the TLS_LDM relocs.  The local_dynamic_type
+      // field tells us this.
+    case elfcpp::R_SPARC_TLS_LDO_HIX22:
+      if (optimized_type == tls::TLSOPT_TO_LE)
+       {
+         value -= tls_segment->memsz();
+         Reloc::hix22(view, value, addend);
+       }
+      else
+       Reloc::ldo_hix22(view, value, addend);
+      break;
+    case elfcpp::R_SPARC_TLS_LDO_LOX10:
+      if (optimized_type == tls::TLSOPT_TO_LE)
+       {
+         value -= tls_segment->memsz();
+         Reloc::lox10(view, value, addend);
+       }
+      else
+       Reloc::ldo_lox10(view, value, addend);
+      break;
+    case elfcpp::R_SPARC_TLS_LDO_ADD:
+      if (optimized_type == tls::TLSOPT_TO_LE)
+       {
+         Insntype* wv = reinterpret_cast<Insntype*>(view);
+         Insntype val;
+
+         // add %reg1, %reg2, %reg3 --> add %g7, %reg2, %reg3
+         val = elfcpp::Swap<32, true>::readval(wv);
+         val = (val & ~0x7c000) | 0x1c000;
+         elfcpp::Swap<32, true>::writeval(wv, val);
+       }
+      break;
+
+      // When optimizing IE --> LE, the only relocation that is handled
+      // differently is R_SPARC_TLS_IE_LD, it is rewritten from
+      // 'ld{,x} [rs1 + rs2], rd' into 'mov rs2, rd' or simply a NOP is
+      // rs2 and rd are the same.
+    case elfcpp::R_SPARC_TLS_IE_LD:
+    case elfcpp::R_SPARC_TLS_IE_LDX:
+      if (optimized_type == tls::TLSOPT_TO_LE)
+       {
+         Insntype* wv = reinterpret_cast<Insntype*>(view);
+         Insntype val = elfcpp::Swap<32, true>::readval(wv);
+         Insntype rs2 = val & 0x1f;
+         Insntype rd = (val >> 25) & 0x1f;
+
+         if (rs2 == rd)
+           val = sparc_nop;
+         else
+           val = sparc_mov | (val & 0x3e00001f);
+
+         elfcpp::Swap<32, true>::writeval(wv, val);
+       }
+      break;
+
+    case elfcpp::R_SPARC_TLS_IE_HI22:
+    case elfcpp::R_SPARC_TLS_IE_LO10:
+      if (optimized_type == tls::TLSOPT_TO_LE)
+       {
+         value -= tls_segment->memsz();
+         switch (r_type)
+           {
+           case elfcpp::R_SPARC_TLS_IE_HI22:
+             // IE_HI22 --> LE_HIX22
+             Reloc::hix22(view, value, addend);
+             break;
+           case elfcpp::R_SPARC_TLS_IE_LO10:
+             // IE_LO10 --> LE_LOX10
+             Reloc::lox10(view, value, addend);
+             break;
+           }
+         break;
+       }
+      else if (optimized_type == tls::TLSOPT_NONE)
+       {
+         // Relocate the field with the offset of the GOT entry for
+         // the tp-relative offset of the symbol.
+         if (gsym != NULL)
+           {
+             gold_assert(gsym->has_got_offset(GOT_TYPE_TLS_OFFSET));
+             value = gsym->got_offset(GOT_TYPE_TLS_OFFSET);
+           }
+         else
+           {
+             unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
+             gold_assert(object->local_has_got_offset(r_sym,
+                                                      GOT_TYPE_TLS_OFFSET));
+             value = object->local_got_offset(r_sym,
+                                              GOT_TYPE_TLS_OFFSET);
+           }
+         switch (r_type)
+           {
+           case elfcpp::R_SPARC_TLS_IE_HI22:
+             Reloc::hi22(view, value, addend);
+             break;
+           case elfcpp::R_SPARC_TLS_IE_LO10:
+             Reloc::lo10(view, value, addend);
+             break;
+           }
+         break;
+       }
+      gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
+                            _("unsupported reloc %u"),
+                            r_type);
+      break;
+
+    case elfcpp::R_SPARC_TLS_IE_ADD:
+      // This seems to be mainly so that we can find the addition
+      // instruction if there is one.  There doesn't seem to be any
+      // actual relocation to apply.
+      break;
+
+    case elfcpp::R_SPARC_TLS_LE_HIX22:
+      // If we're creating a shared library, a dynamic relocation will
+      // have been created for this location, so do not apply it now.
+      if (!parameters->options().shared())
+       {
+         value -= tls_segment->memsz();
+         Reloc::hix22(view, value, addend);
+       }
+      break;
+
+    case elfcpp::R_SPARC_TLS_LE_LOX10:
+      // If we're creating a shared library, a dynamic relocation will
+      // have been created for this location, so do not apply it now.
+      if (!parameters->options().shared())
+       {
+         value -= tls_segment->memsz();
+         Reloc::lox10(view, value, addend);
+       }
+      break;
+    }
+}
+
+// Relocate section data.
+
+template<int size, bool big_endian>
+void
+Target_sparc<size, big_endian>::relocate_section(
+                       const Relocate_info<size, big_endian>* relinfo,
+                       unsigned int sh_type,
+                       const unsigned char* prelocs,
+                       size_t reloc_count,
+                       Output_section* output_section,
+                       bool needs_special_offset_handling,
+                       unsigned char* view,
+                       typename elfcpp::Elf_types<size>::Elf_Addr address,
+                       section_size_type view_size,
+                       const Reloc_symbol_changes* reloc_symbol_changes)
+{
+  typedef Target_sparc<size, big_endian> Sparc;
+  typedef typename Target_sparc<size, big_endian>::Relocate Sparc_relocate;
+
+  gold_assert(sh_type == elfcpp::SHT_RELA);
+
+  gold::relocate_section<size, big_endian, Sparc, elfcpp::SHT_RELA,
+    Sparc_relocate>(
+    relinfo,
+    this,
+    prelocs,
+    reloc_count,
+    output_section,
+    needs_special_offset_handling,
+    view,
+    address,
+    view_size,
+    reloc_symbol_changes);
+}
+
+// Return the size of a relocation while scanning during a relocatable
+// link.
+
+template<int size, bool big_endian>
+unsigned int
+Target_sparc<size, big_endian>::Relocatable_size_for_reloc::get_size_for_reloc(
+    unsigned int,
+    Relobj*)
+{
+  // We are always SHT_RELA, so we should never get here.
+  gold_unreachable();
+  return 0;
+}
+
+// Scan the relocs during a relocatable link.
+
+template<int size, bool big_endian>
+void
+Target_sparc<size, big_endian>::scan_relocatable_relocs(
+                       Symbol_table* symtab,
+                       Layout* layout,
+                       Sized_relobj<size, big_endian>* object,
+                       unsigned int data_shndx,
+                       unsigned int sh_type,
+                       const unsigned char* prelocs,
+                       size_t reloc_count,
+                       Output_section* output_section,
+                       bool needs_special_offset_handling,
+                       size_t local_symbol_count,
+                       const unsigned char* plocal_symbols,
+                       Relocatable_relocs* rr)
+{
+  gold_assert(sh_type == elfcpp::SHT_RELA);
+
+  typedef gold::Default_scan_relocatable_relocs<elfcpp::SHT_RELA,
+    Relocatable_size_for_reloc> Scan_relocatable_relocs;
+
+  gold::scan_relocatable_relocs<size, big_endian, elfcpp::SHT_RELA,
+      Scan_relocatable_relocs>(
+    symtab,
+    layout,
+    object,
+    data_shndx,
+    prelocs,
+    reloc_count,
+    output_section,
+    needs_special_offset_handling,
+    local_symbol_count,
+    plocal_symbols,
+    rr);
+}
+
+// Relocate a section during a relocatable link.
+
+template<int size, bool big_endian>
+void
+Target_sparc<size, big_endian>::relocate_for_relocatable(
+    const Relocate_info<size, big_endian>* relinfo,
+    unsigned int sh_type,
+    const unsigned char* prelocs,
+    size_t reloc_count,
+    Output_section* output_section,
+    off_t offset_in_output_section,
+    const Relocatable_relocs* rr,
+    unsigned char* view,
+    typename elfcpp::Elf_types<size>::Elf_Addr view_address,
+    section_size_type view_size,
+    unsigned char* reloc_view,
+    section_size_type reloc_view_size)
+{
+  gold_assert(sh_type == elfcpp::SHT_RELA);
+
+  gold::relocate_for_relocatable<size, big_endian, elfcpp::SHT_RELA>(
+    relinfo,
+    prelocs,
+    reloc_count,
+    output_section,
+    offset_in_output_section,
+    rr,
+    view,
+    view_address,
+    view_size,
+    reloc_view,
+    reloc_view_size);
+}
+
+// Return the value to use for a dynamic which requires special
+// treatment.  This is how we support equality comparisons of function
+// pointers across shared library boundaries, as described in the
+// processor specific ABI supplement.
+
+template<int size, bool big_endian>
+uint64_t
+Target_sparc<size, big_endian>::do_dynsym_value(const Symbol* gsym) const
+{
+  gold_assert(gsym->is_from_dynobj() && gsym->has_plt_offset());
+  return this->plt_section()->address() + gsym->plt_offset();
+}
+
+// The selector for sparc object files.
+
+template<int size, bool big_endian>
+class Target_selector_sparc : public Target_selector
+{
+public:
+  Target_selector_sparc()
+    : Target_selector(elfcpp::EM_NONE, size, big_endian,
+                     (size == 64 ? "elf64-sparc" : "elf32-sparc"))
+  { }
+
+  Target* do_recognize(int machine, int, int)
+  {
+    switch (size)
+      {
+      case 64:
+       if (machine != elfcpp::EM_SPARCV9)
+         return NULL;
+       break;
+
+      case 32:
+       if (machine != elfcpp::EM_SPARC
+           && machine != elfcpp::EM_SPARC32PLUS)
+         return NULL;
+       break;
+
+      default:
+       return NULL;
+      }
+
+    return this->instantiate_target();
+  }
+
+  Target* do_instantiate_target()
+  { return new Target_sparc<size, big_endian>(); }
+};
+
+Target_selector_sparc<32, true> target_selector_sparc32;
+Target_selector_sparc<64, true> target_selector_sparc64;
+
+} // End anonymous namespace.
diff --git a/contrib/binutils-2.21/include/plugin-api.h b/contrib/binutils-2.21/include/plugin-api.h
new file mode 100644 (file)
index 0000000..9d58fef
--- /dev/null
@@ -0,0 +1,308 @@
+/* plugin-api.h -- External linker plugin API.  */
+
+/* Copyright 2009 Free Software Foundation, Inc.
+   Written by Cary Coutant <ccoutant@google.com>.
+
+   This file is part of 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.  */
+
+/* This file defines the interface for writing a linker plugin, which is
+   described at < http://gcc.gnu.org/wiki/whopr/driver >.  */
+
+#ifndef PLUGIN_API_H
+#define PLUGIN_API_H
+
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#elif defined(HAVE_INTTYPES_H)
+#include <inttypes.h>
+#endif
+#include <sys/types.h>
+#if !defined(HAVE_STDINT_H) && !defined(HAVE_INTTYPES_H) && \
+    !defined(UINT64_MAX) && !defined(uint64_t)
+#error can not find uint64_t type
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* Status code returned by most API routines.  */
+
+enum ld_plugin_status
+{
+  LDPS_OK = 0,
+  LDPS_NO_SYMS,         /* Attempt to get symbols that haven't been added. */
+  LDPS_BAD_HANDLE,      /* No claimed object associated with given handle. */
+  LDPS_ERR
+  /* Additional Error codes TBD.  */
+};
+
+/* The version of the API specification.  */
+
+enum ld_plugin_api_version
+{
+  LD_PLUGIN_API_VERSION = 1
+};
+
+/* The type of output file being generated by the linker.  */
+
+enum ld_plugin_output_file_type
+{
+  LDPO_REL,
+  LDPO_EXEC,
+  LDPO_DYN
+};
+
+/* An input file managed by the plugin library.  */
+
+struct ld_plugin_input_file
+{
+  const char *name;
+  int fd;
+  off_t offset;
+  off_t filesize;
+  void *handle;
+};
+
+/* A symbol belonging to an input file managed by the plugin library.  */
+
+struct ld_plugin_symbol
+{
+  char *name;
+  char *version;
+  int def;
+  int visibility;
+  uint64_t size;
+  char *comdat_key;
+  int resolution;
+};
+
+/* Whether the symbol is a definition, reference, or common, weak or not.  */
+
+enum ld_plugin_symbol_kind
+{
+  LDPK_DEF,
+  LDPK_WEAKDEF,
+  LDPK_UNDEF,
+  LDPK_WEAKUNDEF,
+  LDPK_COMMON
+};
+
+/* The visibility of the symbol.  */
+
+enum ld_plugin_symbol_visibility
+{
+  LDPV_DEFAULT,
+  LDPV_PROTECTED,
+  LDPV_INTERNAL,
+  LDPV_HIDDEN
+};
+
+/* How a symbol is resolved.  */
+
+enum ld_plugin_symbol_resolution
+{
+  LDPR_UNKNOWN = 0,
+
+  /* Symbol is still undefined at this point.  */
+  LDPR_UNDEF,
+
+  /* This is the prevailing definition of the symbol, with references from
+     regular object code.  */
+  LDPR_PREVAILING_DEF,
+
+  /* This is the prevailing definition of the symbol, with no
+     references from regular objects.  It is only referenced from IR
+     code.  */
+  LDPR_PREVAILING_DEF_IRONLY,
+
+  /* This definition was pre-empted by a definition in a regular
+     object file.  */
+  LDPR_PREEMPTED_REG,
+
+  /* This definition was pre-empted by a definition in another IR file.  */
+  LDPR_PREEMPTED_IR,
+
+  /* This symbol was resolved by a definition in another IR file.  */
+  LDPR_RESOLVED_IR,
+
+  /* This symbol was resolved by a definition in a regular object
+     linked into the main executable.  */
+  LDPR_RESOLVED_EXEC,
+
+  /* This symbol was resolved by a definition in a shared object.  */
+  LDPR_RESOLVED_DYN
+};
+
+/* The plugin library's "claim file" handler.  */
+
+typedef
+enum ld_plugin_status
+(*ld_plugin_claim_file_handler) (
+  const struct ld_plugin_input_file *file, int *claimed);
+
+/* The plugin library's "all symbols read" handler.  */
+
+typedef
+enum ld_plugin_status
+(*ld_plugin_all_symbols_read_handler) (void);
+
+/* The plugin library's cleanup handler.  */
+
+typedef
+enum ld_plugin_status
+(*ld_plugin_cleanup_handler) (void);
+
+/* The linker's interface for registering the "claim file" handler.  */
+
+typedef
+enum ld_plugin_status
+(*ld_plugin_register_claim_file) (ld_plugin_claim_file_handler handler);
+
+/* The linker's interface for registering the "all symbols read" handler.  */
+
+typedef
+enum ld_plugin_status
+(*ld_plugin_register_all_symbols_read) (
+  ld_plugin_all_symbols_read_handler handler);
+
+/* The linker's interface for registering the cleanup handler.  */
+
+typedef
+enum ld_plugin_status
+(*ld_plugin_register_cleanup) (ld_plugin_cleanup_handler handler);
+
+/* The linker's interface for adding symbols from a claimed input file.  */
+
+typedef
+enum ld_plugin_status
+(*ld_plugin_add_symbols) (void *handle, int nsyms,
+                          const struct ld_plugin_symbol *syms);
+
+/* The linker's interface for getting the input file information with
+   an open (possibly re-opened) file descriptor.  */
+
+typedef
+enum ld_plugin_status
+(*ld_plugin_get_input_file) (const void *handle,
+                             struct ld_plugin_input_file *file);
+
+/* The linker's interface for releasing the input file.  */
+
+typedef
+enum ld_plugin_status
+(*ld_plugin_release_input_file) (const void *handle);
+
+/* The linker's interface for retrieving symbol resolution information.  */
+
+typedef
+enum ld_plugin_status
+(*ld_plugin_get_symbols) (const void *handle, int nsyms,
+                          struct ld_plugin_symbol *syms);
+
+/* The linker's interface for adding a compiled input file.  */
+
+typedef
+enum ld_plugin_status
+(*ld_plugin_add_input_file) (const char *pathname);
+
+/* The linker's interface for adding a library that should be searched.  */
+
+typedef
+enum ld_plugin_status
+(*ld_plugin_add_input_library) (const char *libname);
+
+/* The linker's interface for adding a library path that should be searched.  */
+
+typedef
+enum ld_plugin_status
+(*ld_plugin_set_extra_library_path) (const char *path);
+
+/* The linker's interface for issuing a warning or error message.  */
+
+typedef
+enum ld_plugin_status
+(*ld_plugin_message) (int level, const char *format, ...);
+
+enum ld_plugin_level
+{
+  LDPL_INFO,
+  LDPL_WARNING,
+  LDPL_ERROR,
+  LDPL_FATAL
+};
+
+/* Values for the tv_tag field of the transfer vector.  */
+
+enum ld_plugin_tag
+{
+  LDPT_NULL = 0,
+  LDPT_API_VERSION,
+  LDPT_GOLD_VERSION,
+  LDPT_LINKER_OUTPUT,
+  LDPT_OPTION,
+  LDPT_REGISTER_CLAIM_FILE_HOOK,
+  LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK,
+  LDPT_REGISTER_CLEANUP_HOOK,
+  LDPT_ADD_SYMBOLS,
+  LDPT_GET_SYMBOLS,
+  LDPT_ADD_INPUT_FILE,
+  LDPT_MESSAGE,
+  LDPT_GET_INPUT_FILE,
+  LDPT_RELEASE_INPUT_FILE,
+  LDPT_ADD_INPUT_LIBRARY,
+  LDPT_OUTPUT_NAME,
+  LDPT_SET_EXTRA_LIBRARY_PATH,
+  LDPT_GNU_LD_VERSION
+};
+
+/* The plugin transfer vector.  */
+
+struct ld_plugin_tv
+{
+  enum ld_plugin_tag tv_tag;
+  union
+  {
+    int tv_val;
+    const char *tv_string;
+    ld_plugin_register_claim_file tv_register_claim_file;
+    ld_plugin_register_all_symbols_read tv_register_all_symbols_read;
+    ld_plugin_register_cleanup tv_register_cleanup;
+    ld_plugin_add_symbols tv_add_symbols;
+    ld_plugin_get_symbols tv_get_symbols;
+    ld_plugin_add_input_file tv_add_input_file;
+    ld_plugin_message tv_message;
+    ld_plugin_get_input_file tv_get_input_file;
+    ld_plugin_release_input_file tv_release_input_file;
+    ld_plugin_add_input_library tv_add_input_library;
+    ld_plugin_set_extra_library_path tv_set_extra_library_path;
+  } tv_u;
+};
+
+/* The plugin library's "onload" entry point.  */
+
+typedef
+enum ld_plugin_status
+(*ld_plugin_onload) (struct ld_plugin_tv *tv);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !defined(PLUGIN_API_H) */
diff --git a/contrib/binutils-2.21/libiberty/crc32.c b/contrib/binutils-2.21/libiberty/crc32.c
new file mode 100644 (file)
index 0000000..c12916b
--- /dev/null
@@ -0,0 +1,180 @@
+/* crc32.c
+   Copyright (C) 2009 Free Software Foundation, Inc.
+
+   This file is part of the libiberty library.
+
+   This file 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 2 of the License, or
+   (at your option) any later version.
+
+   In addition to the permissions in the GNU General Public License, the
+   Free Software Foundation gives you unlimited permission to link the
+   compiled version of this file into combinations with other programs,
+   and to distribute those combinations without any restriction coming
+   from the use of this file.  (The General Public License restrictions
+   do apply in other respects; for example, they cover modification of
+   the file, and distribution when not linked into a combined
+   executable.)
+
+   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.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "libiberty.h"
+
+/* This table was generated by the following program.  This matches
+   what gdb does.
+
+   #include <stdio.h>
+
+   int
+   main ()
+   {
+     int i, j;
+     unsigned int c;
+     int table[256];
+
+     for (i = 0; i < 256; i++)
+       {
+        for (c = i << 24, j = 8; j > 0; --j)
+          c = c & 0x80000000 ? (c << 1) ^ 0x04c11db7 : (c << 1);
+        table[i] = c;
+       }
+
+     printf ("static const unsigned int crc32_table[] =\n{\n");
+     for (i = 0; i < 256; i += 4)
+       {
+        printf ("  0x%08x, 0x%08x, 0x%08x, 0x%08x",
+                table[i + 0], table[i + 1], table[i + 2], table[i + 3]);
+        if (i + 4 < 256)
+          putchar (',');
+        putchar ('\n');
+       }
+     printf ("};\n");
+     return 0;
+   }
+
+   For more information on CRC, see, e.g.,
+   http://www.ross.net/crc/download/crc_v3.txt.  */
+
+static const unsigned int crc32_table[] =
+{
+  0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9,
+  0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,
+  0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
+  0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
+  0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9,
+  0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
+  0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011,
+  0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd,
+  0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
+  0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5,
+  0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81,
+  0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
+  0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49,
+  0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
+  0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
+  0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d,
+  0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae,
+  0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
+  0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
+  0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca,
+  0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
+  0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02,
+  0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066,
+  0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
+  0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e,
+  0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692,
+  0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
+  0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a,
+  0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
+  0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
+  0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686,
+  0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a,
+  0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
+  0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
+  0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f,
+  0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
+  0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47,
+  0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b,
+  0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
+  0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623,
+  0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7,
+  0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
+  0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f,
+  0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
+  0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
+  0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b,
+  0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f,
+  0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
+  0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
+  0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c,
+  0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
+  0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24,
+  0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30,
+  0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
+  0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088,
+  0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654,
+  0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
+  0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c,
+  0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
+  0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
+  0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0,
+  0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c,
+  0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
+  0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
+};
+
+/*
+
+@deftypefn Extension unsigned int crc32 (const unsigned char *@var{buf}, int @var{len}, unsigned int @var{init})
+
+Compute the 32-bit CRC of @var{buf} which has length @var{len}.  The
+starting value is @var{init}; this may be used to compute the CRC of
+data split across multiple buffers by passing the return value of each
+call as the @var{init} parameter of the next.
+
+This is intended to match the CRC used by the @command{gdb} remote
+protocol for the @samp{qCRC} command.  In order to get the same
+results as gdb for a block of data, you must pass the first CRC
+parameter as @code{0xffffffff}.
+
+This CRC can be specified as:
+
+  Width  : 32
+  Poly   : 0x04c11db7
+  Init   : parameter, typically 0xffffffff
+  RefIn  : false
+  RefOut : false
+  XorOut : 0
+
+This differs from the "standard" CRC-32 algorithm in that the values
+are not reflected, and there is no final XOR value.  These differences
+make it easy to compose the values of multiple blocks.
+
+@end deftypefn
+
+*/
+
+unsigned int
+xcrc32 (const unsigned char *buf, int len, unsigned int init)
+{
+  unsigned int crc = init;
+  while (len--)
+    {
+      crc = (crc << 8) ^ crc32_table[((crc >> 24) ^ *buf) & 255];
+      buf++;
+    }
+  return crc;
+}