From c820be077e039666a0dec7a4d95668fb46d0a375 Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Tue, 26 Aug 2008 11:46:41 +0000 Subject: [PATCH] bfd/ * elf32-arm.c (arm_thumb_arm_v4t_short_branch_stub): Define. (elf32_arm_stub_type): Add arm_thumb_arm_v4t_stub_short_branch. (arm_type_of_stub): Handle armv4t short branches. Update prototype. (arm_stub_is_thumb): Handle arm_thumb_arm_v4t_stub_short_branch. (arm_build_one_stub): Likewise. (arm_size_one_stub): Likewise. (elf32_arm_size_stubs): Use new arm_type_of_stub prototype. (arm_map_one_stub): Handle arm_thumb_arm_v4t_stub_short_branch. ld/testsuite/ * ld-arm/arm-elf.exp: Add farcall-thumb-arm-short test. * ld-arm/farcall-group2.s: Fix comment. * ld-arm/farcall-thumb-arm-short.d: New test. * ld-arm/farcall-thumb-arm-short.s: New test. --- bfd/ChangeLog | 12 +++++ bfd/elf32-arm.c | 75 +++++++++++++++++++++++++-- ld/testsuite/ChangeLog | 7 +++ ld/testsuite/ld-arm/arm-elf.exp | 5 +- ld/testsuite/ld-arm/farcall-group2.s | 5 +- ld/testsuite/ld-arm/farcall-thumb-arm-short.d | 14 +++++ ld/testsuite/ld-arm/farcall-thumb-arm-short.s | 21 ++++++++ 7 files changed, 130 insertions(+), 9 deletions(-) create mode 100644 ld/testsuite/ld-arm/farcall-thumb-arm-short.d create mode 100644 ld/testsuite/ld-arm/farcall-thumb-arm-short.s diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 5c34381..9ff4b5c 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,15 @@ +2008-08-25 Christophe Lyon + + * elf32-arm.c (arm_thumb_arm_v4t_short_branch_stub): Define. + (elf32_arm_stub_type): Add arm_thumb_arm_v4t_stub_short_branch. + (arm_type_of_stub): Handle armv4t short branches. Update + prototype. + (arm_stub_is_thumb): Handle arm_thumb_arm_v4t_stub_short_branch. + (arm_build_one_stub): Likewise. + (arm_size_one_stub): Likewise. + (elf32_arm_size_stubs): Use new arm_type_of_stub prototype. + (arm_map_one_stub): Handle arm_thumb_arm_v4t_stub_short_branch. + 2008-08-24 Andreas Schwab * elf-eh-frame.c (_bfd_elf_write_section_eh_frame): Do proper diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c index 39ce002..6601c45 100644 --- a/bfd/elf32-arm.c +++ b/bfd/elf32-arm.c @@ -2045,6 +2045,13 @@ static const bfd_vma arm_thumb_arm_v4t_long_branch_stub[] = 0x00000000, /* dcd R_ARM_ABS32(X) */ }; +static const bfd_vma arm_thumb_arm_v4t_short_branch_stub[] = + { + 0x46c04778, /* bx pc */ + /* nop */ + 0xea000000, /* b (X) */ + }; + static const bfd_vma arm_pic_long_branch_stub[] = { 0xe59fc000, /* ldr r12, [pc] */ @@ -2063,6 +2070,7 @@ enum elf32_arm_stub_type arm_thumb_v4t_stub_long_branch, arm_thumb_thumb_stub_long_branch, arm_thumb_arm_v4t_stub_long_branch, + arm_thumb_arm_v4t_stub_short_branch, arm_stub_pic_long_branch, }; @@ -2738,6 +2746,7 @@ arm_stub_is_thumb (enum elf32_arm_stub_type stub_type) { case arm_thumb_thumb_stub_long_branch: case arm_thumb_arm_v4t_stub_long_branch: + case arm_thumb_arm_v4t_stub_short_branch: return TRUE; case arm_stub_none: BFD_FAIL (); @@ -2756,7 +2765,10 @@ arm_type_of_stub (struct bfd_link_info *info, const Elf_Internal_Rela *rel, unsigned char st_type, struct elf32_arm_link_hash_entry *hash, - bfd_vma destination) + bfd_vma destination, + asection *sym_sec, + bfd *input_bfd, + const char *name) { bfd_vma location; bfd_signed_vma branch_offset; @@ -2826,6 +2838,16 @@ arm_type_of_stub (struct bfd_link_info *info, else { /* Thumb to arm. */ + if (sym_sec != NULL + && sym_sec->owner != NULL + && !INTERWORK_FLAG (sym_sec->owner)) + { + (*_bfd_error_handler) + (_("%B(%s): warning: interworking not enabled.\n" + " first occurrence: %B: Thumb call to ARM"), + sym_sec->owner, input_bfd, name); + } + stub_type = (info->shared | globals->pic_veneer) ? ((globals->use_blx) ? arm_stub_pic_long_branch @@ -2833,6 +2855,12 @@ arm_type_of_stub (struct bfd_link_info *info, : (globals->use_blx) ? arm_stub_long_branch : arm_thumb_arm_v4t_stub_long_branch; + + /* Handle v4t short branches. */ + if ((stub_type == arm_thumb_arm_v4t_stub_long_branch) + && (branch_offset <= THM_MAX_FWD_BRANCH_OFFSET) + && (branch_offset >= THM_MAX_BWD_BRANCH_OFFSET)) + stub_type = arm_thumb_arm_v4t_stub_short_branch; } } } @@ -2841,8 +2869,19 @@ arm_type_of_stub (struct bfd_link_info *info, if (st_type == STT_ARM_TFUNC) { /* Arm to thumb. */ - /* We have an extra 2-bytes reach because of the mode change - (bit 24 (H) of BLX encoding). */ + + if (sym_sec != NULL + && sym_sec->owner != NULL + && !INTERWORK_FLAG (sym_sec->owner)) + { + (*_bfd_error_handler) + (_("%B(%s): warning: interworking not enabled.\n" + " first occurrence: %B: Thumb call to ARM"), + sym_sec->owner, input_bfd, name); + } + + /* We have an extra 2-bytes reach because of + the mode change (bit 24 (H) of BLX encoding). */ if (branch_offset > (ARM_MAX_FWD_BRANCH_OFFSET + 2) || (branch_offset < ARM_MAX_BWD_BRANCH_OFFSET) || !globals->use_blx) @@ -3098,6 +3137,10 @@ arm_build_one_stub (struct bfd_hash_entry *gen_entry, template = arm_thumb_arm_v4t_long_branch_stub; template_size = (sizeof (arm_thumb_arm_v4t_long_branch_stub) / sizeof (bfd_vma)) * 4; break; + case arm_thumb_arm_v4t_stub_short_branch: + template = arm_thumb_arm_v4t_short_branch_stub; + template_size = (sizeof(arm_thumb_arm_v4t_short_branch_stub) / sizeof (bfd_vma)) * 4; + break; case arm_stub_pic_long_branch: template = arm_pic_long_branch_stub; template_size = (sizeof (arm_pic_long_branch_stub) / sizeof (bfd_vma)) * 4; @@ -3147,6 +3190,19 @@ arm_build_one_stub (struct bfd_hash_entry *gen_entry, stub_bfd, stub_sec, stub_sec->contents, stub_entry->stub_offset + 16, sym_value, 0); break; + case arm_thumb_arm_v4t_stub_short_branch: + { + long int rel_offset; + static const insn32 t2a3_b_insn = 0xea000000; + + rel_offset = sym_value - (stub_addr + 8 + 4); + + put_arm_insn (globals, stub_bfd, + (bfd_vma) t2a3_b_insn | ((rel_offset >> 2) & 0x00FFFFFF), + loc + 4); + } + break; + case arm_stub_pic_long_branch: /* We want the value relative to the address 8 bytes from the start of the stub. */ @@ -3197,6 +3253,10 @@ arm_size_one_stub (struct bfd_hash_entry *gen_entry, template = arm_thumb_arm_v4t_long_branch_stub; template_size = (sizeof (arm_thumb_arm_v4t_long_branch_stub) / sizeof (bfd_vma)) * 4; break; + case arm_thumb_arm_v4t_stub_short_branch: + template = arm_thumb_arm_v4t_short_branch_stub; + template_size = (sizeof(arm_thumb_arm_v4t_short_branch_stub) / sizeof (bfd_vma)) * 4; + break; case arm_stub_pic_long_branch: template = arm_pic_long_branch_stub; template_size = (sizeof (arm_pic_long_branch_stub) / sizeof (bfd_vma)) * 4; @@ -3603,7 +3663,8 @@ elf32_arm_size_stubs (bfd *output_bfd, /* Determine what (if any) linker stub is needed. */ stub_type = arm_type_of_stub (info, section, irela, st_type, - hash, destination); + hash, destination, sym_sec, + input_bfd, sym_name); if (stub_type == arm_stub_none) continue; @@ -11205,6 +11266,12 @@ arm_map_one_stub (struct bfd_hash_entry * gen_entry, if (!elf32_arm_output_map_sym (osi, ARM_MAP_DATA, addr + 16)) return FALSE; break; + case arm_thumb_arm_v4t_stub_short_branch: + if (!elf32_arm_output_stub_sym (osi, stub_name, addr | 1, 8)) + return FALSE; + if (!elf32_arm_output_map_sym (osi, ARM_MAP_ARM, addr + 4)) + return FALSE; + break; case arm_stub_pic_long_branch: if (!elf32_arm_output_stub_sym (osi, stub_name, addr, 12)) return FALSE; diff --git a/ld/testsuite/ChangeLog b/ld/testsuite/ChangeLog index 117f5b7..a2c3050 100644 --- a/ld/testsuite/ChangeLog +++ b/ld/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2008-08-26 Nick Clifton + + * ld-arm/arm-elf.exp: Add farcall-thumb-arm-short test. + * ld-arm/farcall-group2.s: Fix comment. + * ld-arm/farcall-thumb-arm-short.d: New test. + * ld-arm/farcall-thumb-arm-short.s: New test. + 2008-08-22 Jan Kratochvil * ld-x86-64/dwarfreloc.exp, ld-x86-64/dwarfreloc.rd, diff --git a/ld/testsuite/ld-arm/arm-elf.exp b/ld/testsuite/ld-arm/arm-elf.exp index c01c795..6075e68 100644 --- a/ld/testsuite/ld-arm/arm-elf.exp +++ b/ld/testsuite/ld-arm/arm-elf.exp @@ -207,7 +207,7 @@ set armeabitests { {"Thumb-2 BL" "-Ttext 0x1000 --section-start .foo=0x1001000" "" {thumb2-bl.s} {{objdump -dr thumb2-bl.d}} "thumb2-bl"} - + {"ARMv4 interworking" "-static -T arm.ld --fix-v4bx-interworking" "--fix-v4bx -meabi=4" {armv4-bx.s} {{objdump -d armv4-bx.d}} "armv4-bx"} @@ -260,6 +260,9 @@ set armeabitests { {"Thumb-ARM farcall" "-Ttext 0x1000 --section-start .foo=0x2001014" "-W" {farcall-thumb-arm.s} {{objdump -d farcall-thumb-arm.d}} "farcall-thumb-arm"} + {"Thumb-ARM (short) call" "-Ttext 0x1000 --section-start .foo=0x0002014" "-W" {farcall-thumb-arm-short.s} + {{objdump -d farcall-thumb-arm-short.d}} + "farcall-thumb-arm-short"} {"Thumb-ARM farcall with BLX" "-Ttext 0x1000 --section-start .foo=0x2001014" "-W -march=armv5t" {farcall-thumb-arm.s} {{objdump -d farcall-thumb-arm-blx.d}} "farcall-thumb-arm-blx"} diff --git a/ld/testsuite/ld-arm/farcall-group2.s b/ld/testsuite/ld-arm/farcall-group2.s index 4624804..774869f 100644 --- a/ld/testsuite/ld-arm/farcall-group2.s +++ b/ld/testsuite/ld-arm/farcall-group2.s @@ -1,10 +1,7 @@ - @ Test to ensure that ARM calls exceeding 32Mb generate stubs. -@ We will place the section .foo at 0x2000. - .text -myfunc: +myfunc: bl bar3 bl bar4 bl bar5 diff --git a/ld/testsuite/ld-arm/farcall-thumb-arm-short.d b/ld/testsuite/ld-arm/farcall-thumb-arm-short.d new file mode 100644 index 0000000..2e7a17a --- /dev/null +++ b/ld/testsuite/ld-arm/farcall-thumb-arm-short.d @@ -0,0 +1,14 @@ +.*: file format .* + +Disassembly of section .text: + +00001000 <__bar_from_thumb>: + 1000: 4778 bx pc + 1002: 46c0 nop \(mov r8, r8\) + 1004: ea000402 b 2014 +00001008 <_start>: + 1008: f7ff fffa bl 1000 <__bar_from_thumb> +Disassembly of section .foo: + +00002014 : + 2014: e12fff1e bx lr diff --git a/ld/testsuite/ld-arm/farcall-thumb-arm-short.s b/ld/testsuite/ld-arm/farcall-thumb-arm-short.s new file mode 100644 index 0000000..1865380 --- /dev/null +++ b/ld/testsuite/ld-arm/farcall-thumb-arm-short.s @@ -0,0 +1,21 @@ +@ Test to ensure that a Thumb to ARM call within 4Mb does not generate a stub. + + .global _start + .syntax unified + +@ We will place the section .text at 0x1000. + + .text + .thumb_func +_start: + bl bar + +@ We will place the section .foo at 0x2014. + + .section .foo, "xa" + + .arm + .type bar, %function +bar: + bx lr + -- 2.7.4