+ case R_ARM_GOTOFFFUNCDESC:
+ {
+ if (h == NULL)
+ {
+ struct fdpic_local *local_fdpic_cnts = elf32_arm_local_fdpic_cnts(input_bfd);
+ int dynindx = elf_section_data (sym_sec->output_section)->dynindx;
+ int offset = local_fdpic_cnts[r_symndx].funcdesc_offset & ~1;
+ bfd_vma addr = dynreloc_value - sym_sec->output_section->vma;
+ bfd_vma seg = -1;
+
+ if (bfd_link_pic(info) && dynindx == 0)
+ abort();
+
+ /* Resolve relocation. */
+ bfd_put_32(output_bfd, (offset + sgot->output_offset)
+ , contents + rel->r_offset);
+ /* Emit R_ARM_FUNCDESC_VALUE or two fixups on funcdesc if
+ not done yet. */
+ arm_elf_fill_funcdesc(output_bfd, info,
+ &local_fdpic_cnts[r_symndx].funcdesc_offset,
+ dynindx, offset, addr, dynreloc_value, seg);
+ }
+ else
+ {
+ int dynindx;
+ int offset = eh->fdpic_cnts.funcdesc_offset & ~1;
+ bfd_vma addr;
+ bfd_vma seg = -1;
+
+ /* For static binaries, sym_sec can be null. */
+ if (sym_sec)
+ {
+ dynindx = elf_section_data (sym_sec->output_section)->dynindx;
+ addr = dynreloc_value - sym_sec->output_section->vma;
+ }
+ else
+ {
+ dynindx = 0;
+ addr = 0;
+ }
+
+ if (bfd_link_pic(info) && dynindx == 0)
+ abort();
+
+ /* This case cannot occur since funcdesc is allocated by
+ the dynamic loader so we cannot resolve the relocation. */
+ if (h->dynindx != -1)
+ abort();
+
+ /* Resolve relocation. */
+ bfd_put_32(output_bfd, (offset + sgot->output_offset),
+ contents + rel->r_offset);
+ /* Emit R_ARM_FUNCDESC_VALUE on funcdesc if not done yet. */
+ arm_elf_fill_funcdesc(output_bfd, info,
+ &eh->fdpic_cnts.funcdesc_offset,
+ dynindx, offset, addr, dynreloc_value, seg);
+ }
+ }
+ *unresolved_reloc_p = FALSE;
+ return bfd_reloc_ok;
+
+ case R_ARM_GOTFUNCDESC:
+ {
+ if (h != NULL)
+ {
+ Elf_Internal_Rela outrel;
+
+ /* Resolve relocation. */
+ bfd_put_32(output_bfd, ((eh->fdpic_cnts.gotfuncdesc_offset & ~1)
+ + sgot->output_offset),
+ contents + rel->r_offset);
+ /* Add funcdesc and associated R_ARM_FUNCDESC_VALUE. */
+ if(h->dynindx == -1)
+ {
+ int dynindx;
+ int offset = eh->fdpic_cnts.funcdesc_offset & ~1;
+ bfd_vma addr;
+ bfd_vma seg = -1;
+
+ /* For static binaries sym_sec can be null. */
+ if (sym_sec)
+ {
+ dynindx = elf_section_data (sym_sec->output_section)->dynindx;
+ addr = dynreloc_value - sym_sec->output_section->vma;
+ }
+ else
+ {
+ dynindx = 0;
+ addr = 0;
+ }
+
+ /* Emit R_ARM_FUNCDESC_VALUE on funcdesc if not done yet. */
+ arm_elf_fill_funcdesc(output_bfd, info,
+ &eh->fdpic_cnts.funcdesc_offset,
+ dynindx, offset, addr, dynreloc_value, seg);
+ }
+
+ /* Add a dynamic relocation on GOT entry if not already done. */
+ if ((eh->fdpic_cnts.gotfuncdesc_offset & 1) == 0)
+ {
+ if (h->dynindx == -1)
+ {
+ outrel.r_info = ELF32_R_INFO (0, R_ARM_RELATIVE);
+ if (h->root.type == bfd_link_hash_undefweak)
+ bfd_put_32(output_bfd, 0, sgot->contents
+ + (eh->fdpic_cnts.gotfuncdesc_offset & ~1));
+ else
+ bfd_put_32(output_bfd, sgot->output_section->vma
+ + sgot->output_offset
+ + (eh->fdpic_cnts.funcdesc_offset & ~1),
+ sgot->contents
+ + (eh->fdpic_cnts.gotfuncdesc_offset & ~1));
+ }
+ else
+ {
+ outrel.r_info = ELF32_R_INFO (h->dynindx, R_ARM_FUNCDESC);
+ }
+ outrel.r_offset = sgot->output_section->vma
+ + sgot->output_offset
+ + (eh->fdpic_cnts.gotfuncdesc_offset & ~1);
+ outrel.r_addend = 0;
+ if (h->dynindx == -1 && !bfd_link_pic(info))
+ if (h->root.type == bfd_link_hash_undefweak)
+ arm_elf_add_rofixup(output_bfd, globals->srofixup, -1);
+ else
+ arm_elf_add_rofixup(output_bfd, globals->srofixup,
+ outrel.r_offset);
+ else
+ elf32_arm_add_dynreloc (output_bfd, info, srelgot, &outrel);
+ eh->fdpic_cnts.gotfuncdesc_offset |= 1;
+ }
+ }
+ else
+ {
+ /* Such relocation on static function should not have been
+ emitted by the compiler. */
+ abort();
+ }
+ }
+ *unresolved_reloc_p = FALSE;
+ return bfd_reloc_ok;
+
+ case R_ARM_FUNCDESC:
+ {
+ if (h == NULL)
+ {
+ struct fdpic_local *local_fdpic_cnts = elf32_arm_local_fdpic_cnts(input_bfd);
+ Elf_Internal_Rela outrel;
+ int dynindx = elf_section_data (sym_sec->output_section)->dynindx;
+ int offset = local_fdpic_cnts[r_symndx].funcdesc_offset & ~1;
+ bfd_vma addr = dynreloc_value - sym_sec->output_section->vma;
+ bfd_vma seg = -1;
+
+ if (bfd_link_pic(info) && dynindx == 0)
+ abort();
+
+ /* Replace static FUNCDESC relocation with a
+ R_ARM_RELATIVE dynamic relocation or with a rofixup for
+ executable. */
+ outrel.r_info = ELF32_R_INFO (0, R_ARM_RELATIVE);
+ outrel.r_offset = input_section->output_section->vma
+ + input_section->output_offset + rel->r_offset;
+ outrel.r_addend = 0;
+ if (bfd_link_pic(info))
+ elf32_arm_add_dynreloc (output_bfd, info, srelgot, &outrel);
+ else
+ arm_elf_add_rofixup(output_bfd, globals->srofixup, outrel.r_offset);
+
+ bfd_put_32 (input_bfd, sgot->output_section->vma
+ + sgot->output_offset + offset, hit_data);
+
+ /* Emit R_ARM_FUNCDESC_VALUE on funcdesc if not done yet. */
+ arm_elf_fill_funcdesc(output_bfd, info,
+ &local_fdpic_cnts[r_symndx].funcdesc_offset,
+ dynindx, offset, addr, dynreloc_value, seg);
+ }
+ else
+ {
+ if (h->dynindx == -1)
+ {
+ int dynindx;
+ int offset = eh->fdpic_cnts.funcdesc_offset & ~1;
+ bfd_vma addr;
+ bfd_vma seg = -1;
+ Elf_Internal_Rela outrel;
+
+ /* For static binaries sym_sec can be null. */
+ if (sym_sec)
+ {
+ dynindx = elf_section_data (sym_sec->output_section)->dynindx;
+ addr = dynreloc_value - sym_sec->output_section->vma;
+ }
+ else
+ {
+ dynindx = 0;
+ addr = 0;
+ }
+
+ if (bfd_link_pic(info) && dynindx == 0)
+ abort();
+
+ /* Replace static FUNCDESC relocation with a
+ R_ARM_RELATIVE dynamic relocation. */
+ outrel.r_info = ELF32_R_INFO (0, R_ARM_RELATIVE);
+ outrel.r_offset = input_section->output_section->vma
+ + input_section->output_offset + rel->r_offset;
+ outrel.r_addend = 0;
+ if (bfd_link_pic(info))
+ elf32_arm_add_dynreloc (output_bfd, info, srelgot, &outrel);
+ else
+ arm_elf_add_rofixup(output_bfd, globals->srofixup, outrel.r_offset);
+
+ bfd_put_32 (input_bfd, sgot->output_section->vma
+ + sgot->output_offset + offset, hit_data);
+
+ /* Emit R_ARM_FUNCDESC_VALUE on funcdesc if not done yet. */
+ arm_elf_fill_funcdesc(output_bfd, info,
+ &eh->fdpic_cnts.funcdesc_offset,
+ dynindx, offset, addr, dynreloc_value, seg);
+ }
+ else
+ {
+ Elf_Internal_Rela outrel;
+
+ /* Add a dynamic relocation. */
+ outrel.r_info = ELF32_R_INFO (h->dynindx, R_ARM_FUNCDESC);
+ outrel.r_offset = input_section->output_section->vma
+ + input_section->output_offset + rel->r_offset;
+ outrel.r_addend = 0;
+ elf32_arm_add_dynreloc (output_bfd, info, srelgot, &outrel);
+ }
+ }
+ }
+ *unresolved_reloc_p = FALSE;
+ return bfd_reloc_ok;
+