From: Sascha Wildner Date: Wed, 23 Mar 2011 20:13:13 +0000 (+0100) Subject: binutils221: Bring in some more files on the vendor branch. X-Git-Tag: v2.11.0~188^2 X-Git-Url: https://gitweb.dragonflybsd.org/~tuxillo/dragonfly.git/commitdiff_plain/1d4a8259fb62b17e702e25146860a904e5ccaebb binutils221: Bring in some more files on the vendor branch. --- diff --git a/contrib/binutils-2.21/binutils/cxxfilt.c b/contrib/binutils-2.21/binutils/cxxfilt.c new file mode 100644 index 0000000000..770df9baf6 --- /dev/null +++ b/contrib/binutils-2.21/binutils/cxxfilt.c @@ -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, "\ + [@] Read extra options from \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 , 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 index 0000000000..cb85eeb42e --- /dev/null +++ b/contrib/binutils-2.21/elfcpp/arm.h @@ -0,0 +1,344 @@ +// arm.h -- ELF definitions specific to EM_ARM -*- C++ -*- + +// Copyright 2009, Free Software Foundation, Inc. +// Written by Doug Kwan . + +// 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 index 0000000000..2bcb3ca12e --- /dev/null +++ b/contrib/binutils-2.21/elfcpp/powerpc.h @@ -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 . + +// 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 index 0000000000..6a9193b355 --- /dev/null +++ b/contrib/binutils-2.21/elfcpp/sparc.h @@ -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 . + +// 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 index 0000000000..007653cb4e --- /dev/null +++ b/contrib/binutils-2.21/gold/arm-reloc-property.cc @@ -0,0 +1,333 @@ +// arm-reloc-property.cc -- ARM relocation property. + +// Copyright 2010 Free Software Foundation, Inc. +// Written by Doug Kwan . + +// 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 +#include +#include +#include +#include + +#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_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 index 0000000000..e7d7f50941 --- /dev/null +++ b/contrib/binutils-2.21/gold/arm-reloc-property.h @@ -0,0 +1,386 @@ +// arm-reloc-property.h -- ARM relocation properties -*- C++ -*- + +// Copyright 2010 Free Software Foundation, Inc. +// Written by Doug Kwan . + +// 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_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 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 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 index 0000000000..2caf3710d1 --- /dev/null +++ b/contrib/binutils-2.21/gold/arm-reloc.def @@ -0,0 +1,194 @@ +// arm-reloc.def -- ARM relocation definitions. + +// Copyright 2010 Free Software Foundation, Inc. +// Written by Doug Kwan . + +// 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_ 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 index 0000000000..de697357f4 --- /dev/null +++ b/contrib/binutils-2.21/gold/freebsd.h @@ -0,0 +1,168 @@ +// freebsd.h -- FreeBSD support for gold -*- C++ -*- + +// Copyright 2009 Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// 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 +class Target_freebsd : public Sized_target +{ + 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(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 +inline void +Target_freebsd::do_adjust_elf_header(unsigned char* view, + int len) const +{ + if (this->osabi_ != elfcpp::ELFOSABI_NONE) + { + gold_assert(len == elfcpp::Elf_sizes::ehdr_size); + + elfcpp::Ehdr 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 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* 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)-> + set_osabi(elfcpp::ELFOSABI_FREEBSD); + else + static_cast*>(target)-> + set_osabi(elfcpp::ELFOSABI_FREEBSD); + } + else if (this->get_size() == 64) + { + if (this->is_big_endian()) + static_cast*>(target)-> + set_osabi(elfcpp::ELFOSABI_FREEBSD); + else + static_cast*>(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 index 0000000000..49af65f8fe --- /dev/null +++ b/contrib/binutils-2.21/gold/powerpc.cc @@ -0,0 +1,2099 @@ +// powerpc.cc -- powerpc target support for gold. + +// Copyright 2008, 2009, 2010 Free Software Foundation, Inc. +// Written by David S. Miller +// and David Edelsohn + +// 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 +class Output_data_plt_powerpc; + +template +class Target_powerpc : public Sized_target +{ + public: + typedef Output_data_reloc Reloc_section; + + Target_powerpc() + : Sized_target(&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* 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* 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*, + 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::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* 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*, + 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::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* object, + unsigned int data_shndx, + Output_section* output_section, + const elfcpp::Rela& reloc, unsigned int r_type, + const elfcpp::Sym& lsym); + + inline void + global(Symbol_table* symtab, Layout* layout, Target_powerpc* target, + Sized_relobj* object, + unsigned int data_shndx, + Output_section* output_section, + const elfcpp::Rela& reloc, unsigned int r_type, + Symbol* gsym); + + inline bool + local_reloc_may_be_function_pointer(Symbol_table* , Layout* , + Target_powerpc* , + Sized_relobj* , + unsigned int , + Output_section* , + const elfcpp::Rela& , + unsigned int , + const elfcpp::Sym&) + { return false; } + + inline bool + global_reloc_may_be_function_pointer(Symbol_table* , Layout* , + Target_powerpc* , + Sized_relobj* , + unsigned int , + Output_section* , + const elfcpp::Rela& , + unsigned int , Symbol*) + { return false; } + + private: + static void + unsupported_reloc_local(Sized_relobj*, + unsigned int r_type); + + static void + unsupported_reloc_global(Sized_relobj*, + 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*, Target_powerpc*, + Output_section*, size_t relnum, + const elfcpp::Rela&, + unsigned int r_type, const Sized_symbol*, + const Symbol_value*, + unsigned char*, + typename elfcpp::Elf_types::Elf_Addr, + section_size_type); + + private: + // Do a TLS relocation. + inline void + relocate_tls(const Relocate_info*, + Target_powerpc* target, + size_t relnum, const elfcpp::Rela&, + unsigned int r_type, const Sized_symbol*, + const Symbol_value*, + unsigned char*, + typename elfcpp::Elf_types::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* + 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* object); + + // Get the PLT section. + const Output_data_plt_powerpc* + 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* object, + unsigned int shndx, Output_section* output_section, + Symbol* sym, const elfcpp::Rela& reloc) + { + this->copy_relocs_.copy_reloc(symtab, layout, + symtab->get_sized_symbol(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* got_; + // The GOT2 section. + Output_data_space* got2_; + // The TOC section. + Output_data_space* toc_; + // The PLT section. + Output_data_plt_powerpc* plt_; + // The dynamic reloc section. + Reloc_section* rela_dyn_; + // Relocs saved to avoid a COPY reloc. + Copy_relocs 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 +class Powerpc_relocate_functions +{ +private: + // Do a simple relocation with the addend in the relocation. + template + static inline void + rela(unsigned char* view, + unsigned int right_shift, + elfcpp::Elf_Xword dst_mask, + typename elfcpp::Swap::Valtype value, + typename elfcpp::Swap::Valtype addend) + { + typedef typename elfcpp::Swap::Valtype Valtype; + Valtype* wv = reinterpret_cast(view); + Valtype val = elfcpp::Swap::readval(wv); + Valtype reloc = ((value + addend) >> right_shift); + + val &= ~dst_mask; + reloc &= dst_mask; + + elfcpp::Swap::writeval(wv, val | reloc); + } + + // Do a simple relocation using a symbol value with the addend in + // the relocation. + template + static inline void + rela(unsigned char* view, + unsigned int right_shift, + elfcpp::Elf_Xword dst_mask, + const Sized_relobj* object, + const Symbol_value* psymval, + typename elfcpp::Swap::Valtype addend) + { + typedef typename elfcpp::Swap::Valtype Valtype; + Valtype* wv = reinterpret_cast(view); + Valtype val = elfcpp::Swap::readval(wv); + Valtype reloc = (psymval->value(object, addend) >> right_shift); + + val &= ~dst_mask; + reloc &= dst_mask; + + elfcpp::Swap::writeval(wv, val | reloc); + } + + // Do a simple relocation using a symbol value with the addend in + // the relocation, unaligned. + template + static inline void + rela_ua(unsigned char* view, unsigned int right_shift, + elfcpp::Elf_Xword dst_mask, + const Sized_relobj* object, + const Symbol_value* psymval, + typename elfcpp::Swap::Valtype addend) + { + typedef typename elfcpp::Swap_unaligned::Valtype Valtype; + unsigned char* wv = view; + Valtype val = elfcpp::Swap_unaligned::readval(wv); + Valtype reloc = (psymval->value(object, addend) >> right_shift); + + val &= ~dst_mask; + reloc &= dst_mask; + + elfcpp::Swap_unaligned::writeval(wv, val | reloc); + } + + // Do a simple PC relative relocation with a Symbol_value with the + // addend in the relocation. + template + static inline void + pcrela(unsigned char* view, unsigned int right_shift, + elfcpp::Elf_Xword dst_mask, + const Sized_relobj* object, + const Symbol_value* psymval, + typename elfcpp::Swap::Valtype addend, + typename elfcpp::Elf_types::Elf_Addr address) + { + typedef typename elfcpp::Swap::Valtype Valtype; + Valtype* wv = reinterpret_cast(view); + Valtype val = elfcpp::Swap::readval(wv); + Valtype reloc = ((psymval->value(object, addend) - address) + >> right_shift); + + val &= ~dst_mask; + reloc &= dst_mask; + + elfcpp::Swap::writeval(wv, val | reloc); + } + + template + static inline void + pcrela_unaligned(unsigned char* view, + const Sized_relobj* object, + const Symbol_value* psymval, + typename elfcpp::Swap::Valtype addend, + typename elfcpp::Elf_types::Elf_Addr address) + { + typedef typename elfcpp::Swap_unaligned::Valtype Valtype; + unsigned char* wv = view; + Valtype reloc = (psymval->value(object, addend) - address); + + elfcpp::Swap_unaligned::writeval(wv, reloc); + } + + typedef Powerpc_relocate_functions This; + typedef Relocate_functions This_reloc; +public: + // R_POWERPC_REL32: (Symbol + Addend - Address) + static inline void + rel32(unsigned char* view, + const Sized_relobj* object, + const Symbol_value* psymval, + typename elfcpp::Elf_types::Elf_Addr addend, + typename elfcpp::Elf_types::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* object, + const Symbol_value* psymval, + typename elfcpp::Elf_types::Elf_Addr addend, + typename elfcpp::Elf_types::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* object, + const Symbol_value* psymval, + typename elfcpp::Elf_types::Elf_Addr addend, + typename elfcpp::Elf_types::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::Elf_Addr value, + typename elfcpp::Elf_types::Elf_Addr addend) + { This_reloc::rela16(view, value, addend); } + + static inline void + addr16(unsigned char* view, + const Sized_relobj* object, + const Symbol_value* psymval, + typename elfcpp::Elf_types::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::Elf_Addr value, + typename elfcpp::Elf_types::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::Elf_Addr value, + typename elfcpp::Elf_types::Elf_Addr addend) + { This_reloc::rela16(view, value, addend); } + + static inline void + addr16_lo(unsigned char* view, + const Sized_relobj* object, + const Symbol_value* psymval, + typename elfcpp::Elf_types::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::Elf_Addr value, + typename elfcpp::Elf_types::Elf_Addr addend) + { + This::template rela<16>(view, 16, 0xffff, value, addend); + } + + static inline void + addr16_hi(unsigned char* view, + const Sized_relobj* object, + const Symbol_value* psymval, + typename elfcpp::Elf_types::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::Elf_Addr value, + typename elfcpp::Elf_types::Elf_Addr addend) + { + typename elfcpp::Elf_types::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* object, + const Symbol_value* psymval, + typename elfcpp::Elf_types::Elf_Addr addend) + { + typename elfcpp::Elf_types::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* object, + const Symbol_value* psymval, + typename elfcpp::Elf_types::Elf_Addr addend, + typename elfcpp::Elf_types::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* object, + const Symbol_value* psymval, + typename elfcpp::Elf_types::Elf_Addr addend, + typename elfcpp::Elf_types::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* object, + const Symbol_value* psymval, + typename elfcpp::Elf_types::Elf_Addr addend, + typename elfcpp::Elf_types::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* object, + const Symbol_value* psymval, + typename elfcpp::Elf_types::Elf_Addr addend, + typename elfcpp::Elf_types::Elf_Addr address) + { + typename elfcpp::Elf_types::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 +Output_data_got* +Target_powerpc::got_section(Symbol_table* symtab, + Layout* layout) +{ + if (this->got_ == NULL) + { + gold_assert(symtab != NULL && layout != NULL); + + this->got_ = new Output_data_got(); + + 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 +typename Target_powerpc::Reloc_section* +Target_powerpc::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 +class Output_data_plt_powerpc : public Output_section_data +{ + public: + typedef Output_data_reloc 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 +Output_data_plt_powerpc::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 +void +Output_data_plt_powerpc::do_adjust_output_section(Output_section* os) +{ + os->set_entsize(0); +} + +// Add an entry to the PLT. + +template +void +Output_data_plt_powerpc::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 +void +Output_data_plt_powerpc::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(pov - oview) == oview_size); + + of->write_output_view(offset, oview_size, oview); +} + +// Create a PLT entry for a global symbol. + +template +void +Target_powerpc::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(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 +unsigned int +Target_powerpc::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 +unsigned int +Target_powerpc::first_plt_entry_offset() const +{ + return Output_data_plt_powerpc::first_plt_entry_offset(); +} + +// Return the size of each PLT entry. + +template +unsigned int +Target_powerpc::plt_entry_size() const +{ + return Output_data_plt_powerpc::get_plt_entry_size(); +} + +// Create a GOT entry for the TLS module index. + +template +unsigned int +Target_powerpc::got_mod_index_entry(Symbol_table* symtab, + Layout* layout, + Sized_relobj* 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* 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 +void +Target_powerpc::Scan::unsupported_reloc_local( + Sized_relobj* 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 +void +Target_powerpc::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 +inline void +Target_powerpc::Scan::local( + Symbol_table* symtab, + Layout* layout, + Target_powerpc* target, + Sized_relobj* object, + unsigned int data_shndx, + Output_section* output_section, + const elfcpp::Rela& reloc, + unsigned int r_type, + const elfcpp::Sym& 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(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(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* got; + unsigned int r_sym; + + got = target->got_section(symtab, layout); + r_sym = elfcpp::elf_r_sym(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 +void +Target_powerpc::Scan::unsupported_reloc_global( + Sized_relobj* 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 +inline void +Target_powerpc::Scan::global( + Symbol_table* symtab, + Layout* layout, + Target_powerpc* target, + Sized_relobj* object, + unsigned int data_shndx, + Output_section* output_section, + const elfcpp::Rela& 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* 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 +void +Target_powerpc::gc_process_relocs( + Symbol_table* symtab, + Layout* layout, + Sized_relobj* 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 Powerpc; + typedef typename Target_powerpc::Scan Scan; + + gold::gc_process_relocs( + 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 +void +Target_powerpc::scan_relocs( + Symbol_table* symtab, + Layout* layout, + Sized_relobj* 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 Powerpc; + typedef typename Target_powerpc::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( + symtab, + layout, + this, + object, + data_shndx, + prelocs, + reloc_count, + output_section, + needs_special_offset_handling, + local_symbol_count, + plocal_symbols); +} + +// Finalize the sections. + +template +void +Target_powerpc::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 +inline bool +Target_powerpc::Relocate::relocate( + const Relocate_info* relinfo, + Target_powerpc* target, + Output_section*, + size_t relnum, + const elfcpp::Rela& rela, + unsigned int r_type, + const Sized_symbol* gsym, + const Symbol_value* psymval, + unsigned char* view, + typename elfcpp::Elf_types::Elf_Addr address, + section_size_type /* view_size */) +{ + const unsigned int toc_base_offset = 0x8000; + typedef Powerpc_relocate_functions Reloc; + + // Pick the value to use for symbols defined in shared objects. + Symbol_value 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* 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(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::rela64(view, object, + psymval, addend); + break; + + case elfcpp::R_POWERPC_ADDR32: + if (!parameters->options().output_is_position_independent()) + Relocate_functions::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 +inline void +Target_powerpc::Relocate::relocate_tls( + const Relocate_info* relinfo, + Target_powerpc* target, + size_t relnum, + const elfcpp::Rela& rela, + unsigned int r_type, + const Sized_symbol* gsym, + const Symbol_value* psymval, + unsigned char* view, + typename elfcpp::Elf_types::Elf_Addr address, + section_size_type) +{ + Output_segment* tls_segment = relinfo->layout->tls_segment(); + typedef Powerpc_relocate_functions Reloc; + const Sized_relobj* object = relinfo->object; + + const elfcpp::Elf_Xword addend = rela.get_r_addend(); + typename elfcpp::Elf_types::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 +void +Target_powerpc::relocate_section( + const Relocate_info* 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::Elf_Addr address, + section_size_type view_size, + const Reloc_symbol_changes* reloc_symbol_changes) +{ + typedef Target_powerpc Powerpc; + typedef typename Target_powerpc::Relocate Powerpc_relocate; + + gold_assert(sh_type == elfcpp::SHT_RELA); + + gold::relocate_section( + 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 +unsigned int +Target_powerpc::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 +void +Target_powerpc::scan_relocatable_relocs( + Symbol_table* symtab, + Layout* layout, + Sized_relobj* 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 Scan_relocatable_relocs; + + gold::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 +void +Target_powerpc::relocate_for_relocatable( + const Relocate_info* 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::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( + 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 +uint64_t +Target_powerpc::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 +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(); } +}; + +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 index 0000000000..2f8ef7a43e --- /dev/null +++ b/contrib/binutils-2.21/gold/sparc.cc @@ -0,0 +1,3412 @@ +// sparc.cc -- sparc target support for gold. + +// Copyright 2008, 2009, 2010 Free Software Foundation, Inc. +// Written by David S. Miller . + +// 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 +#include +#include + +#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 +class Output_data_plt_sparc; + +template +class Target_sparc : public Sized_target +{ + public: + typedef Output_data_reloc Reloc_section; + + Target_sparc() + : Sized_target(&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* 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* 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*, + 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::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* 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*, + 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::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* object, + unsigned int data_shndx, + Output_section* output_section, + const elfcpp::Rela& reloc, unsigned int r_type, + const elfcpp::Sym& lsym); + + inline void + global(Symbol_table* symtab, Layout* layout, Target_sparc* target, + Sized_relobj* object, + unsigned int data_shndx, + Output_section* output_section, + const elfcpp::Rela& reloc, unsigned int r_type, + Symbol* gsym); + + inline bool + local_reloc_may_be_function_pointer(Symbol_table* , Layout* , + Target_sparc* , + Sized_relobj* , + unsigned int , + Output_section* , + const elfcpp::Rela& , + unsigned int , + const elfcpp::Sym&) + { return false; } + + inline bool + global_reloc_may_be_function_pointer(Symbol_table* , Layout* , + Target_sparc* , + Sized_relobj* , + unsigned int , + Output_section* , + const elfcpp::Rela& , + unsigned int , Symbol*) + { return false; } + + + private: + static void + unsupported_reloc_local(Sized_relobj*, + unsigned int r_type); + + static void + unsupported_reloc_global(Sized_relobj*, + 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*, Target_sparc*, + Output_section*, size_t relnum, + const elfcpp::Rela&, + unsigned int r_type, const Sized_symbol*, + const Symbol_value*, + unsigned char*, + typename elfcpp::Elf_types::Elf_Addr, + section_size_type); + + private: + // Do a TLS relocation. + inline void + relocate_tls(const Relocate_info*, Target_sparc* target, + size_t relnum, const elfcpp::Rela&, + unsigned int r_type, const Sized_symbol*, + const Symbol_value*, + unsigned char*, + typename elfcpp::Elf_types::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* + 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* 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* + 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* object, + unsigned int shndx, Output_section* output_section, + Symbol* sym, const elfcpp::Rela& reloc) + { + this->copy_relocs_.copy_reloc(symtab, layout, + symtab->get_sized_symbol(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* got_; + // The PLT section. + Output_data_plt_sparc* plt_; + // The dynamic reloc section. + Reloc_section* rela_dyn_; + // Relocs saved to avoid a COPY reloc. + Copy_relocs 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 +class Sparc_relocate_functions +{ +private: + // Do a simple relocation with the addend in the relocation. + template + static inline void + rela(unsigned char* view, + unsigned int right_shift, + typename elfcpp::Elf_types::Elf_Addr dst_mask, + typename elfcpp::Swap::Valtype value, + typename elfcpp::Swap::Valtype addend) + { + typedef typename elfcpp::Swap::Valtype Valtype; + Valtype* wv = reinterpret_cast(view); + Valtype val = elfcpp::Swap::readval(wv); + Valtype reloc = ((value + addend) >> right_shift); + + val &= ~dst_mask; + reloc &= dst_mask; + + elfcpp::Swap::writeval(wv, val | reloc); + } + + // Do a simple relocation using a symbol value with the addend in + // the relocation. + template + static inline void + rela(unsigned char* view, + unsigned int right_shift, + typename elfcpp::Elf_types::Elf_Addr dst_mask, + const Sized_relobj* object, + const Symbol_value* psymval, + typename elfcpp::Swap::Valtype addend) + { + typedef typename elfcpp::Swap::Valtype Valtype; + Valtype* wv = reinterpret_cast(view); + Valtype val = elfcpp::Swap::readval(wv); + Valtype reloc = (psymval->value(object, addend) >> right_shift); + + val &= ~dst_mask; + reloc &= dst_mask; + + elfcpp::Swap::writeval(wv, val | reloc); + } + + // Do a simple relocation using a symbol value with the addend in + // the relocation, unaligned. + template + static inline void + rela_ua(unsigned char* view, + unsigned int right_shift, elfcpp::Elf_Xword dst_mask, + const Sized_relobj* object, + const Symbol_value* psymval, + typename elfcpp::Swap::Valtype addend) + { + typedef typename elfcpp::Swap_unaligned::Valtype Valtype; + unsigned char* wv = view; + Valtype val = elfcpp::Swap_unaligned::readval(wv); + Valtype reloc = (psymval->value(object, addend) >> right_shift); + + val &= ~dst_mask; + reloc &= dst_mask; + + elfcpp::Swap_unaligned::writeval(wv, val | reloc); + } + + // Do a simple PC relative relocation with a Symbol_value with the + // addend in the relocation. + template + static inline void + pcrela(unsigned char* view, + unsigned int right_shift, + typename elfcpp::Elf_types::Elf_Addr dst_mask, + const Sized_relobj* object, + const Symbol_value* psymval, + typename elfcpp::Swap::Valtype addend, + typename elfcpp::Elf_types::Elf_Addr address) + { + typedef typename elfcpp::Swap::Valtype Valtype; + Valtype* wv = reinterpret_cast(view); + Valtype val = elfcpp::Swap::readval(wv); + Valtype reloc = ((psymval->value(object, addend) - address) + >> right_shift); + + val &= ~dst_mask; + reloc &= dst_mask; + + elfcpp::Swap::writeval(wv, val | reloc); + } + + template + static inline void + pcrela_unaligned(unsigned char* view, + const Sized_relobj* object, + const Symbol_value* psymval, + typename elfcpp::Swap::Valtype addend, + typename elfcpp::Elf_types::Elf_Addr address) + { + typedef typename elfcpp::Swap_unaligned::Valtype Valtype; + unsigned char* wv = view; + Valtype reloc = (psymval->value(object, addend) - address); + + elfcpp::Swap_unaligned::writeval(wv, reloc); + } + + typedef Sparc_relocate_functions This; + typedef Sparc_relocate_functions This_insn; + +public: + // R_SPARC_WDISP30: (Symbol + Addend - Address) >> 2 + static inline void + wdisp30(unsigned char* view, + const Sized_relobj* object, + const Symbol_value* psymval, + typename elfcpp::Elf_types::Elf_Addr addend, + typename elfcpp::Elf_types::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* object, + const Symbol_value* psymval, + typename elfcpp::Elf_types::Elf_Addr addend, + typename elfcpp::Elf_types::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* object, + const Symbol_value* psymval, + typename elfcpp::Elf_types::Elf_Addr addend, + typename elfcpp::Elf_types::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* object, + const Symbol_value* psymval, + typename elfcpp::Elf_types::Elf_Addr addend, + typename elfcpp::Elf_types::Elf_Addr address) + { + typedef typename elfcpp::Swap<32, true>::Valtype Valtype; + Valtype* wv = reinterpret_cast(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* object, + const Symbol_value* psymval, + typename elfcpp::Elf_types::Elf_Addr addend, + typename elfcpp::Elf_types::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* object, + const Symbol_value* psymval, + typename elfcpp::Elf_types::Elf_Addr addend, + typename elfcpp::Elf_types::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::Elf_Addr value, + typename elfcpp::Elf_types::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* object, + const Symbol_value* psymval, + typename elfcpp::Elf_types::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* object, + const Symbol_value* psymval, + typename elfcpp::Elf_types::Elf_Addr addend, + typename elfcpp::Elf_types::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::Elf_Addr value, + typename elfcpp::Elf_types::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* object, + const Symbol_value* psymval, + typename elfcpp::Elf_types::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* object, + const Symbol_value* psymval, + typename elfcpp::Elf_types::Elf_Addr addend, + typename elfcpp::Elf_types::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* object, + const Symbol_value* psymval, + typename elfcpp::Elf_types::Elf_Addr addend, + typename elfcpp::Elf_types::Elf_Addr addend2) + { + typedef typename elfcpp::Swap<32, true>::Valtype Valtype; + Valtype* wv = reinterpret_cast(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* object, + const Symbol_value* psymval, + typename elfcpp::Elf_types::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::Elf_Addr value, + typename elfcpp::Elf_types::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* object, + const Symbol_value* psymval, + typename elfcpp::Elf_types::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* object, + const Symbol_value* psymval, + typename elfcpp::Elf_types::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* object, + const Symbol_value* psymval, + typename elfcpp::Elf_types::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* object, + const Symbol_value* psymval, + typename elfcpp::Elf_types::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* object, + const Symbol_value* psymval, + typename elfcpp::Elf_types::Elf_Addr addend, + typename elfcpp::Elf_types::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* object, + const Symbol_value* psymval, + typename elfcpp::Elf_types::Elf_Addr addend, + typename elfcpp::Elf_types::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* object, + const Symbol_value* psymval, + typename elfcpp::Elf_types::Elf_Addr addend, + typename elfcpp::Elf_types::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* object, + const Symbol_value* psymval, + elfcpp::Elf_Xword addend, + typename elfcpp::Elf_types::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* object, + const Symbol_value* psymval, + typename elfcpp::Elf_types::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* object, + const Symbol_value* psymval, + typename elfcpp::Elf_types::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* object, + const Symbol_value* psymval, + typename elfcpp::Elf_types::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* object, + const Symbol_value* psymval, + typename elfcpp::Elf_types::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* object, + const Symbol_value* psymval, + typename elfcpp::Elf_types::Elf_Addr addend, + typename elfcpp::Elf_types::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* object, + const Symbol_value* psymval, + typename elfcpp::Elf_types::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* object, + const Symbol_value* psymval, + typename elfcpp::Elf_types::Elf_Addr addend, + typename elfcpp::Elf_types::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* object, + const Symbol_value* psymval, + typename elfcpp::Elf_types::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* object, + const Symbol_value* psymval, + typename elfcpp::Elf_types::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* object, + const Symbol_value* psymval, + typename elfcpp::Elf_types::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* object, + const Symbol_value* psymval, + typename elfcpp::Elf_types::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* object, + const Symbol_value* psymval, + typename elfcpp::Elf_types::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::Elf_Addr value, + typename elfcpp::Elf_types::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::Elf_Addr value, + typename elfcpp::Elf_types::Elf_Addr addend) + { + typedef typename elfcpp::Swap<32, true>::Valtype Valtype; + Valtype* wv = reinterpret_cast(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::Elf_Addr value, + typename elfcpp::Elf_types::Elf_Addr addend) + { + typedef typename elfcpp::Swap<32, true>::Valtype Valtype; + Valtype* wv = reinterpret_cast(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* object, + const Symbol_value* psymval, + typename elfcpp::Elf_types::Elf_Addr addend) + { + typedef typename elfcpp::Swap<32, true>::Valtype Valtype; + Valtype* wv = reinterpret_cast(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::Elf_Addr value, + typename elfcpp::Elf_types::Elf_Addr addend) + { + typedef typename elfcpp::Swap<32, true>::Valtype Valtype; + Valtype* wv = reinterpret_cast(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* object, + const Symbol_value* psymval, + typename elfcpp::Elf_types::Elf_Addr addend) + { + typedef typename elfcpp::Swap<32, true>::Valtype Valtype; + Valtype* wv = reinterpret_cast(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 +Output_data_got* +Target_sparc::got_section(Symbol_table* symtab, + Layout* layout) +{ + if (this->got_ == NULL) + { + gold_assert(symtab != NULL && layout != NULL); + + this->got_ = new Output_data_got(); + + 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 +typename Target_sparc::Reloc_section* +Target_sparc::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 +class Output_data_plt_sparc : public Output_section_data +{ + public: + typedef Output_data_reloc 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 +const int Output_data_plt_sparc::base_plt_entry_size; + +template +const unsigned int +Output_data_plt_sparc::plt_entries_per_block; + +template +const unsigned int Output_data_plt_sparc::plt_insn_chunk_size; + +template +const unsigned int +Output_data_plt_sparc::plt_pointer_chunk_size; + +template +const unsigned int Output_data_plt_sparc::plt_block_size; + +// Create the PLT section. The ordinary .got section is an argument, +// since we need to refer to the start. + +template +Output_data_plt_sparc::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 +void +Output_data_plt_sparc::do_adjust_output_section(Output_section* os) +{ + os->set_entsize(0); +} + +// Add an entry to the PLT. + +template +void +Output_data_plt_sparc::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 +void +Output_data_plt_sparc::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(pov - oview) == oview_size); + + of->write_output_view(offset, oview_size, oview); +} + +// Create a PLT entry for a global symbol. + +template +void +Target_sparc::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(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 +unsigned int +Target_sparc::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 +unsigned int +Target_sparc::first_plt_entry_offset() const +{ + return Output_data_plt_sparc::first_plt_entry_offset(); +} + +// Return the size of each PLT entry. + +template +unsigned int +Target_sparc::plt_entry_size() const +{ + return Output_data_plt_sparc::get_plt_entry_size(); +} + +// Create a GOT entry for the TLS module index. + +template +unsigned int +Target_sparc::got_mod_index_entry(Symbol_table* symtab, + Layout* layout, + Sized_relobj* 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* 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 +void +Target_sparc::Scan::generate_tls_call(Symbol_table* symtab, + Layout* layout, + Target_sparc* 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 +void +Target_sparc::Scan::unsupported_reloc_local( + Sized_relobj* 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 +void +Target_sparc::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 +inline void +Target_sparc::Scan::local( + Symbol_table* symtab, + Layout* layout, + Target_sparc* target, + Sized_relobj* object, + unsigned int data_shndx, + Output_section* output_section, + const elfcpp::Rela& reloc, + unsigned int r_type, + const elfcpp::Sym& 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(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(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* got; + unsigned int r_sym; + + got = target->got_section(symtab, layout); + r_sym = elfcpp::elf_r_sym(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* got + = target->got_section(symtab, layout); + unsigned int r_sym = elfcpp::elf_r_sym(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* got + = target->got_section(symtab, layout); + unsigned int r_sym = elfcpp::elf_r_sym(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(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 +void +Target_sparc::Scan::unsupported_reloc_global( + Sized_relobj* 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 +inline void +Target_sparc::Scan::global( + Symbol_table* symtab, + Layout* layout, + Target_sparc* target, + Sized_relobj* object, + unsigned int data_shndx, + Output_section* output_section, + const elfcpp::Rela& 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* 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* 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* 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* 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 +void +Target_sparc::gc_process_relocs( + Symbol_table* symtab, + Layout* layout, + Sized_relobj* 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 Sparc; + typedef typename Target_sparc::Scan Scan; + + gold::gc_process_relocs( + 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 +void +Target_sparc::scan_relocs( + Symbol_table* symtab, + Layout* layout, + Sized_relobj* 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 Sparc; + typedef typename Target_sparc::Scan Scan; + + if (sh_type == elfcpp::SHT_REL) + { + gold_error(_("%s: unsupported REL reloc section"), + object->name().c_str()); + return; + } + + gold::scan_relocs( + symtab, + layout, + this, + object, + data_shndx, + prelocs, + reloc_count, + output_section, + needs_special_offset_handling, + local_symbol_count, + plocal_symbols); +} + +// Finalize the sections. + +template +void +Target_sparc::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 +inline bool +Target_sparc::Relocate::relocate( + const Relocate_info* relinfo, + Target_sparc* target, + Output_section*, + size_t relnum, + const elfcpp::Rela& rela, + unsigned int r_type, + const Sized_symbol* gsym, + const Symbol_value* psymval, + unsigned char* view, + typename elfcpp::Elf_types::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 Reloc; + + // Pick the value to use for symbols defined in shared objects. + Symbol_value 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* 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(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::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::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::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::rela64(view, object, + psymval, addend); + break; + + case elfcpp::R_SPARC_PLT32: + Relocate_functions::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::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 +inline void +Target_sparc::Relocate::relocate_tls( + const Relocate_info* relinfo, + Target_sparc* target, + size_t relnum, + const elfcpp::Rela& rela, + unsigned int r_type, + const Sized_symbol* gsym, + const Symbol_value* psymval, + unsigned char* view, + typename elfcpp::Elf_types::Elf_Addr address, + section_size_type) +{ + Output_segment* tls_segment = relinfo->layout->tls_segment(); + typedef Sparc_relocate_functions Reloc; + const Sized_relobj* object = relinfo->object; + typedef typename elfcpp::Swap<32, true>::Valtype Insntype; + + const elfcpp::Elf_Xword addend = rela.get_r_addend(); + typename elfcpp::Elf_types::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(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(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(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 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(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 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(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(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(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 +void +Target_sparc::relocate_section( + const Relocate_info* 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::Elf_Addr address, + section_size_type view_size, + const Reloc_symbol_changes* reloc_symbol_changes) +{ + typedef Target_sparc Sparc; + typedef typename Target_sparc::Relocate Sparc_relocate; + + gold_assert(sh_type == elfcpp::SHT_RELA); + + gold::relocate_section( + 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 +unsigned int +Target_sparc::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 +void +Target_sparc::scan_relocatable_relocs( + Symbol_table* symtab, + Layout* layout, + Sized_relobj* 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 Scan_relocatable_relocs; + + gold::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 +void +Target_sparc::relocate_for_relocatable( + const Relocate_info* 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::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( + 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 +uint64_t +Target_sparc::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 +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(); } +}; + +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 index 0000000000..9d58fef400 --- /dev/null +++ b/contrib/binutils-2.21/include/plugin-api.h @@ -0,0 +1,308 @@ +/* plugin-api.h -- External linker plugin API. */ + +/* Copyright 2009 Free Software Foundation, Inc. + Written by Cary Coutant . + + 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 +#elif defined(HAVE_INTTYPES_H) +#include +#endif +#include +#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 index 0000000000..c12916b521 --- /dev/null +++ b/contrib/binutils-2.21/libiberty/crc32.c @@ -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 + + 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; +}