+ /* A PLT entry is not required/allowed when:
+
+ 1. We are not using ld.so; because then the PLT entry
+ can't be set up, so we can't use one.
+
+ 2. We know for certain that a symbol is defined in
+ this object, because this object is the application,
+ is linked with -Bsymbolic, or because the symbol is local.
+
+ 3. GC has rendered the entry unused.
+ Note, however, that in an executable all references to the
+ symbol go to the PLT, so we can't turn it off in that case.
+ ??? The correct thing to do here is to reference count
+ all uses of the symbol, not just those to the GOT or PLT. */
+ h->plt.offset = (bfd_vma) -1;
+ h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
+ return true;
+ }
+
+ /* Make sure this symbol is output as a dynamic symbol. */
+ if (h->dynindx == -1)
+ {
+ if (! bfd_elf32_link_record_dynamic_symbol (info, h))
+ return false;
+ }
+ BFD_ASSERT (h->dynindx != -1);
+
+ s = bfd_get_section_by_name (dynobj, ".plt");
+ BFD_ASSERT (s != NULL);
+
+ /* If this is the first .plt entry, make room for the special
+ first entry. */
+ if (s->_raw_size == 0)
+ s->_raw_size += PLT_INITIAL_ENTRY_SIZE;
+
+ /* The PowerPC PLT is actually composed of two parts, the first part
+ is 2 words (for a load and a jump), and then there is a remaining
+ word available at the end. */
+ plt_offset = (PLT_INITIAL_ENTRY_SIZE
+ + (PLT_SLOT_SIZE
+ * ((s->_raw_size - PLT_INITIAL_ENTRY_SIZE)
+ / PLT_ENTRY_SIZE)));
+
+ /* If this symbol is not defined in a regular file, and we are
+ not generating a shared library, then set the symbol to this
+ location in the .plt. This is required to make function
+ pointers compare as equal between the normal executable and
+ the shared library. */
+ if (! info->shared
+ && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
+ {
+ h->root.u.def.section = s;
+ h->root.u.def.value = plt_offset;
+ }
+
+ h->plt.offset = plt_offset;
+
+ /* Make room for this entry. After the 8192nd entry, room
+ for two entries is allocated. */
+ if ((s->_raw_size - PLT_INITIAL_ENTRY_SIZE) / PLT_ENTRY_SIZE
+ >= PLT_NUM_SINGLE_ENTRIES)
+ s->_raw_size += 2 * PLT_ENTRY_SIZE;
+ else
+ s->_raw_size += PLT_ENTRY_SIZE;
+
+ /* We also need to make an entry in the .rela.plt section. */
+ s = bfd_get_section_by_name (dynobj, ".rela.plt");
+ BFD_ASSERT (s != NULL);
+ s->_raw_size += sizeof (Elf32_External_Rela);
+
+ return true;
+ }
+
+ /* If this is a weak symbol, and there is a real definition, the
+ processor independent code will have arranged for us to see the
+ real definition first, and we can just use the same value. */
+ if (h->weakdef != NULL)
+ {
+ BFD_ASSERT (h->weakdef->root.type == bfd_link_hash_defined
+ || h->weakdef->root.type == bfd_link_hash_defweak);
+ h->root.u.def.section = h->weakdef->root.u.def.section;
+ h->root.u.def.value = h->weakdef->root.u.def.value;
+ return true;
+ }
+
+ /* This is a reference to a symbol defined by a dynamic object which
+ is not a function. */
+
+ /* If we are creating a shared library, we must presume that the
+ only references to the symbol are via the global offset table.
+ For such cases we need not do anything here; the relocations will
+ be handled correctly by relocate_section. */
+ if (info->shared)
+ return true;
+
+ /* We must allocate the symbol in our .dynbss section, which will
+ become part of the .bss section of the executable. There will be
+ an entry for this symbol in the .dynsym section. The dynamic
+ object will contain position independent code, so all references
+ from the dynamic object to this symbol will go through the global
+ offset table. The dynamic linker will use the .dynsym entry to
+ determine the address it must put in the global offset table, so
+ both the dynamic object and the regular object will refer to the
+ same memory location for the variable.
+
+ Of course, if the symbol is sufficiently small, we must instead
+ allocate it in .sbss. FIXME: It would be better to do this if and
+ only if there were actually SDAREL relocs for that symbol. */
+
+ if (h->size <= elf_gp_size (dynobj))
+ s = bfd_get_section_by_name (dynobj, ".dynsbss");
+ else
+ s = bfd_get_section_by_name (dynobj, ".dynbss");
+ BFD_ASSERT (s != NULL);
+
+ /* We must generate a R_PPC_COPY reloc to tell the dynamic linker to
+ copy the initial value out of the dynamic object and into the
+ runtime process image. We need to remember the offset into the
+ .rela.bss section we are going to use. */
+ if ((h->root.u.def.section->flags & SEC_ALLOC) != 0)
+ {
+ asection *srel;
+
+ if (h->size <= elf_gp_size (dynobj))
+ srel = bfd_get_section_by_name (dynobj, ".rela.sbss");
+ else
+ srel = bfd_get_section_by_name (dynobj, ".rela.bss");
+ BFD_ASSERT (srel != NULL);
+ srel->_raw_size += sizeof (Elf32_External_Rela);
+ h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_COPY;
+ }
+
+ /* We need to figure out the alignment required for this symbol. I
+ have no idea how ELF linkers handle this. */
+ power_of_two = bfd_log2 (h->size);
+ if (power_of_two > 4)
+ power_of_two = 4;
+
+ /* Apply the required alignment. */
+ s->_raw_size = BFD_ALIGN (s->_raw_size,
+ (bfd_size_type) (1 << power_of_two));
+ if (power_of_two > bfd_get_section_alignment (dynobj, s))
+ {
+ if (! bfd_set_section_alignment (dynobj, s, power_of_two))
+ return false;
+ }
+
+ /* Define the symbol as being at this point in the section. */
+ h->root.u.def.section = s;
+ h->root.u.def.value = s->_raw_size;
+
+ /* Increment the section size to make room for the symbol. */
+ s->_raw_size += h->size;
+
+ return true;
+}
+
+\f
+/* Set the sizes of the dynamic sections. */
+
+static boolean
+ppc_elf_size_dynamic_sections (output_bfd, info)
+ bfd *output_bfd;
+ struct bfd_link_info *info;
+{
+ bfd *dynobj;
+ asection *s;
+ boolean plt;
+ boolean relocs;
+ boolean reltext;
+
+#ifdef DEBUG
+ fprintf (stderr, "ppc_elf_size_dynamic_sections called\n");
+#endif
+
+ dynobj = elf_hash_table (info)->dynobj;
+ BFD_ASSERT (dynobj != NULL);
+
+ if (elf_hash_table (info)->dynamic_sections_created)
+ {
+ /* Set the contents of the .interp section to the interpreter. */
+ if (! info->shared)
+ {
+ s = bfd_get_section_by_name (dynobj, ".interp");
+ BFD_ASSERT (s != NULL);
+ s->_raw_size = sizeof ELF_DYNAMIC_INTERPRETER;
+ s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
+ }
+ }
+ else
+ {
+ /* We may have created entries in the .rela.got, .rela.sdata, and
+ .rela.sdata2 sections. However, if we are not creating the
+ dynamic sections, we will not actually use these entries. Reset
+ the size of .rela.got, et al, which will cause it to get
+ stripped from the output file below. */
+ static char *rela_sections[] = { ".rela.got", ".rela.sdata",
+ ".rela.sdata2", ".rela.sbss",
+ (char *)0 };
+ char **p;
+
+ for (p = rela_sections; *p != (char *)0; p++)
+ {
+ s = bfd_get_section_by_name (dynobj, *p);
+ if (s != NULL)
+ s->_raw_size = 0;
+ }
+ }
+
+ /* The check_relocs and adjust_dynamic_symbol entry points have
+ determined the sizes of the various dynamic sections. Allocate
+ memory for them. */
+ plt = false;
+ relocs = false;
+ reltext = false;
+ for (s = dynobj->sections; s != NULL; s = s->next)
+ {
+ const char *name;
+ boolean strip;
+
+ if ((s->flags & SEC_LINKER_CREATED) == 0)
+ continue;
+
+ /* It's OK to base decisions on the section name, because none
+ of the dynobj section names depend upon the input files. */
+ name = bfd_get_section_name (dynobj, s);
+
+ strip = false;
+
+ if (strcmp (name, ".plt") == 0)
+ {
+ if (s->_raw_size == 0)
+ {
+ /* Strip this section if we don't need it; see the
+ comment below. */
+ strip = true;
+ }
+ else
+ {
+ /* Remember whether there is a PLT. */
+ plt = true;
+ }
+ }
+ else if (strncmp (name, ".rela", 5) == 0)
+ {
+ if (s->_raw_size == 0)
+ {
+ /* If we don't need this section, strip it from the
+ output file. This is mostly to handle .rela.bss and
+ .rela.plt. We must create both sections in
+ create_dynamic_sections, because they must be created
+ before the linker maps input sections to output
+ sections. The linker does that before
+ adjust_dynamic_symbol is called, and it is that
+ function which decides whether anything needs to go
+ into these sections. */
+ strip = true;
+ }
+ else
+ {
+ asection *target;
+ const char *outname;
+
+ /* Remember whether there are any relocation sections. */
+ relocs = true;
+
+ /* If this relocation section applies to a read only
+ section, then we probably need a DT_TEXTREL entry. */
+ outname = bfd_get_section_name (output_bfd,
+ s->output_section);
+ target = bfd_get_section_by_name (output_bfd, outname + 5);
+ if (target != NULL
+ && (target->flags & SEC_READONLY) != 0
+ && (target->flags & SEC_ALLOC) != 0)
+ reltext = true;
+
+ /* We use the reloc_count field as a counter if we need
+ to copy relocs into the output file. */
+ s->reloc_count = 0;
+ }
+ }
+ else if (strcmp (name, ".got") != 0
+ && strcmp (name, ".sdata") != 0
+ && strcmp (name, ".sdata2") != 0)
+ {
+ /* It's not one of our sections, so don't allocate space. */
+ continue;
+ }
+
+ if (strip)
+ {
+ _bfd_strip_section_from_output (info, s);
+ continue;
+ }
+
+ /* Allocate memory for the section contents. */
+ s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->_raw_size);
+ if (s->contents == NULL && s->_raw_size != 0)
+ return false;
+ }
+
+ if (elf_hash_table (info)->dynamic_sections_created)
+ {
+ /* Add some entries to the .dynamic section. We fill in the
+ values later, in ppc_elf_finish_dynamic_sections, but we
+ must add the entries now so that we get the correct size for
+ the .dynamic section. The DT_DEBUG entry is filled in by the
+ dynamic linker and used by the debugger. */
+ if (! info->shared)
+ {
+ if (! bfd_elf32_add_dynamic_entry (info, DT_DEBUG, 0))
+ return false;
+ }
+
+ if (plt)
+ {
+ if (! bfd_elf32_add_dynamic_entry (info, DT_PLTGOT, 0)
+ || ! bfd_elf32_add_dynamic_entry (info, DT_PLTRELSZ, 0)
+ || ! bfd_elf32_add_dynamic_entry (info, DT_PLTREL, DT_RELA)
+ || ! bfd_elf32_add_dynamic_entry (info, DT_JMPREL, 0))
+ return false;
+ }
+
+ if (relocs)
+ {
+ if (! bfd_elf32_add_dynamic_entry (info, DT_RELA, 0)
+ || ! bfd_elf32_add_dynamic_entry (info, DT_RELASZ, 0)
+ || ! bfd_elf32_add_dynamic_entry (info, DT_RELAENT,
+ sizeof (Elf32_External_Rela)))
+ return false;
+ }
+
+ if (reltext)
+ {
+ if (! bfd_elf32_add_dynamic_entry (info, DT_TEXTREL, 0))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+\f
+/* Look through the relocs for a section during the first phase, and
+ allocate space in the global offset table or procedure linkage
+ table. */
+
+static boolean
+ppc_elf_check_relocs (abfd, info, sec, relocs)
+ bfd *abfd;
+ struct bfd_link_info *info;
+ asection *sec;
+ const Elf_Internal_Rela *relocs;
+{
+ bfd *dynobj;
+ Elf_Internal_Shdr *symtab_hdr;
+ struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
+ const Elf_Internal_Rela *rel;
+ const Elf_Internal_Rela *rel_end;
+ bfd_signed_vma *local_got_refcounts;
+ elf_linker_section_t *sdata;
+ elf_linker_section_t *sdata2;
+ asection *sreloc;
+ asection *sgot = NULL;
+ asection *srelgot = NULL;
+
+ if (info->relocateable)
+ return true;
+
+#ifdef DEBUG
+ fprintf (stderr, "ppc_elf_check_relocs called for section %s in %s\n",
+ bfd_get_section_name (abfd, sec),
+ bfd_get_filename (abfd));
+#endif
+
+ /* Create the linker generated sections all the time so that the
+ special symbols are created. */
+
+ if ((sdata = elf_linker_section (abfd, LINKER_SECTION_SDATA)) == NULL)
+ {
+ sdata = ppc_elf_create_linker_section (abfd, info, LINKER_SECTION_SDATA);
+ if (!sdata)
+ return false;
+ }
+
+
+ if ((sdata2 = elf_linker_section (abfd, LINKER_SECTION_SDATA2)) == NULL)
+ {
+ sdata2 = ppc_elf_create_linker_section (abfd, info, LINKER_SECTION_SDATA2);
+ if (!sdata2)
+ return false;
+ }
+
+ dynobj = elf_hash_table (info)->dynobj;
+ symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+ local_got_refcounts = elf_local_got_refcounts (abfd);
+
+ sym_hashes = elf_sym_hashes (abfd);
+ sym_hashes_end = sym_hashes + symtab_hdr->sh_size/sizeof(Elf32_External_Sym);
+ if (!elf_bad_symtab (abfd))
+ sym_hashes_end -= symtab_hdr->sh_info;
+
+ sreloc = NULL;
+
+ rel_end = relocs + sec->reloc_count;
+ for (rel = relocs; rel < rel_end; rel++)
+ {
+ unsigned long r_symndx;
+ struct elf_link_hash_entry *h;
+
+ r_symndx = ELF32_R_SYM (rel->r_info);
+ if (r_symndx < symtab_hdr->sh_info)
+ h = NULL;
+ else
+ h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+
+ /* If a relocation refers to _GLOBAL_OFFSET_TABLE_, create the .got.
+ This shows up in particular in an R_PPC_ADDR32 in the eabi
+ startup code. */
+ if (h && strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0)
+ {
+ if (sgot == NULL)
+ {
+ if (dynobj == NULL)
+ elf_hash_table (info)->dynobj = dynobj = abfd;
+ if (! _bfd_elf_create_got_section (dynobj, info))
+ return false;
+ sgot = bfd_get_section_by_name (dynobj, ".got");
+ BFD_ASSERT (sgot != NULL);
+ }
+ }
+
+ switch (ELF32_R_TYPE (rel->r_info))
+ {
+ /* GOT16 relocations */
+ case R_PPC_GOT16:
+ case R_PPC_GOT16_LO:
+ case R_PPC_GOT16_HI:
+ case R_PPC_GOT16_HA:
+ /* This symbol requires a global offset table entry. */
+
+ if (sgot == NULL)
+ {
+ if (dynobj == NULL)
+ elf_hash_table (info)->dynobj = dynobj = abfd;
+ if (! _bfd_elf_create_got_section (dynobj, info))
+ return false;
+ sgot = bfd_get_section_by_name (dynobj, ".got");
+ BFD_ASSERT (sgot != NULL);
+ }
+
+ if (srelgot == NULL
+ && (h != NULL || info->shared))
+ {
+ srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
+ if (srelgot == NULL)
+ {
+ srelgot = bfd_make_section (dynobj, ".rela.got");
+ if (srelgot == NULL
+ || ! bfd_set_section_flags (dynobj, srelgot,
+ (SEC_ALLOC
+ | SEC_LOAD
+ | SEC_HAS_CONTENTS
+ | SEC_IN_MEMORY
+ | SEC_LINKER_CREATED
+ | SEC_READONLY))
+ || ! bfd_set_section_alignment (dynobj, srelgot, 2))
+ return false;
+ }
+ }
+
+ if (h != NULL)
+ {
+ if (h->got.refcount == -1)
+ {
+ /* Make sure this symbol is output as a dynamic symbol. */
+ if (h->dynindx == -1)
+ if (!bfd_elf32_link_record_dynamic_symbol (info, h))
+ return false;
+
+ /* Allocate space in the .got. */
+ sgot->_raw_size += 4;
+ /* Allocate relocation space. */
+ srelgot->_raw_size += sizeof (Elf32_External_Rela);
+
+ h->got.refcount = 1;
+ }
+ else
+ h->got.refcount++;
+ }
+ else
+ {
+ /* This is a global offset table entry for a local symbol. */
+ if (local_got_refcounts == NULL)
+ {
+ size_t size;
+
+ size = symtab_hdr->sh_info * sizeof (bfd_signed_vma);
+ local_got_refcounts = (bfd_signed_vma *)
+ bfd_alloc (abfd, size);
+ if (local_got_refcounts == NULL)
+ return false;
+ elf_local_got_refcounts (abfd) = local_got_refcounts;
+ memset (local_got_refcounts, -1, size);
+ }
+ if (local_got_refcounts[r_symndx] == -1)
+ {
+ sgot->_raw_size += 4;
+
+ /* If we are generating a shared object, we need to
+ output a R_PPC_RELATIVE reloc so that the
+ dynamic linker can adjust this GOT entry. */
+ if (info->shared)
+ srelgot->_raw_size += sizeof (Elf32_External_Rela);
+
+ local_got_refcounts[r_symndx] = 1;
+ }
+ else
+ local_got_refcounts[r_symndx]++;
+ }
+ break;
+
+ /* Indirect .sdata relocation */
+ case R_PPC_EMB_SDAI16:
+ if (info->shared)
+ {
+ ((*_bfd_error_handler)
+ (_("%s: relocation %s cannot be used when making a shared object"),
+ bfd_get_filename (abfd), "R_PPC_EMB_SDAI16"));
+ return false;
+ }
+
+ if (srelgot == NULL && (h != NULL || info->shared))
+ {
+ srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
+ if (srelgot == NULL)
+ {
+ srelgot = bfd_make_section (dynobj, ".rela.got");
+ if (srelgot == NULL
+ || ! bfd_set_section_flags (dynobj, srelgot,
+ (SEC_ALLOC
+ | SEC_LOAD
+ | SEC_HAS_CONTENTS
+ | SEC_IN_MEMORY
+ | SEC_LINKER_CREATED
+ | SEC_READONLY))
+ || ! bfd_set_section_alignment (dynobj, srelgot, 2))
+ return false;
+ }
+ }
+
+ if (!bfd_elf32_create_pointer_linker_section (abfd, info, sdata, h, rel))
+ return false;
+
+ break;
+
+ /* Indirect .sdata2 relocation */
+ case R_PPC_EMB_SDA2I16:
+ if (info->shared)
+ {
+ ((*_bfd_error_handler)
+ (_("%s: relocation %s cannot be used when making a shared object"),
+ bfd_get_filename (abfd), "R_PPC_EMB_SDA2I16"));
+ return false;
+ }
+
+ if (srelgot == NULL && (h != NULL || info->shared))
+ {
+ srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
+ if (srelgot == NULL)
+ {
+ srelgot = bfd_make_section (dynobj, ".rela.got");
+ if (srelgot == NULL
+ || ! bfd_set_section_flags (dynobj, srelgot,
+ (SEC_ALLOC
+ | SEC_LOAD
+ | SEC_HAS_CONTENTS
+ | SEC_IN_MEMORY
+ | SEC_LINKER_CREATED
+ | SEC_READONLY))
+ || ! bfd_set_section_alignment (dynobj, srelgot, 2))
+ return false;
+ }
+ }
+
+ if (!bfd_elf32_create_pointer_linker_section (abfd, info, sdata2, h, rel))
+ return false;
+
+ break;
+
+ case R_PPC_SDAREL16:
+ case R_PPC_EMB_SDA2REL:
+ case R_PPC_EMB_SDA21:
+ if (info->shared)
+ {
+ ((*_bfd_error_handler)
+ (_("%s: relocation %s cannot be used when making a shared object"),
+ bfd_get_filename (abfd),
+ ppc_elf_howto_table[(int)ELF32_R_TYPE (rel->r_info)]->name));
+ return false;
+ }
+ break;
+
+ case R_PPC_PLT32:
+ case R_PPC_PLTREL24:
+ case R_PPC_PLT16_LO:
+ case R_PPC_PLT16_HI:
+ case R_PPC_PLT16_HA:
+#ifdef DEBUG
+ fprintf (stderr, "Reloc requires a PLT entry\n");
+#endif
+ /* 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. */
+
+ if (h == NULL)
+ {
+ /* It does not make sense to have a procedure linkage
+ table entry for a local symbol. */
+ bfd_set_error (bfd_error_bad_value);
+ return false;
+ }
+
+ /* Make sure this symbol is output as a dynamic symbol. */
+ if (h->dynindx == -1)
+ {
+ if (! bfd_elf32_link_record_dynamic_symbol (info, h))
+ return false;
+ }
+ if (h->plt.refcount == -1)
+ {
+ h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
+ h->plt.refcount = 1;
+ }
+ else
+ h->plt.refcount++;
+ break;
+
+ /* The following relocations don't need to propagate the
+ relocation if linking a shared object since they are
+ section relative. */
+ case R_PPC_SECTOFF:
+ case R_PPC_SECTOFF_LO:
+ case R_PPC_SECTOFF_HI:
+ case R_PPC_SECTOFF_HA:
+ break;
+
+ /* This refers only to functions defined in the shared library */
+ case R_PPC_LOCAL24PC:
+ break;
+
+ /* This relocation describes the C++ object vtable hierarchy.
+ Reconstruct it for later use during GC. */
+ case R_PPC_GNU_VTINHERIT:
+ if (!_bfd_elf32_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
+ return false;
+ break;
+
+ /* This relocation describes which C++ vtable entries are actually
+ used. Record for later use during GC. */
+ case R_PPC_GNU_VTENTRY:
+ if (!_bfd_elf32_gc_record_vtentry (abfd, sec, h, rel->r_addend))
+ return false;
+ break;
+
+ /* When creating a shared object, we must copy these
+ relocs into the output file. We create a reloc
+ section in dynobj and make room for the reloc. */
+ case R_PPC_REL24:
+ case R_PPC_REL14:
+ case R_PPC_REL14_BRTAKEN:
+ case R_PPC_REL14_BRNTAKEN:
+ case R_PPC_REL32:
+ if (h == NULL
+ || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0)
+ break;
+ /* fall through */
+
+ default:
+ if (info->shared)
+ {
+#ifdef DEBUG
+ fprintf (stderr, "ppc_elf_check_relocs need to create relocation for %s\n",
+ (h && h->root.root.string) ? h->root.root.string : "<unknown>");
+#endif
+ if (sreloc == NULL)
+ {
+ const char *name;
+
+ name = (bfd_elf_string_from_elf_section
+ (abfd,
+ elf_elfheader (abfd)->e_shstrndx,
+ elf_section_data (sec)->rel_hdr.sh_name));
+ if (name == NULL)
+ return false;
+
+ BFD_ASSERT (strncmp (name, ".rela", 5) == 0
+ && strcmp (bfd_get_section_name (abfd, sec),
+ name + 5) == 0);
+
+ sreloc = bfd_get_section_by_name (dynobj, name);
+ if (sreloc == NULL)
+ {
+ flagword flags;
+
+ sreloc = bfd_make_section (dynobj, name);
+ flags = (SEC_HAS_CONTENTS | SEC_READONLY
+ | SEC_IN_MEMORY | SEC_LINKER_CREATED);
+ if ((sec->flags & SEC_ALLOC) != 0)
+ flags |= SEC_ALLOC | SEC_LOAD;
+ if (sreloc == NULL
+ || ! bfd_set_section_flags (dynobj, sreloc, flags)
+ || ! bfd_set_section_alignment (dynobj, sreloc, 2))
+ return false;
+ }
+ }
+
+ sreloc->_raw_size += sizeof (Elf32_External_Rela);
+
+ /* FIXME: We should here do what the m68k and i386
+ backends do: if the reloc is pc-relative, record it
+ in case it turns out that the reloc is unnecessary
+ because the symbol is forced local by versioning or
+ we are linking with -Bdynamic. Fortunately this
+ case is not frequent. */
+ }
+
+ break;
+ }
+ }
+
+ return true;
+}
+
+/* Return the section that should be marked against GC for a given
+ relocation. */
+
+static asection *
+ppc_elf_gc_mark_hook (abfd, info, rel, h, sym)
+ bfd *abfd;
+ struct bfd_link_info *info ATTRIBUTE_UNUSED;
+ Elf_Internal_Rela *rel;
+ struct elf_link_hash_entry *h;
+ Elf_Internal_Sym *sym;
+{
+ if (h != NULL)
+ {
+ switch (ELF32_R_TYPE (rel->r_info))
+ {
+ case R_PPC_GNU_VTINHERIT:
+ case R_PPC_GNU_VTENTRY:
+ break;
+
+ default:
+ switch (h->root.type)
+ {
+ case bfd_link_hash_defined:
+ case bfd_link_hash_defweak:
+ return h->root.u.def.section;
+
+ case bfd_link_hash_common:
+ return h->root.u.c.p->section;
+
+ default:
+ break;
+ }
+ }
+ }
+ else
+ {
+ if (!(elf_bad_symtab (abfd)
+ && ELF_ST_BIND (sym->st_info) != STB_LOCAL)
+ && ! ((sym->st_shndx <= 0 || sym->st_shndx >= SHN_LORESERVE)
+ && sym->st_shndx != SHN_COMMON))
+ {
+ return bfd_section_from_elf_index (abfd, sym->st_shndx);
+ }
+ }
+
+ return NULL;
+}
+
+/* Update the got entry reference counts for the section being removed. */
+
+static boolean
+ppc_elf_gc_sweep_hook (abfd, info, sec, relocs)
+ bfd *abfd;
+ struct bfd_link_info *info ATTRIBUTE_UNUSED;
+ asection *sec;
+ const Elf_Internal_Rela *relocs;
+{
+ Elf_Internal_Shdr *symtab_hdr;
+ struct elf_link_hash_entry **sym_hashes;
+ bfd_signed_vma *local_got_refcounts;
+ const Elf_Internal_Rela *rel, *relend;
+ unsigned long r_symndx;
+ struct elf_link_hash_entry *h;
+
+ symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+ sym_hashes = elf_sym_hashes (abfd);
+ local_got_refcounts = elf_local_got_refcounts (abfd);
+
+ relend = relocs + sec->reloc_count;
+ for (rel = relocs; rel < relend; rel++)
+ switch (ELF32_R_TYPE (rel->r_info))
+ {
+ case R_PPC_GOT16:
+ case R_PPC_GOT16_LO:
+ case R_PPC_GOT16_HI:
+ case R_PPC_GOT16_HA:
+ r_symndx = ELF32_R_SYM (rel->r_info);
+ if (r_symndx >= symtab_hdr->sh_info)
+ {
+ h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+ if (h->got.refcount > 0)
+ h->got.refcount--;
+ }
+ else if (local_got_refcounts != NULL)
+ {
+ if (local_got_refcounts[r_symndx] > 0)
+ local_got_refcounts[r_symndx]--;
+ }
+ break;
+
+ case R_PPC_PLT32:
+ case R_PPC_PLTREL24:
+ case R_PPC_PLT16_LO:
+ case R_PPC_PLT16_HI:
+ case R_PPC_PLT16_HA:
+ r_symndx = ELF32_R_SYM (rel->r_info);
+ if (r_symndx >= symtab_hdr->sh_info)
+ {
+ h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+ if (h->plt.refcount > 0)
+ h->plt.refcount--;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return true;
+}
+\f
+/* Hook called by the linker routine which adds symbols from an object
+ file. We use it to put .comm items in .sbss, and not .bss. */
+
+/*ARGSUSED*/
+static boolean
+ppc_elf_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp)
+ bfd *abfd;
+ struct bfd_link_info *info;
+ const Elf_Internal_Sym *sym;
+ const char **namep ATTRIBUTE_UNUSED;
+ flagword *flagsp ATTRIBUTE_UNUSED;
+ asection **secp;
+ bfd_vma *valp;
+{
+ if (sym->st_shndx == SHN_COMMON
+ && !info->relocateable
+ && sym->st_size <= (bfd_vma) bfd_get_gp_size (abfd))
+ {
+ /* Common symbols less than or equal to -G nn bytes are automatically
+ put into .sdata. */
+ elf_linker_section_t *sdata
+ = ppc_elf_create_linker_section (abfd, info, LINKER_SECTION_SDATA);
+
+ if (!sdata->bss_section)
+ {
+ /* We don't go through bfd_make_section, because we don't
+ want to attach this common section to DYNOBJ. The linker
+ will move the symbols to the appropriate output section
+ when it defines common symbols. */
+ sdata->bss_section = ((asection *)
+ bfd_zalloc (abfd, sizeof (asection)));
+ if (sdata->bss_section == NULL)
+ return false;
+ sdata->bss_section->name = sdata->bss_name;
+ sdata->bss_section->flags = SEC_IS_COMMON;
+ sdata->bss_section->output_section = sdata->bss_section;
+ sdata->bss_section->symbol =
+ (asymbol *) bfd_zalloc (abfd, sizeof (asymbol));
+ sdata->bss_section->symbol_ptr_ptr =
+ (asymbol **) bfd_zalloc (abfd, sizeof (asymbol *));
+ if (sdata->bss_section->symbol == NULL
+ || sdata->bss_section->symbol_ptr_ptr == NULL)
+ return false;
+ sdata->bss_section->symbol->name = sdata->bss_name;
+ sdata->bss_section->symbol->flags = BSF_SECTION_SYM;
+ sdata->bss_section->symbol->section = sdata->bss_section;
+ *sdata->bss_section->symbol_ptr_ptr = sdata->bss_section->symbol;
+ }
+
+ *secp = sdata->bss_section;
+ *valp = sym->st_size;
+ }
+
+ return true;
+}
+
+\f
+/* Finish up dynamic symbol handling. We set the contents of various
+ dynamic sections here. */
+
+static boolean
+ppc_elf_finish_dynamic_symbol (output_bfd, info, h, sym)
+ bfd *output_bfd;
+ struct bfd_link_info *info;
+ struct elf_link_hash_entry *h;
+ Elf_Internal_Sym *sym;
+{
+ bfd *dynobj;
+
+#ifdef DEBUG
+ fprintf (stderr, "ppc_elf_finish_dynamic_symbol called for %s",
+ h->root.root.string);
+#endif
+
+ dynobj = elf_hash_table (info)->dynobj;
+ BFD_ASSERT (dynobj != NULL);
+
+ if (h->plt.offset != (bfd_vma) -1)
+ {
+ asection *splt;
+ asection *srela;
+ Elf_Internal_Rela rela;
+ bfd_vma reloc_index;
+
+#ifdef DEBUG
+ fprintf (stderr, ", plt_offset = %d", h->plt.offset);
+#endif
+
+ /* This symbol has an entry in the procedure linkage table. Set
+ it up. */
+
+ BFD_ASSERT (h->dynindx != -1);
+
+ splt = bfd_get_section_by_name (dynobj, ".plt");
+ srela = bfd_get_section_by_name (dynobj, ".rela.plt");
+ BFD_ASSERT (splt != NULL && srela != NULL);
+
+ /* We don't need to fill in the .plt. The ppc dynamic linker
+ will fill it in. */
+
+ /* Fill in the entry in the .rela.plt section. */
+ rela.r_offset = (splt->output_section->vma
+ + splt->output_offset
+ + h->plt.offset);
+ rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_JMP_SLOT);
+ rela.r_addend = 0;
+
+ reloc_index = (h->plt.offset - PLT_INITIAL_ENTRY_SIZE) / PLT_SLOT_SIZE;
+ if (reloc_index > PLT_NUM_SINGLE_ENTRIES)
+ reloc_index -= (reloc_index - PLT_NUM_SINGLE_ENTRIES) / 2;
+ bfd_elf32_swap_reloca_out (output_bfd, &rela,
+ ((Elf32_External_Rela *) srela->contents
+ + reloc_index));
+
+ if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
+ {
+ /* Mark the symbol as undefined, rather than as defined in
+ the .plt section. Leave the value alone. */
+ sym->st_shndx = SHN_UNDEF;
+ }
+ }
+
+ if (h->got.offset != (bfd_vma) -1)
+ {
+ asection *sgot;
+ asection *srela;
+ Elf_Internal_Rela rela;
+
+ /* This symbol has an entry in the global offset table. Set it
+ up. */
+
+ sgot = bfd_get_section_by_name (dynobj, ".got");
+ srela = bfd_get_section_by_name (dynobj, ".rela.got");
+ BFD_ASSERT (sgot != NULL && srela != NULL);
+
+ rela.r_offset = (sgot->output_section->vma
+ + sgot->output_offset
+ + (h->got.offset &~ 1));
+
+ /* If this is a -Bsymbolic link, and the symbol is defined
+ locally, we just want to emit a RELATIVE reloc. The entry in
+ the global offset table will already have been initialized in
+ the relocate_section function. */
+ if (info->shared
+ && (info->symbolic || h->dynindx == -1)
+ && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR))
+ {
+ rela.r_info = ELF32_R_INFO (0, R_PPC_RELATIVE);
+ rela.r_addend = (h->root.u.def.value
+ + h->root.u.def.section->output_section->vma
+ + h->root.u.def.section->output_offset);
+ }
+ else
+ {
+ BFD_ASSERT((h->got.offset & 1) == 0);
+ bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + h->got.offset);
+ rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_GLOB_DAT);
+ rela.r_addend = 0;
+ }
+
+ bfd_elf32_swap_reloca_out (output_bfd, &rela,
+ ((Elf32_External_Rela *) srela->contents
+ + srela->reloc_count));
+ ++srela->reloc_count;
+ }
+
+ if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_COPY) != 0)
+ {
+ asection *s;
+ Elf_Internal_Rela rela;
+
+ /* This symbols needs a copy reloc. Set it up. */
+
+#ifdef DEBUG
+ fprintf (stderr, ", copy");
+#endif
+
+ BFD_ASSERT (h->dynindx != -1);
+
+ if (h->size <= elf_gp_size (dynobj))
+ s = bfd_get_section_by_name (h->root.u.def.section->owner,
+ ".rela.sbss");
+ else
+ s = bfd_get_section_by_name (h->root.u.def.section->owner,
+ ".rela.bss");
+ BFD_ASSERT (s != NULL);
+
+ rela.r_offset = (h->root.u.def.value
+ + h->root.u.def.section->output_section->vma
+ + h->root.u.def.section->output_offset);
+ rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_COPY);
+ rela.r_addend = 0;
+ bfd_elf32_swap_reloca_out (output_bfd, &rela,
+ ((Elf32_External_Rela *) s->contents
+ + s->reloc_count));
+ ++s->reloc_count;
+ }
+
+#ifdef DEBUG
+ fprintf (stderr, "\n");
+#endif
+
+ /* Mark some specially defined symbols as absolute. */
+ if (strcmp (h->root.root.string, "_DYNAMIC") == 0
+ || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0
+ || strcmp (h->root.root.string, "_PROCEDURE_LINKAGE_TABLE_") == 0)
+ sym->st_shndx = SHN_ABS;
+
+ return true;
+}
+
+\f
+/* Finish up the dynamic sections. */
+
+static boolean
+ppc_elf_finish_dynamic_sections (output_bfd, info)
+ bfd *output_bfd;
+ struct bfd_link_info *info;
+{
+ asection *sdyn;
+ bfd *dynobj = elf_hash_table (info)->dynobj;
+ asection *sgot = bfd_get_section_by_name (dynobj, ".got");
+
+#ifdef DEBUG
+ fprintf (stderr, "ppc_elf_finish_dynamic_sections called\n");
+#endif
+
+ sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
+
+ if (elf_hash_table (info)->dynamic_sections_created)
+ {
+ asection *splt;
+ Elf32_External_Dyn *dyncon, *dynconend;
+
+ splt = bfd_get_section_by_name (dynobj, ".plt");
+ BFD_ASSERT (splt != NULL && sdyn != NULL);
+
+ dyncon = (Elf32_External_Dyn *) sdyn->contents;
+ dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->_raw_size);
+ for (; dyncon < dynconend; dyncon++)
+ {
+ Elf_Internal_Dyn dyn;
+ const char *name;
+ boolean size;
+
+ bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn);
+
+ switch (dyn.d_tag)
+ {
+ case DT_PLTGOT: name = ".plt"; size = false; break;
+ case DT_PLTRELSZ: name = ".rela.plt"; size = true; break;
+ case DT_JMPREL: name = ".rela.plt"; size = false; break;
+ default: name = NULL; size = false; break;
+ }
+
+ if (name != NULL)
+ {
+ asection *s;
+
+ s = bfd_get_section_by_name (output_bfd, name);
+ if (s == NULL)
+ dyn.d_un.d_val = 0;
+ else
+ {
+ if (! size)
+ dyn.d_un.d_ptr = s->vma;
+ else
+ {
+ if (s->_cooked_size != 0)
+ dyn.d_un.d_val = s->_cooked_size;
+ else
+ dyn.d_un.d_val = s->_raw_size;
+ }
+ }
+ bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
+ }
+ }
+ }
+
+ /* Add a blrl instruction at _GLOBAL_OFFSET_TABLE_-4 so that a function can
+ easily find the address of the _GLOBAL_OFFSET_TABLE_. */
+ if (sgot)
+ {
+ unsigned char *contents = sgot->contents;
+ bfd_put_32 (output_bfd, 0x4e800021 /* blrl */, contents);
+
+ if (sdyn == NULL)
+ bfd_put_32 (output_bfd, (bfd_vma) 0, contents+4);
+ else
+ bfd_put_32 (output_bfd,
+ sdyn->output_section->vma + sdyn->output_offset,
+ contents+4);
+
+ elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4;
+ }
+
+ return true;
+}
+
+\f
+/* The RELOCATE_SECTION function is called by the ELF backend linker
+ to handle the relocations for a section.
+
+ The relocs are always passed as Rela structures; if the section
+ actually uses Rel structures, the r_addend field will always be
+ zero.
+
+ This function is responsible for adjust the section contents as
+ necessary, and (if using Rela relocs and generating a
+ relocateable output file) adjusting the reloc addend as
+ necessary.
+
+ This function does not have to worry about setting the reloc
+ address or the reloc symbol index.
+
+ LOCAL_SYMS is a pointer to the swapped in local symbols.
+
+ LOCAL_SECTIONS is an array giving the section in the input file
+ corresponding to the st_shndx field of each local symbol.
+
+ The global hash table entry for the global symbols can be found
+ via elf_sym_hashes (input_bfd).
+
+ When generating relocateable output, this function must handle
+ STB_LOCAL/STT_SECTION symbols specially. The output symbol is
+ going to be the section symbol corresponding to the output
+ section, which means that the addend must be adjusted
+ accordingly. */
+
+static boolean
+ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
+ contents, relocs, local_syms, local_sections)
+ bfd *output_bfd;
+ struct bfd_link_info *info;
+ bfd *input_bfd;
+ asection *input_section;
+ bfd_byte *contents;
+ Elf_Internal_Rela *relocs;
+ Elf_Internal_Sym *local_syms;
+ asection **local_sections;
+{
+ Elf_Internal_Shdr *symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+ struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (input_bfd);
+ bfd *dynobj = elf_hash_table (info)->dynobj;
+ elf_linker_section_t *sdata = (dynobj) ? elf_linker_section (dynobj, LINKER_SECTION_SDATA) : NULL;
+ elf_linker_section_t *sdata2 = (dynobj) ? elf_linker_section (dynobj, LINKER_SECTION_SDATA2) : NULL;
+ Elf_Internal_Rela *rel = relocs;
+ Elf_Internal_Rela *relend = relocs + input_section->reloc_count;
+ asection *sreloc = NULL;
+ asection *splt;
+ asection *sgot;
+ bfd_vma *local_got_offsets;
+ boolean ret = true;
+ long insn;
+
+#ifdef DEBUG
+ fprintf (stderr, "ppc_elf_relocate_section called for %s section %s, %ld relocations%s\n",
+ bfd_get_filename (input_bfd),
+ bfd_section_name(input_bfd, input_section),
+ (long)input_section->reloc_count,
+ (info->relocateable) ? " (relocatable)" : "");
+#endif
+
+ if (!ppc_elf_howto_table[ R_PPC_ADDR32 ]) /* Initialize howto table if needed */
+ ppc_elf_howto_init ();
+
+ local_got_offsets = elf_local_got_offsets (input_bfd);
+
+ splt = sgot = NULL;
+ if (dynobj != NULL)
+ {
+ splt = bfd_get_section_by_name (dynobj, ".plt");
+ sgot = bfd_get_section_by_name (dynobj, ".got");
+ }
+
+ for (; rel < relend; rel++)
+ {
+ enum elf_ppc_reloc_type r_type = (enum elf_ppc_reloc_type)ELF32_R_TYPE (rel->r_info);
+ bfd_vma offset = rel->r_offset;
+ bfd_vma addend = rel->r_addend;
+ bfd_reloc_status_type r = bfd_reloc_other;
+ Elf_Internal_Sym *sym = (Elf_Internal_Sym *)0;
+ asection *sec = (asection *)0;
+ struct elf_link_hash_entry *h = (struct elf_link_hash_entry *)0;
+ const char *sym_name = (const char *)0;
+ reloc_howto_type *howto;
+ unsigned long r_symndx;
+ bfd_vma relocation;
+
+ /* Unknown relocation handling */
+ if ((unsigned)r_type >= (unsigned)R_PPC_max || !ppc_elf_howto_table[(int)r_type])
+ {
+ (*_bfd_error_handler) (_("%s: unknown relocation type %d"),
+ bfd_get_filename (input_bfd),
+ (int)r_type);
+
+ bfd_set_error (bfd_error_bad_value);
+ ret = false;
+ continue;