diff options
author | Nick Clifton <nickc@redhat.com> | 2008-08-26 11:46:41 +0000 |
---|---|---|
committer | Nick Clifton <nickc@redhat.com> | 2008-08-26 11:46:41 +0000 |
commit | c820be077e039666a0dec7a4d95668fb46d0a375 (patch) | |
tree | 436b00f94184bcbe354ea9873497d00fe5227c00 /bfd | |
parent | 8716772cc56cb5beb0cbea672eed1b10d6486484 (diff) | |
download | gdb-c820be077e039666a0dec7a4d95668fb46d0a375.zip gdb-c820be077e039666a0dec7a4d95668fb46d0a375.tar.gz gdb-c820be077e039666a0dec7a4d95668fb46d0a375.tar.bz2 |
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.
Diffstat (limited to 'bfd')
-rw-r--r-- | bfd/ChangeLog | 12 | ||||
-rw-r--r-- | bfd/elf32-arm.c | 75 |
2 files changed, 83 insertions, 4 deletions
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 <christophe.lyon@st.com> + + * 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 <schwab@suse.de> * 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; |