aboutsummaryrefslogtreecommitdiff
path: root/bfd
diff options
context:
space:
mode:
authorNick Clifton <nickc@redhat.com>2008-08-26 11:46:41 +0000
committerNick Clifton <nickc@redhat.com>2008-08-26 11:46:41 +0000
commitc820be077e039666a0dec7a4d95668fb46d0a375 (patch)
tree436b00f94184bcbe354ea9873497d00fe5227c00 /bfd
parent8716772cc56cb5beb0cbea672eed1b10d6486484 (diff)
downloadgdb-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/ChangeLog12
-rw-r--r--bfd/elf32-arm.c75
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;