* elf64-ppc.c (ppc_add_stub): Replace strcpy/strncpy with memcpy.
[deliverable/binutils-gdb.git] / bfd / elf64-ppc.c
index 40b460076b9521a49acaba2f61a02036e3f8eee3..9d798efc083229baaf377e868f0b1f9b3805bb98 100644 (file)
@@ -39,21 +39,31 @@ static reloc_howto_type *ppc64_elf_reloc_type_lookup
   PARAMS ((bfd *abfd, bfd_reloc_code_real_type code));
 static void ppc64_elf_info_to_howto
   PARAMS ((bfd *abfd, arelent *cache_ptr, Elf64_Internal_Rela *dst));
-static bfd_reloc_status_type ppc64_elf_addr16_ha_reloc
+static bfd_reloc_status_type ppc64_elf_ha_reloc
   PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
+static bfd_reloc_status_type ppc64_elf_brtaken_reloc
+  PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
+static bfd_reloc_status_type ppc64_elf_sectoff_reloc
+  PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
+static bfd_reloc_status_type ppc64_elf_sectoff_ha_reloc
+  PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
+static bfd_reloc_status_type ppc64_elf_toc_reloc
+  PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
+static bfd_reloc_status_type ppc64_elf_toc_ha_reloc
+  PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
+static bfd_reloc_status_type ppc64_elf_toc64_reloc
+  PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
+static bfd_reloc_status_type ppc64_elf_unhandled_reloc
+  PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
+static void ppc64_elf_get_symbol_info
+  PARAMS ((bfd *, asymbol *, symbol_info *));
 static boolean ppc64_elf_set_private_flags
   PARAMS ((bfd *, flagword));
 static boolean ppc64_elf_merge_private_bfd_data
   PARAMS ((bfd *, bfd *));
 static boolean ppc64_elf_section_from_shdr
-  PARAMS ((bfd *, Elf64_Internal_Shdr *, char *));
-
-
-/* Mask to set RA in memory instructions.  */
-#define RA_REGISTER_MASK 0x001f0000
+  PARAMS ((bfd *, Elf64_Internal_Shdr *, const char *));
 
-/* Value to shift register by to insert RA.  */
-#define RA_REGISTER_SHIFT 16
 
 /* The name of the dynamic interpreter.  This is put in the .interp
    section.  */
@@ -98,7 +108,7 @@ static boolean ppc64_elf_section_from_shdr
 #define CROR_151515    0x4def7b82
 #define CROR_313131    0x4ffffb82
 
-/* .glink entries for the first 32k functions are two instructions. */
+/* .glink entries for the first 32k functions are two instructions.  */
 #define LI_R0_0                0x38000000      /* li    %r0,0          */
 #define B_DOT          0x48000000      /* b     .              */
 
@@ -225,7 +235,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        ppc64_elf_addr16_ha_reloc, /* special_function */
+        ppc64_elf_ha_reloc,    /* special_function */
         "R_PPC64_ADDR16_HA",   /* name */
         false,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -258,7 +268,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_bitfield, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc64_elf_brtaken_reloc, /* special_function */
         "R_PPC64_ADDR14_BRTAKEN",/* name */
         false,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -275,7 +285,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_bitfield, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc64_elf_brtaken_reloc, /* special_function */
         "R_PPC64_ADDR14_BRNTAKEN",/* name */
         false,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -322,7 +332,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         true,                  /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc64_elf_brtaken_reloc, /* special_function */
         "R_PPC64_REL14_BRTAKEN", /* name */
         false,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -339,7 +349,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         true,                  /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc64_elf_brtaken_reloc, /* special_function */
         "R_PPC64_REL14_BRNTAKEN",/* name */
         false,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -355,7 +365,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc64_elf_unhandled_reloc, /* special_function */
         "R_PPC64_GOT16",       /* name */
         false,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -371,7 +381,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc64_elf_unhandled_reloc, /* special_function */
         "R_PPC64_GOT16_LO",    /* name */
         false,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -387,7 +397,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont,/* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc64_elf_unhandled_reloc, /* special_function */
         "R_PPC64_GOT16_HI",    /* name */
         false,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -403,7 +413,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont,/* complain_on_overflow */
-        ppc64_elf_addr16_ha_reloc, /* special_function */
+        ppc64_elf_unhandled_reloc, /* special_function */
         "R_PPC64_GOT16_HA",    /* name */
         false,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -422,7 +432,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_bitfield, /* complain_on_overflow */
-        bfd_elf_generic_reloc,  /* special_function */
+        ppc64_elf_unhandled_reloc,  /* special_function */
         "R_PPC64_COPY",        /* name */
         false,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -438,7 +448,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc,  /* special_function */
+        ppc64_elf_unhandled_reloc,  /* special_function */
         "R_PPC64_GLOB_DAT",    /* name */
         false,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -454,7 +464,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc64_elf_unhandled_reloc, /* special_function */
         "R_PPC64_JMP_SLOT",    /* name */
         false,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -515,7 +525,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         32,                    /* bitsize */
         true,                  /* pc_relative */
         0,                     /* bitpos */
-        /* FIXME: Verify.  Was complain_overflow_bitfield. */
+        /* FIXME: Verify.  Was complain_overflow_bitfield.  */
         complain_overflow_signed, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_PPC64_REL32",       /* name */
@@ -532,7 +542,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_bitfield, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc64_elf_unhandled_reloc, /* special_function */
         "R_PPC64_PLT32",       /* name */
         false,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -564,7 +574,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc64_elf_unhandled_reloc, /* special_function */
         "R_PPC64_PLT16_LO",    /* name */
         false,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -580,7 +590,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc64_elf_unhandled_reloc, /* special_function */
         "R_PPC64_PLT16_HI",    /* name */
         false,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -596,31 +606,29 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        ppc64_elf_addr16_ha_reloc, /* special_function */
+        ppc64_elf_unhandled_reloc, /* special_function */
         "R_PPC64_PLT16_HA",    /* name */
         false,                 /* partial_inplace */
         0,                     /* src_mask */
         0xffff,                /* dst_mask */
         false),                /* pcrel_offset */
 
-  /* 32-bit section relative relocation.  */
-  /* FIXME: Verify R_PPC64_SECTOFF.  Seems strange with size=2 and
-     dst_mask=0.  */
+  /* 16-bit section relative relocation.  */
   HOWTO (R_PPC64_SECTOFF,      /* type */
         0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        32,                    /* bitsize */
-        true,                  /* pc_relative */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_bitfield, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc64_elf_sectoff_reloc, /* special_function */
         "R_PPC64_SECTOFF",     /* name */
         false,                 /* partial_inplace */
         0,                     /* src_mask */
-        0,                     /* dst_mask */
-        true),                 /* pcrel_offset */
+        0xffff,                /* dst_mask */
+        false),                /* pcrel_offset */
 
-  /* 16-bit lower half section relative relocation.  */
+  /* Like R_PPC64_SECTOFF, but no overflow warning.  */
   HOWTO (R_PPC64_SECTOFF_LO,   /* type */
         0,                     /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
@@ -628,7 +636,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc64_elf_sectoff_reloc, /* special_function */
         "R_PPC64_SECTOFF_LO",  /* name */
         false,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -643,7 +651,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc64_elf_sectoff_reloc, /* special_function */
         "R_PPC64_SECTOFF_HI",  /* name */
         false,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -658,7 +666,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        ppc64_elf_addr16_ha_reloc, /* special_function */
+        ppc64_elf_sectoff_ha_reloc, /* special_function */
         "R_PPC64_SECTOFF_HA",  /* name */
         false,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -666,8 +674,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         false),                /* pcrel_offset */
 
   /* Like R_PPC64_REL24 without touching the two least significant
-     bits.  */
-  /* FIXME: Verify R_PPC64_ADDR30.  */
+     bits.  Should have been named R_PPC64_REL30!  */
   HOWTO (R_PPC64_ADDR30,       /* type */
         2,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
@@ -723,7 +730,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        ppc64_elf_addr16_ha_reloc, /* special_function */
+        ppc64_elf_ha_reloc,    /* special_function */
         "R_PPC64_ADDR16_HIGHERA", /* name */
         false,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -754,7 +761,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        ppc64_elf_addr16_ha_reloc, /* special_function */
+        ppc64_elf_ha_reloc,    /* special_function */
         "R_PPC64_ADDR16_HIGHESTA", /* name */
         false,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -791,7 +798,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         0xffffffffffffffff,    /* dst_mask */
         true),                 /* pcrel_offset */
 
-  /* 64-bit relocation to the symbol's procedure linkage table. */
+  /* 64-bit relocation to the symbol's procedure linkage table.  */
   HOWTO (R_PPC64_PLT64,                /* type */
         0,                     /* rightshift */
         4,                     /* size (0=byte, 1=short, 2=long, 4=64 bits) */
@@ -799,7 +806,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc64_elf_unhandled_reloc, /* special_function */
         "R_PPC64_PLT64",       /* name */
         false,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -816,7 +823,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         true,                  /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc64_elf_unhandled_reloc, /* special_function */
         "R_PPC64_PLTREL64",    /* name */
         false,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -833,7 +840,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc64_elf_toc_reloc,   /* special_function */
         "R_PPC64_TOC16",       /* name */
         false,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -850,7 +857,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc64_elf_toc_reloc,   /* special_function */
         "R_PPC64_TOC16_LO",    /* name */
         false,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -867,7 +874,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc64_elf_toc_reloc,   /* special_function */
         "R_PPC64_TOC16_HI",    /* name */
         false,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -886,7 +893,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        ppc64_elf_addr16_ha_reloc, /* special_function */
+        ppc64_elf_toc_ha_reloc, /* special_function */
         "R_PPC64_TOC16_HA",    /* name */
         false,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -903,7 +910,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_bitfield, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc64_elf_toc64_reloc, /* special_function */
         "R_PPC64_TOC",         /* name */
         false,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -926,7 +933,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc64_elf_unhandled_reloc, /* special_function */
         "R_PPC64_PLTGOT16",    /* name */
         false,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -942,7 +949,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc64_elf_unhandled_reloc, /* special_function */
         "R_PPC64_PLTGOT16_LO", /* name */
         false,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -958,7 +965,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc64_elf_unhandled_reloc, /* special_function */
         "R_PPC64_PLTGOT16_HI", /* name */
         false,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -976,7 +983,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont,/* complain_on_overflow */
-        ppc64_elf_addr16_ha_reloc, /* special_function */
+        ppc64_elf_unhandled_reloc, /* special_function */
         "R_PPC64_PLTGOT16_HA", /* name */
         false,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -1021,7 +1028,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc64_elf_unhandled_reloc, /* special_function */
         "R_PPC64_GOT16_DS",    /* name */
         false,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -1036,7 +1043,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc64_elf_unhandled_reloc, /* special_function */
         "R_PPC64_GOT16_LO_DS", /* name */
         false,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -1051,7 +1058,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc64_elf_unhandled_reloc, /* special_function */
         "R_PPC64_PLT16_LO_DS", /* name */
         false,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -1059,21 +1066,19 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         false),                /* pcrel_offset */
 
   /* Like R_PPC64_SECTOFF, but for instructions with a DS field.  */
-  /* FIXME: Verify R_PPC64_SECTOFF.  Seems strange with size=2 and
-     dst_mask=0.  */
   HOWTO (R_PPC64_SECTOFF_DS,   /* type */
         0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        32,                    /* bitsize */
-        true,                  /* pc_relative */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_bitfield, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc64_elf_sectoff_reloc, /* special_function */
         "R_PPC64_SECTOFF_DS",  /* name */
         false,                 /* partial_inplace */
         0,                     /* src_mask */
-        0,                     /* dst_mask */
-        true),                 /* pcrel_offset */
+        0xfffc,                /* dst_mask */
+        false),                /* pcrel_offset */
 
   /* Like R_PPC64_SECTOFF_LO, but for instructions with a DS field.  */
   HOWTO (R_PPC64_SECTOFF_LO_DS, /* type */
@@ -1083,7 +1088,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc64_elf_sectoff_reloc, /* special_function */
         "R_PPC64_SECTOFF_LO_DS",/* name */
         false,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -1098,7 +1103,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc64_elf_toc_reloc,   /* special_function */
         "R_PPC64_TOC16_DS",    /* name */
         false,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -1113,7 +1118,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc64_elf_toc_reloc,   /* special_function */
         "R_PPC64_TOC16_LO_DS", /* name */
         false,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -1129,7 +1134,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc64_elf_unhandled_reloc, /* special_function */
         "R_PPC64_PLTGOT16_DS", /* name */
         false,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -1145,7 +1150,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc64_elf_unhandled_reloc, /* special_function */
         "R_PPC64_PLTGOT16_LO_DS",/* name */
         false,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -1271,7 +1276,7 @@ ppc64_elf_reloc_type_lookup (abfd, code)
       break;
     case BFD_RELOC_HI16_S_PLTOFF:       ppc_reloc = R_PPC64_PLT16_HA;
       break;
-    case BFD_RELOC_32_BASEREL:          ppc_reloc = R_PPC64_SECTOFF;
+    case BFD_RELOC_16_BASEREL:          ppc_reloc = R_PPC64_SECTOFF;
       break;
     case BFD_RELOC_LO16_BASEREL:        ppc_reloc = R_PPC64_SECTOFF_LO;
       break;
@@ -1356,8 +1361,8 @@ ppc64_elf_info_to_howto (abfd, cache_ptr, dst)
 {
   unsigned int type;
 
+  /* Initialize howto table if needed.  */
   if (!ppc64_elf_howto_table[R_PPC64_ADDR32])
-    /* Initialize howto table if needed.  */
     ppc_howto_init ();
 
   type = ELF64_R_TYPE (dst->r_info);
@@ -1369,41 +1374,281 @@ ppc64_elf_info_to_howto (abfd, cache_ptr, dst)
 /* Handle the R_PPC_ADDR16_HA and similar relocs.  */
 
 static bfd_reloc_status_type
-ppc64_elf_addr16_ha_reloc (abfd, reloc_entry, symbol, data, input_section,
-                          output_bfd, error_message)
-     bfd *abfd ATTRIBUTE_UNUSED;
+ppc64_elf_ha_reloc (abfd, reloc_entry, symbol, data,
+                   input_section, output_bfd, error_message)
+     bfd *abfd;
      arelent *reloc_entry;
      asymbol *symbol;
-     PTR data ATTRIBUTE_UNUSED;
+     PTR data;
      asection *input_section;
      bfd *output_bfd;
-     char **error_message ATTRIBUTE_UNUSED;
+     char **error_message;
 {
-  bfd_vma relocation;
+  /* If this is a relocatable link (output_bfd test tells us), just
+     call the generic function.  Any adjustment will be done at final
+     link time.  */
+  if (output_bfd != NULL)
+    return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
+                                 input_section, output_bfd, error_message);
 
+  /* Adjust the addend for sign extension of the low 16 bits.
+     We won't actually be using the low 16 bits, so trashing them
+     doesn't matter.  */
+  reloc_entry->addend += 0x8000;
+  return bfd_reloc_continue;
+}
+
+static bfd_reloc_status_type
+ppc64_elf_brtaken_reloc (abfd, reloc_entry, symbol, data,
+                        input_section, output_bfd, error_message)
+     bfd *abfd;
+     arelent *reloc_entry;
+     asymbol *symbol;
+     PTR data;
+     asection *input_section;
+     bfd *output_bfd;
+     char **error_message;
+{
+  long insn;
+  enum elf_ppc_reloc_type r_type;
+  bfd_size_type octets;
+  /* Disabled until we sort out how ld should choose 'y' vs 'at'.  */
+  boolean is_power4 = false;
+
+  /* If this is a relocatable link (output_bfd test tells us), just
+     call the generic function.  Any adjustment will be done at final
+     link time.  */
   if (output_bfd != NULL)
+    return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
+                                 input_section, output_bfd, error_message);
+
+  octets = reloc_entry->address * bfd_octets_per_byte (abfd);
+  insn = bfd_get_32 (abfd, (bfd_byte *) data + octets);
+  insn &= ~(0x01 << 21);
+  r_type = (enum elf_ppc_reloc_type) reloc_entry->howto->type;
+  if (r_type == R_PPC64_ADDR14_BRTAKEN
+      || r_type == R_PPC64_REL14_BRTAKEN)
+    insn |= 0x01 << 21; /* 'y' or 't' bit, lowest bit of BO field.  */
+
+  if (is_power4)
     {
-      reloc_entry->address += input_section->output_offset;
-      return bfd_reloc_ok;
+      /* Set 'a' bit.  This is 0b00010 in BO field for branch
+        on CR(BI) insns (BO == 001at or 011at), and 0b01000
+        for branch on CTR insns (BO == 1a00t or 1a01t).  */
+      if ((insn & (0x14 << 21)) == (0x04 << 21))
+       insn |= 0x02 << 21;
+      else if ((insn & (0x14 << 21)) == (0x10 << 21))
+       insn |= 0x08 << 21;
+      else
+       return bfd_reloc_continue;
     }
+  else
+    {
+      bfd_vma target = 0;
+      bfd_vma from;
 
-  if (reloc_entry->address > input_section->_cooked_size)
-    return bfd_reloc_outofrange;
+      if (!bfd_is_com_section (symbol->section))
+       target = symbol->value;
+      target += symbol->section->output_section->vma;
+      target += symbol->section->output_offset;
+      target += reloc_entry->addend;
 
-  if (bfd_is_com_section (symbol->section))
-    relocation = 0;
-  else
-    relocation = symbol->value;
+      from = (reloc_entry->address
+             + input_section->output_offset
+             + input_section->output_section->vma);
 
-  relocation += symbol->section->output_section->vma;
-  relocation += symbol->section->output_offset;
-  relocation += reloc_entry->addend;
+      /* Invert 'y' bit if not the default.  */
+      if ((bfd_signed_vma) (target - from) < 0)
+       insn ^= 0x01 << 21;
+    }
+  bfd_put_32 (abfd, (bfd_vma) insn, (bfd_byte *) data + octets);
+  return bfd_reloc_continue;
+}
 
-  reloc_entry->addend += (relocation & 0x8000) << 1;
+static bfd_reloc_status_type
+ppc64_elf_sectoff_reloc (abfd, reloc_entry, symbol, data,
+                        input_section, output_bfd, error_message)
+     bfd *abfd;
+     arelent *reloc_entry;
+     asymbol *symbol;
+     PTR data;
+     asection *input_section;
+     bfd *output_bfd;
+     char **error_message;
+{
+  /* If this is a relocatable link (output_bfd test tells us), just
+     call the generic function.  Any adjustment will be done at final
+     link time.  */
+  if (output_bfd != NULL)
+    return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
+                                 input_section, output_bfd, error_message);
 
+  /* Subtract the symbol section base address.  */
+  reloc_entry->addend -= symbol->section->output_section->vma;
   return bfd_reloc_continue;
 }
 
+static bfd_reloc_status_type
+ppc64_elf_sectoff_ha_reloc (abfd, reloc_entry, symbol, data,
+                           input_section, output_bfd, error_message)
+     bfd *abfd;
+     arelent *reloc_entry;
+     asymbol *symbol;
+     PTR data;
+     asection *input_section;
+     bfd *output_bfd;
+     char **error_message;
+{
+  /* If this is a relocatable link (output_bfd test tells us), just
+     call the generic function.  Any adjustment will be done at final
+     link time.  */
+  if (output_bfd != NULL)
+    return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
+                                 input_section, output_bfd, error_message);
+
+  /* Subtract the symbol section base address.  */
+  reloc_entry->addend -= symbol->section->output_section->vma;
+
+  /* Adjust the addend for sign extension of the low 16 bits.  */
+  reloc_entry->addend += 0x8000;
+  return bfd_reloc_continue;
+}
+
+static bfd_reloc_status_type
+ppc64_elf_toc_reloc (abfd, reloc_entry, symbol, data,
+                    input_section, output_bfd, error_message)
+     bfd *abfd;
+     arelent *reloc_entry;
+     asymbol *symbol;
+     PTR data;
+     asection *input_section;
+     bfd *output_bfd;
+     char **error_message;
+{
+  bfd_vma TOCstart;
+
+  /* If this is a relocatable link (output_bfd test tells us), just
+     call the generic function.  Any adjustment will be done at final
+     link time.  */
+  if (output_bfd != NULL)
+    return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
+                                 input_section, output_bfd, error_message);
+
+  TOCstart = _bfd_get_gp_value (input_section->output_section->owner);
+  if (TOCstart == 0)
+    TOCstart = ppc64_elf_toc (input_section->output_section->owner);
+
+  /* Subtract the TOC base address.  */
+  reloc_entry->addend -= TOCstart + TOC_BASE_OFF;
+  return bfd_reloc_continue;
+}
+
+static bfd_reloc_status_type
+ppc64_elf_toc_ha_reloc (abfd, reloc_entry, symbol, data,
+                       input_section, output_bfd, error_message)
+     bfd *abfd;
+     arelent *reloc_entry;
+     asymbol *symbol;
+     PTR data;
+     asection *input_section;
+     bfd *output_bfd;
+     char **error_message;
+{
+  bfd_vma TOCstart;
+
+  /* If this is a relocatable link (output_bfd test tells us), just
+     call the generic function.  Any adjustment will be done at final
+     link time.  */
+  if (output_bfd != NULL)
+    return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
+                                 input_section, output_bfd, error_message);
+
+  TOCstart = _bfd_get_gp_value (input_section->output_section->owner);
+  if (TOCstart == 0)
+    TOCstart = ppc64_elf_toc (input_section->output_section->owner);
+
+  /* Subtract the TOC base address.  */
+  reloc_entry->addend -= TOCstart + TOC_BASE_OFF;
+
+  /* Adjust the addend for sign extension of the low 16 bits.  */
+  reloc_entry->addend += 0x8000;
+  return bfd_reloc_continue;
+}
+
+static bfd_reloc_status_type
+ppc64_elf_toc64_reloc (abfd, reloc_entry, symbol, data,
+                      input_section, output_bfd, error_message)
+     bfd *abfd;
+     arelent *reloc_entry;
+     asymbol *symbol;
+     PTR data;
+     asection *input_section;
+     bfd *output_bfd;
+     char **error_message;
+{
+  bfd_vma TOCstart;
+  bfd_size_type octets;
+
+  /* If this is a relocatable link (output_bfd test tells us), just
+     call the generic function.  Any adjustment will be done at final
+     link time.  */
+  if (output_bfd != NULL)
+    return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
+                                 input_section, output_bfd, error_message);
+
+  TOCstart = _bfd_get_gp_value (input_section->output_section->owner);
+  if (TOCstart == 0)
+    TOCstart = ppc64_elf_toc (input_section->output_section->owner);
+
+  octets = reloc_entry->address * bfd_octets_per_byte (abfd);
+  bfd_put_64 (abfd, TOCstart + TOC_BASE_OFF, (bfd_byte *) data + octets);
+  return bfd_reloc_ok;
+}
+
+static bfd_reloc_status_type
+ppc64_elf_unhandled_reloc (abfd, reloc_entry, symbol, data,
+                          input_section, output_bfd, error_message)
+     bfd *abfd;
+     arelent *reloc_entry;
+     asymbol *symbol;
+     PTR data;
+     asection *input_section;
+     bfd *output_bfd;
+     char **error_message;
+{
+  /* If this is a relocatable link (output_bfd test tells us), just
+     call the generic function.  Any adjustment will be done at final
+     link time.  */
+  if (output_bfd != NULL)
+    return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
+                                 input_section, output_bfd, error_message);
+
+  if (error_message != NULL)
+    {
+      static char buf[60];
+      sprintf (buf, "generic linker can't handle %s",
+              reloc_entry->howto->name);
+      *error_message = buf;
+    }
+  return bfd_reloc_dangerous;
+}
+
+/* Return symbol info as per usual for ELF targets, except that
+   symbols in .opd are given 'd' or 'D' for type.  */
+
+static void
+ppc64_elf_get_symbol_info (abfd, symbol, ret)
+     bfd *abfd;
+     asymbol *symbol;
+     symbol_info *ret;
+{
+  _bfd_elf_get_symbol_info (abfd, symbol, ret);
+  if (ret->type == '?'
+      && (symbol->flags & (BSF_GLOBAL | BSF_LOCAL)) != 0
+      && strcmp (symbol->section->name, ".opd") == 0)
+    ret->type = (symbol->flags & BSF_GLOBAL) != 0 ? 'D' : 'd';
+}
+
 /* Function to set whether a module needs the -mrelocatable bit set.  */
 
 static boolean
@@ -1491,7 +1736,7 @@ ppc64_elf_merge_private_bfd_data (ibfd, obfd)
        elf_elfheader (obfd)->e_flags &= ~EF_PPC_RELOCATABLE_LIB;
 
       /* The output is -mrelocatable iff it can't be -mrelocatable-lib,
-         but each input file is either -mrelocatable or -mrelocatable-lib.  */
+        but each input file is either -mrelocatable or -mrelocatable-lib.  */
       if (! (elf_elfheader (obfd)->e_flags & EF_PPC_RELOCATABLE_LIB)
          && (new_flags & (EF_PPC_RELOCATABLE_LIB | EF_PPC_RELOCATABLE))
          && (old_flags & (EF_PPC_RELOCATABLE_LIB | EF_PPC_RELOCATABLE)))
@@ -1530,7 +1775,7 @@ static boolean
 ppc64_elf_section_from_shdr (abfd, hdr, name)
      bfd *abfd;
      Elf64_Internal_Shdr *hdr;
-     char *name;
+     const char *name;
 {
   asection *newsect;
   flagword flags;
@@ -1642,12 +1887,9 @@ struct ppc_dyn_relocs
    selects between relative and absolute types.  */
 
 #define IS_ABSOLUTE_RELOC(RTYPE)               \
-  ((RTYPE) != R_PPC64_REL14                    \
-   && (RTYPE) != R_PPC64_REL14_BRNTAKEN                \
-   && (RTYPE) != R_PPC64_REL14_BRTAKEN         \
-   && (RTYPE) != R_PPC64_REL24                 \
-   && (RTYPE) != R_PPC64_REL32                 \
-   && (RTYPE) != R_PPC64_REL64)
+  ((RTYPE) != R_PPC64_REL32                    \
+   && (RTYPE) != R_PPC64_REL64                 \
+   && (RTYPE) != R_PPC64_ADDR30)
 
 /* Section name for stubs is the associated section name plus this
    string.  */
@@ -1795,6 +2037,9 @@ struct ppc_link_hash_table
      select suitable defaults for the stub group size.  */
   unsigned int has_14bit_branch;
 
+  /* Set if we detect a reference undefined weak symbol.  */
+  unsigned int have_undefweak;
+
   /* Incremented every time we size stubs.  */
   unsigned int stub_iteration;
 
@@ -2036,6 +2281,7 @@ ppc64_elf_link_hash_table_create (abfd)
   htab->srelbrlt = NULL;
   htab->stub_error = 0;
   htab->has_14bit_branch = 0;
+  htab->have_undefweak = 0;
   htab->stub_iteration = 0;
   htab->sym_sec.abfd = NULL;
 
@@ -2167,16 +2413,18 @@ ppc_add_stub (stub_name, section, htab)
       stub_sec = htab->stub_group[link_sec->id].stub_sec;
       if (stub_sec == NULL)
        {
+         size_t namelen;
          bfd_size_type len;
          char *s_name;
 
-         len = strlen (link_sec->name) + sizeof (STUB_SUFFIX);
+         namelen = strlen (link_sec->name);
+         len = namelen + sizeof (STUB_SUFFIX);
          s_name = bfd_alloc (htab->stub_bfd, len);
          if (s_name == NULL)
            return NULL;
 
-         strcpy (s_name, link_sec->name);
-         strcpy (s_name + len - sizeof (STUB_SUFFIX), STUB_SUFFIX);
+         memcpy (s_name, link_sec->name, namelen);
+         memcpy (s_name + namelen, STUB_SUFFIX, sizeof (STUB_SUFFIX));
          stub_sec = (*htab->add_stub_section) (s_name, link_sec);
          if (stub_sec == NULL)
            return NULL;
@@ -2462,14 +2710,14 @@ ppc64_elf_check_relocs (abfd, info, sec, relocs)
        case R_PPC64_PLT32:
        case R_PPC64_PLT64:
          /* This symbol requires a procedure linkage table entry.  We
-             actually build the entry in adjust_dynamic_symbol,
-             because this might be a case of linking PIC code without
-             linking in any dynamic objects, in which case we don't
-             need to generate a procedure linkage table after all.  */
+            actually build the entry in adjust_dynamic_symbol,
+            because this might be a case of linking PIC code without
+            linking in any dynamic objects, in which case we don't
+            need to generate a procedure linkage table after all.  */
          if (h == NULL)
            {
              /* It does not make sense to have a procedure linkage
-                 table entry for a local symbol.  */
+                table entry for a local symbol.  */
              bfd_set_error (bfd_error_bad_value);
              return false;
            }
@@ -2541,11 +2789,6 @@ ppc64_elf_check_relocs (abfd, info, sec, relocs)
                                          false, false, false);
              if (fdh != NULL)
                {
-                 /* Ensure the function descriptor symbol string is
-                    part of the code symbol string.  We aren't
-                    changing the name here, just allowing some tricks
-                    in ppc64_elf_hide_symbol.  */
-                 fdh->root.root.string = h->root.root.string + 1;
                  ((struct ppc_link_hash_entry *) fdh)->is_func_descriptor = 1;
                  ((struct ppc_link_hash_entry *) fdh)->oh = h;
                  ((struct ppc_link_hash_entry *) h)->is_func = 1;
@@ -2931,6 +3174,10 @@ func_desc_adjust (h, inf)
   if (!((struct ppc_link_hash_entry *) h)->is_func)
     return true;
 
+  if (h->root.type == bfd_link_hash_undefweak
+      && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR))
+    htab->have_undefweak = true;
+
   if (h->plt.refcount > 0
       && h->root.root.string[0] == '.'
       && h->root.root.string[1] != '\0')
@@ -2993,7 +3240,6 @@ func_desc_adjust (h, inf)
            }
          ((struct ppc_link_hash_entry *) fdh)->is_func_descriptor = 1;
          ((struct ppc_link_hash_entry *) fdh)->oh = h;
-         fdh->root.root.string = h->root.root.string + 1;
          ((struct ppc_link_hash_entry *) h)->oh = fdh;
        }
 
@@ -3004,8 +3250,14 @@ func_desc_adjust (h, inf)
         been imported from another library.  Function code syms that
         are really in the library we must leave global to prevent the
         linker dragging in a definition from a static library.  */
-      force_local = ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0
-                    && info->shared);
+      force_local = (info->shared
+                    && ((h->elf_link_hash_flags
+                         & ELF_LINK_HASH_DEF_REGULAR) == 0
+                        || fdh == NULL
+                        || (fdh->elf_link_hash_flags
+                            & ELF_LINK_HASH_DEF_REGULAR) == 0
+                        || (fdh->elf_link_hash_flags
+                            & ELF_LINK_FORCED_LOCAL) != 0));
       _bfd_elf_link_hash_hide_symbol (info, h, force_local);
     }
 
@@ -3080,11 +3332,21 @@ ppc64_elf_func_desc_adjust (obfd, info)
        }
     }
 
+  elf_link_hash_traverse (&htab->elf, func_desc_adjust, (PTR) info);
+
   htab->sfpr->_raw_size = ((MAX_SAVE_FPR + 2 - lowest_savef) * 4
                           + (MAX_SAVE_FPR + 2 - lowest_restf) * 4);
 
   if (htab->sfpr->_raw_size == 0)
-    htab->sfpr->_raw_size = 4;
+    {
+      if (!htab->have_undefweak)
+       {
+         _bfd_strip_section_from_output (info, htab->sfpr);
+         return true;
+       }
+
+      htab->sfpr->_raw_size = 4;
+    }
 
   p = (bfd_byte *) bfd_alloc (htab->elf.dynobj, htab->sfpr->_raw_size);
   if (p == NULL)
@@ -3117,7 +3379,6 @@ ppc64_elf_func_desc_adjust (obfd, info)
       bfd_put_32 (htab->elf.dynobj, BLR, p);
     }
 
-  elf_link_hash_traverse (&htab->elf, func_desc_adjust, (PTR) info);
   return true;
 }
 
@@ -3261,14 +3522,48 @@ ppc64_elf_hide_symbol (info, h, force_local)
 
   if (((struct ppc_link_hash_entry *) h)->is_func_descriptor)
     {
-      const char *name;
       struct elf_link_hash_entry *fh = ((struct ppc_link_hash_entry *) h)->oh;
-      struct ppc_link_hash_table *htab;
 
-      name = h->root.root.string - 1;
-      htab = ppc_hash_table (info);
       if (fh == NULL)
-       fh = elf_link_hash_lookup (&htab->elf, name, false, false, false);
+       {
+         const char *p, *q;
+         struct ppc_link_hash_table *htab;
+         char save;
+
+         /* We aren't supposed to use alloca in BFD because on
+            systems which do not have alloca the version in libiberty
+            calls xmalloc, which might cause the program to crash
+            when it runs out of memory.  This function doesn't have a
+            return status, so there's no way to gracefully return an
+            error.  So cheat.  We know that string[-1] can be safely
+            dereferenced;  It's either a string in an ELF string
+            table, or allocated in an objalloc structure.  */
+
+         p = h->root.root.string - 1;
+         save = *p;
+         *(char *) p = '.';
+         htab = ppc_hash_table (info);
+         fh = elf_link_hash_lookup (&htab->elf, p, false, false, false);
+         *(char *) p = save;
+
+         /* Unfortunately, if it so happens that the string we were
+            looking for was allocated immediately before this string,
+            then we overwrote the string terminator.  That's the only
+            reason the lookup should fail.  */
+         if (fh == NULL)
+           {
+             q = h->root.root.string + strlen (h->root.root.string);
+             while (q >= h->root.root.string && *q == *p)
+               --q, --p;
+             if (q < h->root.root.string && *p == '.')
+               fh = elf_link_hash_lookup (&htab->elf, p, false, false, false);
+           }
+         if (fh != NULL)
+           {
+             ((struct ppc_link_hash_entry *) h)->oh = fh;
+             ((struct ppc_link_hash_entry *) fh)->oh = h;
+           }
+       }
       if (fh != NULL)
        _bfd_elf_link_hash_hide_symbol (info, fh, force_local);
     }
@@ -3630,6 +3925,10 @@ ppc64_elf_size_dynamic_sections (output_bfd, info)
          continue;
        }
 
+      /* .plt is in the bss section.  We don't initialise it.  */
+      if ((s->flags & SEC_LOAD) == 0)
+       continue;
+
       /* Allocate memory for the section contents.  We use bfd_zalloc
         here in case unused entries are not reclaimed before the
         section's contents are written out.  This should not happen,
@@ -3656,7 +3955,7 @@ ppc64_elf_size_dynamic_sections (output_bfd, info)
            return false;
        }
 
-      if (htab->splt->_raw_size != 0)
+      if (htab->splt != NULL && htab->splt->_raw_size != 0)
        {
          if (!add_dynamic_entry (DT_PLTGOT, 0)
              || !add_dynamic_entry (DT_PLTRELSZ, 0)
@@ -3912,6 +4211,20 @@ ppc_build_one_stub (gen_entry, in_arg)
       htab->sglink->_cooked_size = p - htab->sglink->contents;
       htab->sglink->reloc_count += 1;
 
+      /* Do the best we can for shared libraries built without
+        exporting ".foo" for each "foo".  This can happen when symbol
+        versioning scripts strip all bar a subset of symbols.  */
+      if (stub_entry->h->oh->root.type != bfd_link_hash_defined
+         && stub_entry->h->oh->root.type != bfd_link_hash_defweak)
+       {
+         /* Point the symbol at the stub.  There may be multiple stubs,
+            we don't really care;  The main thing is to make this sym
+            defined somewhere.  */
+         stub_entry->h->oh->root.type = bfd_link_hash_defined;
+         stub_entry->h->oh->root.u.def.section = stub_entry->stub_sec;
+         stub_entry->h->oh->root.u.def.value = stub_entry->stub_offset;
+       }
+
       /* Now build the stub.  */
       off = stub_entry->h->elf.plt.offset;
       if (off >= (bfd_vma) -2)
@@ -4021,7 +4334,7 @@ ppc_size_one_stub (gen_entry, in_arg)
 
 /* Set up various things so that we can make a list of input sections
    for each output section included in the link.  Returns -1 on error,
-   0 when no stubs will be needed, and 1 on success. */
+   0 when no stubs will be needed, and 1 on success.  */
 
 int
 ppc64_elf_setup_section_lists (output_bfd, info)
@@ -4036,7 +4349,8 @@ ppc64_elf_setup_section_lists (output_bfd, info)
   bfd_size_type amt;
   struct ppc_link_hash_table *htab = ppc_hash_table (info);
 
-  if (htab->sbrlt == NULL)
+  if (htab->elf.root.creator->flavour != bfd_target_elf_flavour
+      || htab->sbrlt == NULL)
     return 0;
 
   /* Count the number of input BFDs and find the top input section id.  */
@@ -4102,16 +4416,13 @@ ppc64_elf_setup_section_lists (output_bfd, info)
    we may insert linker stubs.  */
 
 void
-ppc64_elf_next_input_section (output_bfd, info, isec)
-     bfd *output_bfd;
+ppc64_elf_next_input_section (info, isec)
      struct bfd_link_info *info;
      asection *isec;
 {
   struct ppc_link_hash_table *htab = ppc_hash_table (info);
 
-  if (isec->output_section != NULL
-      && isec->output_section->owner == output_bfd
-      && isec->output_section->index <= htab->top_index)
+  if (isec->output_section->index <= htab->top_index)
     {
       asection **list = htab->input_list + isec->output_section->index;
       if (*list != bfd_abs_section_ptr)
@@ -4285,7 +4596,8 @@ get_local_syms (input_bfd, htab)
             isym = local_syms, shndx = shndx_buf;
           esym < end_sy;
           esym++, isym++, shndx = (shndx ? shndx + 1 : NULL))
-       bfd_elf64_swap_symbol_in (input_bfd, esym, shndx, isym);
+       bfd_elf64_swap_symbol_in (input_bfd, (const PTR) esym,
+                                 (const PTR) shndx, isym);
 
       /* Now we can free the external symbols.  */
       free (shndx_buf);
@@ -4581,12 +4893,10 @@ ppc64_elf_size_stubs (output_bfd, stub_bfd, info, group_size,
       (*htab->layout_sections_again) ();
     }
 
-  if (htab->sbrlt->_raw_size == 0)
-    {
-      _bfd_strip_section_from_output (info, htab->sbrlt);
-      if (htab->srelbrlt != NULL)
-       _bfd_strip_section_from_output (info, htab->srelbrlt);
-    }
+  /* It would be nice to strip .branch_lt from the output if the
+     section is empty, but it's too late.  If we strip sections here,
+     the dynamic symbol table is corrupted since the section symbol
+     for the stripped section isn't written.  */
 
   ret = true;
 
@@ -4600,66 +4910,60 @@ ppc64_elf_size_stubs (output_bfd, stub_bfd, info, group_size,
 }
 
 /* Called after we have determined section placement.  If sections
-   move, we'll be called again.  Provide a value for TOCstart, and
-   store in the output bfd elf_gp.  */
+   move, we'll be called again.  Provide a value for TOCstart.  */
 
-boolean
-ppc64_elf_set_toc (obfd, info)
+bfd_vma
+ppc64_elf_toc (obfd)
      bfd *obfd;
-     struct bfd_link_info *info;
 {
-  if (!info->relocateable)
-    {
-      asection *s;
-      bfd_vma TOCstart;
+  asection *s;
+  bfd_vma TOCstart;
 
-      /* The TOC consists of sections .got, .toc, .tocbss, .plt in that
-        order.  The TOC starts where the first of these sections starts.  */
-      s = bfd_get_section_by_name (obfd, ".got");
-      if (s == NULL)
-       s = bfd_get_section_by_name (obfd, ".toc");
+  /* The TOC consists of sections .got, .toc, .tocbss, .plt in that
+     order.  The TOC starts where the first of these sections starts.  */
+  s = bfd_get_section_by_name (obfd, ".got");
+  if (s == NULL)
+    s = bfd_get_section_by_name (obfd, ".toc");
+  if (s == NULL)
+    s = bfd_get_section_by_name (obfd, ".tocbss");
+  if (s == NULL)
+    s = bfd_get_section_by_name (obfd, ".plt");
+  if (s == NULL)
+    {
+      /* This may happen for
+        o  references to TOC base (SYM@toc / TOC[tc0]) without a
+        .toc directive
+        o  bad linker script
+        o --gc-sections and empty TOC sections
+
+        FIXME: Warn user?  */
+
+      /* Look for a likely section.  We probably won't even be
+        using TOCstart.  */
+      for (s = obfd->sections; s != NULL; s = s->next)
+       if ((s->flags & (SEC_ALLOC | SEC_SMALL_DATA | SEC_READONLY))
+           == (SEC_ALLOC | SEC_SMALL_DATA))
+         break;
       if (s == NULL)
-       s = bfd_get_section_by_name (obfd, ".tocbss");
+       for (s = obfd->sections; s != NULL; s = s->next)
+         if ((s->flags & (SEC_ALLOC | SEC_SMALL_DATA))
+             == (SEC_ALLOC | SEC_SMALL_DATA))
+           break;
       if (s == NULL)
-       s = bfd_get_section_by_name (obfd, ".plt");
+       for (s = obfd->sections; s != NULL; s = s->next)
+         if ((s->flags & (SEC_ALLOC | SEC_READONLY)) == SEC_ALLOC)
+           break;
       if (s == NULL)
-       {
-         /* This may happen for
-            o  references to TOC base (SYM@toc / TOC[tc0]) without a
-            .toc directive
-            o  bad linker script
-            o --gc-sections and empty TOC sections
-
-            FIXME: Warn user?  */
-
-         /* Look for a likely section.  We probably won't even be
-            using TOCstart.  */
-         for (s = obfd->sections; s != NULL; s = s->next)
-           if ((s->flags & (SEC_ALLOC | SEC_SMALL_DATA | SEC_READONLY))
-               == (SEC_ALLOC | SEC_SMALL_DATA))
-             break;
-         if (s == NULL)
-           for (s = obfd->sections; s != NULL; s = s->next)
-             if ((s->flags & (SEC_ALLOC | SEC_SMALL_DATA))
-                 == (SEC_ALLOC | SEC_SMALL_DATA))
-               break;
-         if (s == NULL)
-           for (s = obfd->sections; s != NULL; s = s->next)
-             if ((s->flags & (SEC_ALLOC | SEC_READONLY)) == SEC_ALLOC)
-               break;
-         if (s == NULL)
-           for (s = obfd->sections; s != NULL; s = s->next)
-             if ((s->flags & SEC_ALLOC) == SEC_ALLOC)
-               break;
-       }
+       for (s = obfd->sections; s != NULL; s = s->next)
+         if ((s->flags & SEC_ALLOC) == SEC_ALLOC)
+           break;
+    }
 
-      TOCstart = 0;
-      if (s != NULL)
-       TOCstart = s->output_section->vma + s->output_offset;
+  TOCstart = 0;
+  if (s != NULL)
+    TOCstart = s->output_section->vma + s->output_offset;
 
-      elf_gp (obfd) = TOCstart;
-    }
-  return true;
+  return TOCstart;
 }
 
 /* Build all the stubs associated with the current output file.
@@ -4812,6 +5116,9 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
   /* Disabled until we sort out how ld should choose 'y' vs 'at'.  */
   boolean is_power4 = false;
 
+  if (info->relocateable)
+    return true;
+
   /* Initialize howto table if needed.  */
   if (!ppc64_elf_howto_table[R_PPC64_ADDR32])
     ppc_howto_init ();
@@ -4839,6 +5146,7 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
       unsigned long r_symndx;
       bfd_vma relocation;
       boolean unresolved_reloc;
+      boolean warned;
       long insn;
       struct ppc_stub_hash_entry *stub_entry;
       bfd_vma max_br_offset;
@@ -4846,27 +5154,6 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
 
       r_type = (enum elf_ppc_reloc_type) ELF64_R_TYPE (rel->r_info);
       r_symndx = ELF64_R_SYM (rel->r_info);
-
-      if (info->relocateable)
-       {
-         /* This is a relocatable link.  We don't have to change
-            anything, unless the reloc is against a section symbol,
-            in which case we have to adjust according to where the
-            section symbol winds up in the output section.  */
-         if (r_symndx < symtab_hdr->sh_info)
-           {
-             sym = local_syms + r_symndx;
-             if ((unsigned) ELF_ST_TYPE (sym->st_info) == STT_SECTION)
-               {
-                 sec = local_sections[r_symndx];
-                 rel->r_addend += sec->output_offset + sym->st_value;
-               }
-           }
-         continue;
-       }
-
-      /* This is a final link.  */
-
       offset = rel->r_offset;
       addend = rel->r_addend;
       r = bfd_reloc_other;
@@ -4875,6 +5162,7 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
       h = (struct elf_link_hash_entry *) 0;
       sym_name = (const char *) 0;
       unresolved_reloc = false;
+      warned = false;
 
       if (r_type == R_PPC64_TOC)
        {
@@ -4889,6 +5177,8 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
          sym_name = "<local symbol>";
 
          relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel);
+         /* rel may have changed, update our copy of addend.  */
+         addend = rel->r_addend;
        }
       else
        {
@@ -4929,6 +5219,7 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                               || info->no_undefined
                               || ELF_ST_VISIBILITY (h->other)))))
                return false;
+             warned = true;
            }
        }
 
@@ -4942,8 +5233,8 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
          /* Branch taken prediction relocations.  */
        case R_PPC64_ADDR14_BRTAKEN:
        case R_PPC64_REL14_BRTAKEN:
-         insn = 0x01 << 21; /* 'y' or 't' bit, lowest bit of BO field. */
-         /* Fall thru. */
+         insn = 0x01 << 21; /* 'y' or 't' bit, lowest bit of BO field.  */
+         /* Fall thru.  */
 
          /* Branch not taken prediction relocations.  */
        case R_PPC64_ADDR14_BRNTAKEN:
@@ -4963,8 +5254,12 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
            }
          else
            {
+             from = (offset
+                     + input_section->output_offset
+                     + input_section->output_section->vma);
+
              /* Invert 'y' bit if not the default.  */
-             if ((bfd_signed_vma) (relocation - offset) < 0)
+             if ((bfd_signed_vma) (relocation + addend - from) < 0)
                insn ^= 0x01 << 21;
            }
 
@@ -5025,15 +5320,18 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                 blr.  We can thus call a weak function without first
                 checking whether the function is defined.  We have a
                 blr at the end of .sfpr.  */
+             BFD_ASSERT (htab->sfpr->_raw_size != 0);
              relocation = (htab->sfpr->_raw_size - 4
                            + htab->sfpr->output_offset
                            + htab->sfpr->output_section->vma);
              from = (offset
                      + input_section->output_offset
                      + input_section->output_section->vma);
+
              /* But let's not be silly about it.  If the blr isn't in
                 reach, just go to the next instruction.  */
-             if (relocation - from + (1 << 25) >= (1 << 26))
+             if (relocation - from + (1 << 25) >= (1 << 26)
+                 || htab->sfpr->_raw_size == 0)
                relocation = from + 4;
            }
          break;
@@ -5318,6 +5616,21 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                  relocate = true;
                  if (r_type == R_PPC64_ADDR64 || r_type == R_PPC64_TOC)
                    {
+                     if (is_opd && h != NULL)
+                       {
+                         /* Lie about opd entries.  This case occurs
+                            when building shared libraries and we
+                            reference a function in another shared
+                            lib.  The same thing happens for a weak
+                            definition in an application that's
+                            overridden by a strong definition in a
+                            shared lib.  (I believe this is a generic
+                            bug in binutils handling of weak syms.)
+                            In these cases we won't use the opd
+                            entry in this lib;  We ought to edit the
+                            opd section to remove unused entries.  */
+                         unresolved_reloc = false;
+                       }
                      outrel.r_info = ELF64_R_INFO (0, R_PPC64_RELATIVE);
                    }
                  else
@@ -5475,12 +5788,15 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
          && !(info->shared
               && (input_section->flags & SEC_DEBUGGING) != 0
               && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0))
-       (*_bfd_error_handler)
-         (_("%s(%s+0x%lx): unresolvable relocation against symbol `%s'"),
-          bfd_archive_filename (input_bfd),
-          bfd_get_section_name (input_bfd, input_section),
-          (long) rel->r_offset,
-          h->root.root.string);
+       {
+         (*_bfd_error_handler)
+           (_("%s(%s+0x%lx): unresolvable relocation against symbol `%s'"),
+            bfd_archive_filename (input_bfd),
+            bfd_get_section_name (input_bfd, input_section),
+            (long) rel->r_offset,
+            h->root.root.string);
+         ret = false;
+       }
 
       r = _bfd_final_link_relocate (ppc64_elf_howto_table[(int) r_type],
                                    input_bfd,
@@ -5490,9 +5806,7 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                                    relocation,
                                    addend);
 
-      if (r == bfd_reloc_ok)
-       ;
-      else if (r == bfd_reloc_overflow)
+      if (r != bfd_reloc_ok)
        {
          const char *name;
 
@@ -5523,13 +5837,25 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                name = bfd_section_name (input_bfd, sec);
            }
 
-         if (! ((*info->callbacks->reloc_overflow)
-                (info, name, ppc64_elf_howto_table[(int) r_type]->name,
-                 (bfd_vma) 0, input_bfd, input_section, offset)))
-           return false;
+         if (r == bfd_reloc_overflow)
+           {
+             if (warned)
+               continue;
+             if (!((*info->callbacks->reloc_overflow)
+                   (info, name, ppc64_elf_howto_table[(int) r_type]->name,
+                    rel->r_addend, input_bfd, input_section, offset)))
+               return false;
+           }
+         else
+           {
+             (*_bfd_error_handler)
+               (_("%s(%s+0x%lx): reloc against `%s': error %d"),
+                bfd_archive_filename (input_bfd),
+                bfd_get_section_name (input_bfd, input_section),
+                (long) rel->r_offset, name, (int) r);
+             ret = false;
+           }
        }
-      else
-       ret = false;
     }
 
   return ret;
@@ -5558,7 +5884,7 @@ ppc64_elf_finish_dynamic_symbol (output_bfd, info, h, sym)
       Elf64_External_Rela *loc;
 
       /* This symbol has an entry in the procedure linkage table.  Set
-         it up.  */
+        it up.  */
 
       if (htab->splt == NULL
          || htab->srelplt == NULL
@@ -5585,7 +5911,7 @@ ppc64_elf_finish_dynamic_symbol (output_bfd, info, h, sym)
       Elf64_External_Rela *loc;
 
       /* This symbol has an entry in the global offset table.  Set it
-         up.  */
+        up.  */
 
       if (htab->sgot == NULL || htab->srelgot == NULL)
        abort ();
@@ -5805,12 +6131,14 @@ ppc64_elf_finish_dynamic_sections (output_bfd, info)
 #define elf_backend_plt_header_size PLT_INITIAL_ENTRY_SIZE
 #define elf_backend_can_gc_sections 1
 #define elf_backend_can_refcount 1
+#define elf_backend_rela_normal 1
 
 #define bfd_elf64_bfd_reloc_type_lookup              ppc64_elf_reloc_type_lookup
 #define bfd_elf64_bfd_set_private_flags              ppc64_elf_set_private_flags
 #define bfd_elf64_bfd_merge_private_bfd_data  ppc64_elf_merge_private_bfd_data
 #define bfd_elf64_bfd_link_hash_table_create  ppc64_elf_link_hash_table_create
 #define bfd_elf64_bfd_link_hash_table_free    ppc64_elf_link_hash_table_free
+#define bfd_elf64_get_symbol_info            ppc64_elf_get_symbol_info
 
 #define elf_backend_section_from_shdr        ppc64_elf_section_from_shdr
 #define elf_backend_create_dynamic_sections   ppc64_elf_create_dynamic_sections
This page took 0.062606 seconds and 4 git commands to generate.