From eed94f8f8eddbd2268fc317508044bedc81a4e70 Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Tue, 4 Mar 2014 15:25:53 +0000 Subject: [PATCH] Install patch for PR ld/16017. This adds support for generating PLT entries using Thumb2 instructions for those cores which do not support the ARM ISA. * elf32-arm.c (elf32_thumb2_plt0_entry): New array. (elf32_thumb2_plt_entry): New array. (elf32_arm_create_dynamic_sections): Set PLT entry sizes when using thumb2 based PLT. (elf32_arm_populate_plt_entry): Handle generating Thumb2 based PLT entries. (elf32_arm_final_link_relocate): Do not bias jumps to Thumb based PLT entries. (elf32_arm_finish_dynamic_sections): Handle creation of Thumb2 based PLT 0-entry. (elf32_arm_output_plt_map_1): Handle creation of local symbols for Thumb2 based PLT 0-entry. (elf32_arm_output_arch_local_syms): Handle creation of local symbols for Thumb2 based PLT entries. --- bfd/ChangeLog | 18 +++++ bfd/elf32-arm.c | 188 +++++++++++++++++++++++++++++++++++++----------- 2 files changed, 164 insertions(+), 42 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 75a638c54da..a7977420c17 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,21 @@ +2014-03-04 Nick Clifton + + PR ld/16017 + * elf32-arm.c (elf32_thumb2_plt0_entry): New array. + (elf32_thumb2_plt_entry): New array. + (elf32_arm_create_dynamic_sections): Set PLT entry sizes when + using thumb2 based PLT. + (elf32_arm_populate_plt_entry): Handle generating Thumb2 based PLT + entries. + (elf32_arm_final_link_relocate): Do not bias jumps to Thumb based + PLT entries. + (elf32_arm_finish_dynamic_sections): Handle creation of Thumb2 + based PLT 0-entry. + (elf32_arm_output_plt_map_1): Handle creation of local symbols for + Thumb2 based PLT 0-entry. + (elf32_arm_output_arch_local_syms): Handle creation of local + symbols for Thumb2 based PLT entries. + 2014-02-28 Alan Modra PR ld/16643 diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c index b17f4d435d9..db9566b9291 100644 --- a/bfd/elf32-arm.c +++ b/bfd/elf32-arm.c @@ -2125,7 +2125,7 @@ static const bfd_vma elf32_arm_plt_entry [] = 0x00000000, /* unused */ }; -#else +#else /* not FOUR_WORD_PLT */ /* The first entry in a procedure linkage table looks like this. It is set up so that any shared library function that is @@ -2161,7 +2161,34 @@ static const bfd_vma elf32_arm_plt_entry_long [] = static bfd_boolean elf32_arm_use_long_plt_entry = FALSE; -#endif +#endif /* not FOUR_WORD_PLT */ + +/* The first entry in a procedure linkage table looks like this. + It is set up so that any shared library function that is called before the + relocation has been set up calls the dynamic linker first. */ +static const bfd_vma elf32_thumb2_plt0_entry [] = +{ + /* NOTE: As this is a mixture of 16-bit and 32-bit instructions, + an instruction maybe encoded to one or two array elements. */ + 0xf8dfb500, /* push {lr} */ + 0x44fee008, /* ldr.w lr, [pc, #8] */ + /* add lr, pc */ + 0xff08f85e, /* ldr.w pc, [lr, #8]! */ + 0x00000000, /* &GOT[0] - . */ +}; + +/* Subsequent entries in a procedure linkage table for thumb only target + look like this. */ +static const bfd_vma elf32_thumb2_plt_entry [] = +{ + /* NOTE: As this is a mixture of 16-bit and 32-bit instructions, + an instruction maybe encoded to one or two array elements. */ + 0x0c00f240, /* movw ip, #0xNNNN */ + 0x0c00f2c0, /* movt ip, #0xNNNN */ + 0xf8dc44fc, /* add ip, pc */ + 0xbf00f000 /* ldr.w pc, [ip] */ + /* nop */ +}; /* The format of the first entry in the procedure linkage table for a VxWorks executable. */ @@ -3329,6 +3356,37 @@ create_ifunc_sections (struct bfd_link_info *info) return TRUE; } +/* Determine if we're dealing with a Thumb only architecture. */ + +static bfd_boolean +using_thumb_only (struct elf32_arm_link_hash_table *globals) +{ + int arch = bfd_elf_get_obj_attr_int (globals->obfd, OBJ_ATTR_PROC, + Tag_CPU_arch); + int profile; + + if (arch == TAG_CPU_ARCH_V6_M || arch == TAG_CPU_ARCH_V6S_M) + return TRUE; + + if (arch != TAG_CPU_ARCH_V7 && arch != TAG_CPU_ARCH_V7E_M) + return FALSE; + + profile = bfd_elf_get_obj_attr_int (globals->obfd, OBJ_ATTR_PROC, + Tag_CPU_arch_profile); + + return profile == 'M'; +} + +/* Determine if we're dealing with a Thumb-2 object. */ + +static bfd_boolean +using_thumb2 (struct elf32_arm_link_hash_table *globals) +{ + int arch = bfd_elf_get_obj_attr_int (globals->obfd, OBJ_ATTR_PROC, + Tag_CPU_arch); + return arch == TAG_CPU_ARCH_V6T2 || arch >= TAG_CPU_ARCH_V7; +} + /* Create .plt, .rel(a).plt, .got, .got.plt, .rel(a).got, .dynbss, and .rel(a).bss sections in DYNOBJ, and set up shortcuts to them in our hash table. */ @@ -3372,6 +3430,22 @@ elf32_arm_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info) = 4 * ARRAY_SIZE (elf32_arm_vxworks_exec_plt_entry); } } + else + { + /* PR ld/16017 + Test for thumb only architectures. Note - we cannot just call + using_thumb_only() as the attributes in the output bfd have not been + initialised at this point, so instead we use the input bfd. */ + bfd * saved_obfd = htab->obfd; + + htab->obfd = dynobj; + if (using_thumb_only (htab)) + { + htab->plt_header_size = 4 * ARRAY_SIZE (elf32_thumb2_plt0_entry); + htab->plt_entry_size = 4 * ARRAY_SIZE (elf32_thumb2_plt_entry); + } + htab->obfd = saved_obfd; + } if (!htab->root.splt || !htab->root.srelplt @@ -3503,37 +3577,6 @@ elf32_arm_hash_table_free (struct bfd_link_hash_table *hash) _bfd_elf_link_hash_table_free (hash); } -/* Determine if we're dealing with a Thumb only architecture. */ - -static bfd_boolean -using_thumb_only (struct elf32_arm_link_hash_table *globals) -{ - int arch = bfd_elf_get_obj_attr_int (globals->obfd, OBJ_ATTR_PROC, - Tag_CPU_arch); - int profile; - - if (arch == TAG_CPU_ARCH_V6_M || arch == TAG_CPU_ARCH_V6S_M) - return TRUE; - - if (arch != TAG_CPU_ARCH_V7 && arch != TAG_CPU_ARCH_V7E_M) - return FALSE; - - profile = bfd_elf_get_obj_attr_int (globals->obfd, OBJ_ATTR_PROC, - Tag_CPU_arch_profile); - - return profile == 'M'; -} - -/* Determine if we're dealing with a Thumb-2 object. */ - -static bfd_boolean -using_thumb2 (struct elf32_arm_link_hash_table *globals) -{ - int arch = bfd_elf_get_obj_attr_int (globals->obfd, OBJ_ATTR_PROC, - Tag_CPU_arch); - return arch == TAG_CPU_ARCH_V6T2 || arch >= TAG_CPU_ARCH_V7; -} - /* Determine what kind of NOPs are available. */ static bfd_boolean @@ -7710,13 +7753,43 @@ elf32_arm_populate_plt_entry (bfd *output_bfd, struct bfd_link_info *info, } else if (using_thumb_only (htab)) { - /* PR ld/16017: Do not generate ARM instructions for - the PLT if compiling for a thumb-only target. + /* PR ld/16017: Generate thumb only PLT entries. */ + if (!using_thumb2 (htab)) + { + /* FIXME: We ought to be able to generate thumb-1 PLT + instructions... */ + _bfd_error_handler (_("%B: Warning: thumb-1 mode PLT generation not currently supported"), + output_bfd); + return FALSE; + } - FIXME: We ought to be able to generate thumb PLT instructions... */ - _bfd_error_handler (_("%B: Warning: thumb mode PLT generation not currently supported"), - output_bfd); - return FALSE; + /* Calculate the displacement between the PLT slot and the entry in + the GOT. The 12-byte offset accounts for the value produced by + adding to pc in the 3rd instruction of the PLT stub. */ + got_displacement = got_address - (plt_address + 12); + + /* As we are using 32 bit instructions we have to use 'put_arm_insn' + instead of 'put_thumb_insn'. */ + put_arm_insn (htab, output_bfd, + elf32_thumb2_plt_entry[0] + | ((got_displacement & 0x000000ff) << 16) + | ((got_displacement & 0x00000700) << 20) + | ((got_displacement & 0x00000800) >> 1) + | ((got_displacement & 0x0000f000) >> 12), + ptr + 0); + put_arm_insn (htab, output_bfd, + elf32_thumb2_plt_entry[1] + | ((got_displacement & 0x00ff0000) ) + | ((got_displacement & 0x07000000) << 4) + | ((got_displacement & 0x08000000) >> 17) + | ((got_displacement & 0xf0000000) >> 28), + ptr + 4); + put_arm_insn (htab, output_bfd, + elf32_thumb2_plt_entry[2], + ptr + 8); + put_arm_insn (htab, output_bfd, + elf32_thumb2_plt_entry[3], + ptr + 12); } else { @@ -8961,7 +9034,9 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, + splt->output_offset + plt_offset); - if (globals->use_blx && r_type == R_ARM_THM_CALL) + if (globals->use_blx + && r_type == R_ARM_THM_CALL + && ! using_thumb_only (globals)) { /* If the Thumb BLX instruction is available, convert the BL to a BLX instruction to call the ARM-mode @@ -8971,8 +9046,9 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, } else { - /* Target the Thumb stub before the ARM PLT entry. */ - value -= PLT_THUMB_STUB_SIZE; + if (! using_thumb_only (globals)) + /* Target the Thumb stub before the ARM PLT entry. */ + value -= PLT_THUMB_STUB_SIZE; branch_type = ST_BRANCH_TO_THUMB; } *unresolved_reloc_p = FALSE; @@ -14427,6 +14503,20 @@ elf32_arm_finish_dynamic_sections (bfd * output_bfd, struct bfd_link_info * info else if (htab->nacl_p) arm_nacl_put_plt0 (htab, output_bfd, splt, got_address + 8 - (plt_address + 16)); + else if (using_thumb_only (htab)) + { + got_displacement = got_address - (plt_address + 12); + + plt0_entry = elf32_thumb2_plt0_entry; + put_arm_insn (htab, output_bfd, plt0_entry[0], + splt->contents + 0); + put_arm_insn (htab, output_bfd, plt0_entry[1], + splt->contents + 4); + put_arm_insn (htab, output_bfd, plt0_entry[2], + splt->contents + 8); + + bfd_put_32 (output_bfd, got_displacement, splt->contents + 12); + } else { got_displacement = got_address - (plt_address + 16); @@ -14765,6 +14855,11 @@ elf32_arm_output_plt_map_1 (output_arch_syminfo *osi, if (!elf32_arm_output_map_sym (osi, ARM_MAP_ARM, addr)) return FALSE; } + else if (using_thumb_only (htab)) + { + if (!elf32_arm_output_map_sym (osi, ARM_MAP_THUMB, addr)) + return FALSE; + } else { bfd_boolean thumb_stub_p; @@ -15096,6 +15191,15 @@ elf32_arm_output_arch_local_syms (bfd *output_bfd, if (!elf32_arm_output_map_sym (&osi, ARM_MAP_ARM, 0)) return FALSE; } + else if (using_thumb_only (htab)) + { + if (!elf32_arm_output_map_sym (&osi, ARM_MAP_THUMB, 0)) + return FALSE; + if (!elf32_arm_output_map_sym (&osi, ARM_MAP_DATA, 12)) + return FALSE; + if (!elf32_arm_output_map_sym (&osi, ARM_MAP_THUMB, 16)) + return FALSE; + } else if (!htab->symbian_p) { if (!elf32_arm_output_map_sym (&osi, ARM_MAP_ARM, 0)) -- 2.30.2