+ 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;
+
+ case R_ARM_THM_BF16:
+ {
+ bfd_vma relocation;
+ bfd_vma upper_insn = bfd_get_16 (input_bfd, hit_data);
+ bfd_vma lower_insn = bfd_get_16 (input_bfd, hit_data + 2);
+
+ if (globals->use_rel)
+ {
+ bfd_vma immA = (upper_insn & 0x001f);
+ bfd_vma immB = (lower_insn & 0x07fe) >> 1;
+ bfd_vma immC = (lower_insn & 0x0800) >> 11;
+ addend = (immA << 12);
+ addend |= (immB << 2);
+ addend |= (immC << 1);
+ addend |= 1;
+ /* Sign extend. */
+ signed_addend = (addend & 0x10000) ? addend - (1 << 17) : addend;
+ }
+
+ relocation = value + signed_addend;
+ relocation -= (input_section->output_section->vma
+ + input_section->output_offset
+ + rel->r_offset);
+
+ /* Put RELOCATION back into the insn. */
+ {
+ bfd_vma immA = (relocation & 0x0001f000) >> 12;
+ bfd_vma immB = (relocation & 0x00000ffc) >> 2;
+ bfd_vma immC = (relocation & 0x00000002) >> 1;
+
+ upper_insn = (upper_insn & 0xffe0) | immA;
+ lower_insn = (lower_insn & 0xf001) | (immC << 11) | (immB << 1);
+ }
+
+ /* Put the relocated value back in the object file: */
+ bfd_put_16 (input_bfd, upper_insn, hit_data);
+ bfd_put_16 (input_bfd, lower_insn, hit_data + 2);
+
+ return bfd_reloc_ok;
+ }
+
+ case R_ARM_THM_BF12:
+ {
+ bfd_vma relocation;
+ bfd_vma upper_insn = bfd_get_16 (input_bfd, hit_data);
+ bfd_vma lower_insn = bfd_get_16 (input_bfd, hit_data + 2);
+
+ if (globals->use_rel)
+ {
+ bfd_vma immA = (upper_insn & 0x0001);
+ bfd_vma immB = (lower_insn & 0x07fe) >> 1;
+ bfd_vma immC = (lower_insn & 0x0800) >> 11;
+ addend = (immA << 12);
+ addend |= (immB << 2);
+ addend |= (immC << 1);
+ addend |= 1;
+ /* Sign extend. */
+ addend = (addend & 0x1000) ? addend - (1 << 13) : addend;
+ signed_addend = addend;
+ }
+
+ relocation = value + signed_addend;
+ relocation -= (input_section->output_section->vma
+ + input_section->output_offset
+ + rel->r_offset);
+
+ /* Put RELOCATION back into the insn. */
+ {
+ bfd_vma immA = (relocation & 0x00001000) >> 12;
+ bfd_vma immB = (relocation & 0x00000ffc) >> 2;
+ bfd_vma immC = (relocation & 0x00000002) >> 1;
+
+ upper_insn = (upper_insn & 0xfffe) | immA;
+ lower_insn = (lower_insn & 0xf001) | (immC << 11) | (immB << 1);
+ }
+
+ /* Put the relocated value back in the object file: */
+ bfd_put_16 (input_bfd, upper_insn, hit_data);
+ bfd_put_16 (input_bfd, lower_insn, hit_data + 2);
+
+ return bfd_reloc_ok;
+ }
+
+ case R_ARM_THM_BF18:
+ {
+ bfd_vma relocation;
+ bfd_vma upper_insn = bfd_get_16 (input_bfd, hit_data);
+ bfd_vma lower_insn = bfd_get_16 (input_bfd, hit_data + 2);
+
+ if (globals->use_rel)
+ {
+ bfd_vma immA = (upper_insn & 0x007f);
+ bfd_vma immB = (lower_insn & 0x07fe) >> 1;
+ bfd_vma immC = (lower_insn & 0x0800) >> 11;
+ addend = (immA << 12);
+ addend |= (immB << 2);
+ addend |= (immC << 1);
+ addend |= 1;
+ /* Sign extend. */
+ addend = (addend & 0x40000) ? addend - (1 << 19) : addend;
+ signed_addend = addend;
+ }
+
+ relocation = value + signed_addend;
+ relocation -= (input_section->output_section->vma
+ + input_section->output_offset
+ + rel->r_offset);
+
+ /* Put RELOCATION back into the insn. */
+ {
+ bfd_vma immA = (relocation & 0x0007f000) >> 12;
+ bfd_vma immB = (relocation & 0x00000ffc) >> 2;
+ bfd_vma immC = (relocation & 0x00000002) >> 1;
+
+ upper_insn = (upper_insn & 0xff80) | immA;
+ lower_insn = (lower_insn & 0xf001) | (immC << 11) | (immB << 1);
+ }
+
+ /* Put the relocated value back in the object file: */
+ bfd_put_16 (input_bfd, upper_insn, hit_data);
+ bfd_put_16 (input_bfd, lower_insn, hit_data + 2);
+
+ return bfd_reloc_ok;
+ }
+