This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[patch] Arm BE8 stubs
- From: Paul Brook <paul at codesourcery dot com>
- To: binutils at sourceware dot org
- Date: Thu, 18 May 2006 20:32:50 +0100
- Subject: [patch] Arm BE8 stubs
The Arm linker backend uses elf32_arm_write_section to byteswap code when
generating BE8 format images. However this hook is not called for linker
generated sections (e.g the PLT and interworking stub sections).
The attached patch performs appropriate byteswapping when filling in the plt
and interworking stubs.
Tested with cross to arm-none-eabi.
Ok?
Paul
2006-05-18 Paul Brook <paul@codesourcery.com>
* elf32-arm.c (put_arm_insn, put_thumb_insn): New functions.
(elf32_thumb_to_arm_stub, elf32_arm_to_thumb_stub,
elf32_arm_finish_dynamic_symbol): Use them.
Index: bfd/elf32-arm.c
===================================================================
RCS file: /var/cvsroot/src-cvs/src/bfd/elf32-arm.c,v
retrieving revision 1.75
diff -u -p -r1.75 elf32-arm.c
--- bfd/elf32-arm.c 15 May 2006 19:57:34 -0000 1.75
+++ bfd/elf32-arm.c 18 May 2006 19:15:20 -0000
@@ -2655,6 +2655,35 @@ insert_thumb_branch (insn32 br_insn, int
return br_insn;
}
+
+/* Store an Arm insn into an output section not processed by
+ elf32_arm_write_section. */
+
+static void
+put_arm_insn(struct elf32_arm_link_hash_table *htab,
+ bfd * output_bfd, bfd_vma val, void * ptr)
+{
+ if (htab->byteswap_code != bfd_little_endian (output_bfd))
+ bfd_putl32(val, ptr);
+ else
+ bfd_putb32(val, ptr);
+}
+
+
+/* Store a 16-bit Thumb insn into an output section not processed by
+ elf32_arm_write_section. */
+
+static void
+put_thumb_insn(struct elf32_arm_link_hash_table *htab,
+ bfd * output_bfd, bfd_vma val, void * ptr)
+{
+ if (htab->byteswap_code != bfd_little_endian (output_bfd))
+ bfd_putl16(val, ptr);
+ else
+ bfd_putb16(val, ptr);
+}
+
+
/* Thumb code calling an ARM function. */
static int
@@ -2711,11 +2740,11 @@ elf32_thumb_to_arm_stub (struct bfd_link
--my_offset;
myh->root.u.def.value = my_offset;
- bfd_put_16 (output_bfd, (bfd_vma) t2a1_bx_pc_insn,
- s->contents + my_offset);
+ put_thumb_insn (globals, output_bfd, (bfd_vma) t2a1_bx_pc_insn,
+ s->contents + my_offset);
- bfd_put_16 (output_bfd, (bfd_vma) t2a2_noop_insn,
- s->contents + my_offset + 2);
+ put_thumb_insn (globals, output_bfd, (bfd_vma) t2a2_noop_insn,
+ s->contents + my_offset + 2);
ret_offset =
/* Address of destination of the stub. */
@@ -2733,9 +2762,9 @@ elf32_thumb_to_arm_stub (struct bfd_link
/* ARM branches work from the pc of the instruction + 8. */
+ 8);
- bfd_put_32 (output_bfd,
- (bfd_vma) t2a3_b_insn | ((ret_offset >> 2) & 0x00FFFFFF),
- s->contents + my_offset + 4);
+ put_arm_insn (globals, output_bfd,
+ (bfd_vma) t2a3_b_insn | ((ret_offset >> 2) & 0x00FFFFFF),
+ s->contents + my_offset + 4);
}
BFD_ASSERT (my_offset <= globals->thumb_glue_size);
@@ -2820,12 +2849,12 @@ elf32_arm_to_thumb_stub (struct bfd_link
so construct the address from a relative offset. */
/* TODO: If the offset is small it's probably worth
constructing the address with adds. */
- bfd_put_32 (output_bfd, (bfd_vma) a2t1p_ldr_insn,
- s->contents + my_offset);
- bfd_put_32 (output_bfd, (bfd_vma) a2t2p_add_pc_insn,
- s->contents + my_offset + 4);
- bfd_put_32 (output_bfd, (bfd_vma) a2t3p_bx_r12_insn,
- s->contents + my_offset + 8);
+ put_arm_insn (globals, output_bfd, (bfd_vma) a2t1p_ldr_insn,
+ s->contents + my_offset);
+ put_arm_insn (globals, output_bfd, (bfd_vma) a2t2p_add_pc_insn,
+ s->contents + my_offset + 4);
+ put_arm_insn (globals, output_bfd, (bfd_vma) a2t3p_bx_r12_insn,
+ s->contents + my_offset + 8);
/* Adjust the offset by 4 for the position of the add,
and 8 for the pipeline offset. */
ret_offset = (val - (s->output_offset
@@ -2837,11 +2866,11 @@ elf32_arm_to_thumb_stub (struct bfd_link
}
else
{
- bfd_put_32 (output_bfd, (bfd_vma) a2t1_ldr_insn,
- s->contents + my_offset);
+ put_arm_insn (globals, output_bfd, (bfd_vma) a2t1_ldr_insn,
+ s->contents + my_offset);
- bfd_put_32 (output_bfd, (bfd_vma) a2t2_bx_r12_insn,
- s->contents + my_offset + 4);
+ put_arm_insn (globals, output_bfd, (bfd_vma) a2t2_bx_r12_insn,
+ s->contents + my_offset + 4);
/* It's a thumb address. Add the low order bit. */
bfd_put_32 (output_bfd, val | a2t3_func_addr_insn,
@@ -6984,16 +7013,17 @@ elf32_arm_finish_dynamic_symbol (bfd * o
/* Fill in the entry in the procedure linkage table. */
if (htab->symbian_p)
{
- unsigned i;
- for (i = 0; i < htab->plt_entry_size / 4; ++i)
- bfd_put_32 (output_bfd,
- elf32_arm_symbian_plt_entry[i],
- splt->contents + h->plt.offset + 4 * i);
+ put_arm_insn (htab, output_bfd,
+ elf32_arm_symbian_plt_entry[0],
+ splt->contents + h->plt.offset);
+ bfd_put_32 (output_bfd,
+ elf32_arm_symbian_plt_entry[1],
+ splt->contents + h->plt.offset + 4);
/* Fill in the entry in the .rel.plt section. */
rel.r_offset = (splt->output_section->vma
+ splt->output_offset
- + h->plt.offset + 4 * (i - 1));
+ + h->plt.offset + 4);
rel.r_info = ELF32_R_INFO (h->dynindx, R_ARM_GLOB_DAT);
/* Get the index in the procedure linkage table which
@@ -7008,6 +7038,7 @@ elf32_arm_finish_dynamic_symbol (bfd * o
bfd_vma got_offset, got_address, plt_address;
bfd_vma got_displacement;
asection * sgot;
+ bfd_byte * ptr;
sgot = bfd_get_section_by_name (dynobj, ".got.plt");
BFD_ASSERT (sgot != NULL);
@@ -7033,20 +7064,23 @@ elf32_arm_finish_dynamic_symbol (bfd * o
+ splt->output_offset
+ h->plt.offset);
+ ptr = htab->splt->contents + h->plt.offset;
if (htab->vxworks_p && info->shared)
{
unsigned int i;
bfd_vma val;
- for (i = 0; i != htab->plt_entry_size / 4; i++)
+ for (i = 0; i != htab->plt_entry_size / 4; i++, ptr += 4)
{
val = elf32_arm_vxworks_shared_plt_entry[i];
if (i == 2)
val |= got_address - sgot->output_section->vma;
if (i == 5)
val |= plt_index * RELOC_SIZE (htab);
- bfd_put_32 (output_bfd, val,
- htab->splt->contents + h->plt.offset + i * 4);
+ if (i == 2 || i == 5)
+ bfd_put_32 (output_bfd, val, ptr);
+ else
+ put_arm_insn (htab, output_bfd, val, ptr);
}
}
else if (htab->vxworks_p)
@@ -7063,8 +7097,10 @@ elf32_arm_finish_dynamic_symbol (bfd * o
val |= 0xffffff & -((h->plt.offset + i * 4 + 8) >> 2);
if (i == 5)
val |= plt_index * RELOC_SIZE (htab);
- bfd_put_32 (output_bfd, val,
- htab->splt->contents + h->plt.offset + i * 4);
+ if (i == 2 || i == 5)
+ bfd_put_32 (output_bfd, val, ptr);
+ else
+ put_arm_insn (htab, output_bfd, val, ptr);
}
loc = (htab->srelplt2->contents
@@ -7097,27 +7133,26 @@ elf32_arm_finish_dynamic_symbol (bfd * o
if (!htab->use_blx && eh->plt_thumb_refcount > 0)
{
- bfd_put_16 (output_bfd, elf32_arm_plt_thumb_stub[0],
- splt->contents + h->plt.offset - 4);
- bfd_put_16 (output_bfd, elf32_arm_plt_thumb_stub[1],
- splt->contents + h->plt.offset - 2);
+ put_thumb_insn (htab, output_bfd,
+ elf32_arm_plt_thumb_stub[0], ptr - 4);
+ put_thumb_insn (htab, output_bfd,
+ elf32_arm_plt_thumb_stub[1], ptr - 2);
}
- bfd_put_32 (output_bfd,
- elf32_arm_plt_entry[0]
- | ((got_displacement & 0x0ff00000) >> 20),
- splt->contents + h->plt.offset + 0);
- bfd_put_32 (output_bfd,
- elf32_arm_plt_entry[1]
- | ((got_displacement & 0x000ff000) >> 12),
- splt->contents + h->plt.offset + 4);
- bfd_put_32 (output_bfd,
- elf32_arm_plt_entry[2]
- | (got_displacement & 0x00000fff),
- splt->contents + h->plt.offset + 8);
+ put_arm_insn (htab, output_bfd,
+ elf32_arm_plt_entry[0]
+ | ((got_displacement & 0x0ff00000) >> 20),
+ ptr + 0);
+ put_arm_insn (htab, output_bfd,
+ elf32_arm_plt_entry[1]
+ | ((got_displacement & 0x000ff000) >> 12),
+ ptr+ 4);
+ put_arm_insn (htab, output_bfd,
+ elf32_arm_plt_entry[2]
+ | (got_displacement & 0x00000fff),
+ ptr + 8);
#ifdef FOUR_WORD_PLT
- bfd_put_32 (output_bfd, elf32_arm_plt_entry[3],
- splt->contents + h->plt.offset + 12);
+ bfd_put_32 (output_bfd, elf32_arm_plt_entry[3], ptr + 12);
#endif
}
@@ -7427,9 +7462,12 @@ elf32_arm_finish_dynamic_sections (bfd *
Elf_Internal_Rela rel;
plt0_entry = elf32_arm_vxworks_exec_plt0_entry;
- bfd_put_32 (output_bfd, plt0_entry[0], splt->contents + 0);
- bfd_put_32 (output_bfd, plt0_entry[1], splt->contents + 4);
- bfd_put_32 (output_bfd, plt0_entry[2], splt->contents + 8);
+ 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_address, splt->contents + 12);
/* Generate a relocation for _GLOBAL_OFFSET_TABLE_. */
@@ -7444,10 +7482,14 @@ elf32_arm_finish_dynamic_sections (bfd *
got_displacement = got_address - (plt_address + 16);
plt0_entry = elf32_arm_plt0_entry;
- bfd_put_32 (output_bfd, plt0_entry[0], splt->contents + 0);
- bfd_put_32 (output_bfd, plt0_entry[1], splt->contents + 4);
- bfd_put_32 (output_bfd, plt0_entry[2], splt->contents + 8);
- bfd_put_32 (output_bfd, plt0_entry[3], splt->contents + 12);
+ 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);
+ put_arm_insn (htab, output_bfd, plt0_entry[3],
+ splt->contents + 12);
#ifdef FOUR_WORD_PLT
/* The displacement value goes in the otherwise-unused