2007-08-06 Paul Brook <paul@codesourcery.com>

* elf32-arm.c (elf32_arm_link_hash_entry): Add
	plt_maybe_thumb_refcount.
	(elf32_arm_link_hash_newfunc): Set plt_maybe_thumb_refcount.
	(elf32_arm_copy_indirect_symbol): Ditto.
	(elf32_arm_adjust_dynamic_symbol): Ditto.
	(bfd_elf32_arm_process_before_allocation): Handle R_ARM_THM_JUMP24.
	(arm_add_to_rel): Ditto.
	(elf32_arm_final_link_relocate): Merge R_ARM_THM_JUMP24 with
	R_ARM_THM_CALL.  Handle R_ARM_THM_JUMP19 against a PLT stub.
	(elf32_arm_gc_sweep_hook): Call check_use_blx.  Update plt counts
	for R_ARM_THM_JUMP24 and R_ARM_THM_JUMP19.
	(elf32_arm_check_relocs): Update plt counts for R_ARM_THM_JUMP24
	and R_ARM_THM_JUMP19.
	(allocate_dynrelocs): Use plt_maybe_thumb_refcount.
	(elf32_arm_finish_dynamic_symbol): Ditto.
	(elf32_arm_output_plt_map): Ditto.
This commit is contained in:
Daniel Jacobowitz
2007-08-06 18:47:21 +00:00
parent c981028a3f
commit bd97cb95f8
2 changed files with 90 additions and 87 deletions

View File

@ -1,3 +1,22 @@
2007-08-06 Paul Brook <paul@codesourcery.com>
* elf32-arm.c (elf32_arm_link_hash_entry): Add
plt_maybe_thumb_refcount.
(elf32_arm_link_hash_newfunc): Set plt_maybe_thumb_refcount.
(elf32_arm_copy_indirect_symbol): Ditto.
(elf32_arm_adjust_dynamic_symbol): Ditto.
(bfd_elf32_arm_process_before_allocation): Handle R_ARM_THM_JUMP24.
(arm_add_to_rel): Ditto.
(elf32_arm_final_link_relocate): Merge R_ARM_THM_JUMP24 with
R_ARM_THM_CALL. Handle R_ARM_THM_JUMP19 against a PLT stub.
(elf32_arm_gc_sweep_hook): Call check_use_blx. Update plt counts
for R_ARM_THM_JUMP24 and R_ARM_THM_JUMP19.
(elf32_arm_check_relocs): Update plt counts for R_ARM_THM_JUMP24
and R_ARM_THM_JUMP19.
(allocate_dynrelocs): Use plt_maybe_thumb_refcount.
(elf32_arm_finish_dynamic_symbol): Ditto.
(elf32_arm_output_plt_map): Ditto.
2007-08-06 Daniel Jacobowitz <dan@codesourcery.com> 2007-08-06 Daniel Jacobowitz <dan@codesourcery.com>
* elf.c (rewrite_elf_program_header): Handle sections not sorted * elf.c (rewrite_elf_program_header): Handle sections not sorted

View File

@ -2129,6 +2129,10 @@ struct elf32_arm_link_hash_entry
so that we can emit the Thumb trampoline only if needed. */ so that we can emit the Thumb trampoline only if needed. */
bfd_signed_vma plt_thumb_refcount; bfd_signed_vma plt_thumb_refcount;
/* Some references from Thumb code may be eliminated by BL->BLX
conversion, so record them separately. */
bfd_signed_vma plt_maybe_thumb_refcount;
/* Since PLT entries have variable size if the Thumb prologue is /* Since PLT entries have variable size if the Thumb prologue is
used, we need to record the index into .got.plt instead of used, we need to record the index into .got.plt instead of
recomputing it from the PLT offset. */ recomputing it from the PLT offset. */
@ -2267,6 +2271,7 @@ elf32_arm_link_hash_newfunc (struct bfd_hash_entry * entry,
ret->relocs_copied = NULL; ret->relocs_copied = NULL;
ret->tls_type = GOT_UNKNOWN; ret->tls_type = GOT_UNKNOWN;
ret->plt_thumb_refcount = 0; ret->plt_thumb_refcount = 0;
ret->plt_maybe_thumb_refcount = 0;
ret->plt_got_offset = -1; ret->plt_got_offset = -1;
ret->export_glue = NULL; ret->export_glue = NULL;
} }
@ -2422,6 +2427,8 @@ elf32_arm_copy_indirect_symbol (struct bfd_link_info *info,
/* Copy over PLT info. */ /* Copy over PLT info. */
edir->plt_thumb_refcount += eind->plt_thumb_refcount; edir->plt_thumb_refcount += eind->plt_thumb_refcount;
eind->plt_thumb_refcount = 0; eind->plt_thumb_refcount = 0;
edir->plt_maybe_thumb_refcount += eind->plt_maybe_thumb_refcount;
eind->plt_maybe_thumb_refcount = 0;
if (dir->got.refcount <= 0) if (dir->got.refcount <= 0)
{ {
@ -3162,7 +3169,8 @@ bfd_elf32_arm_process_before_allocation (bfd *abfd,
&& r_type != R_ARM_PLT32 && r_type != R_ARM_PLT32
&& r_type != R_ARM_CALL && r_type != R_ARM_CALL
&& r_type != R_ARM_JUMP24 && r_type != R_ARM_JUMP24
&& r_type != R_ARM_THM_CALL) && r_type != R_ARM_THM_CALL
&& r_type != R_ARM_THM_JUMP24)
continue; continue;
/* Get the section contents if we haven't done so already. */ /* Get the section contents if we haven't done so already. */
@ -3216,10 +3224,12 @@ bfd_elf32_arm_process_before_allocation (bfd *abfd,
break; break;
case R_ARM_THM_CALL: case R_ARM_THM_CALL:
case R_ARM_THM_JUMP24:
/* This one is a call from thumb code. We look /* This one is a call from thumb code. We look
up the target of the call. If it is not a thumb up the target of the call. If it is not a thumb
target, we insert glue. */ target, we insert glue. */
if (ELF_ST_TYPE (h->type) != STT_ARM_TFUNC && !globals->use_blx if (ELF_ST_TYPE (h->type) != STT_ARM_TFUNC
&& !(globals->use_blx && r_type == R_ARM_THM_CALL)
&& h->root.type != bfd_link_hash_undefweak) && h->root.type != bfd_link_hash_undefweak)
record_thumb_to_arm_glue (link_info, h); record_thumb_to_arm_glue (link_info, h);
break; break;
@ -4996,6 +5006,7 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto,
case R_ARM_THM_XPC22: case R_ARM_THM_XPC22:
case R_ARM_THM_CALL: case R_ARM_THM_CALL:
case R_ARM_THM_JUMP24:
/* Thumb BL (branch long instruction). */ /* Thumb BL (branch long instruction). */
{ {
bfd_vma relocation; bfd_vma relocation;
@ -5059,7 +5070,7 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto,
&& (h == NULL || splt == NULL && (h == NULL || splt == NULL
|| h->plt.offset == (bfd_vma) -1)) || h->plt.offset == (bfd_vma) -1))
{ {
if (globals->use_blx) if (globals->use_blx && r_type == R_ARM_THM_CALL)
{ {
/* Convert BL to BLX. */ /* Convert BL to BLX. */
lower_insn = (lower_insn & ~0x1000) | 0x0800; lower_insn = (lower_insn & ~0x1000) | 0x0800;
@ -5072,7 +5083,8 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto,
else else
return bfd_reloc_dangerous; return bfd_reloc_dangerous;
} }
else if (sym_flags == STT_ARM_TFUNC && globals->use_blx) else if (sym_flags == STT_ARM_TFUNC && globals->use_blx
&& r_type == R_ARM_THM_CALL)
{ {
/* Make sure this is a BL. */ /* Make sure this is a BL. */
lower_insn |= 0x1800; lower_insn |= 0x1800;
@ -5085,7 +5097,7 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto,
value = (splt->output_section->vma value = (splt->output_section->vma
+ splt->output_offset + splt->output_offset
+ h->plt.offset); + h->plt.offset);
if (globals->use_blx) if (globals->use_blx && r_type == R_ARM_THM_CALL)
{ {
/* If the Thumb BLX instruction is available, convert the /* If the Thumb BLX instruction is available, convert the
BL to a BLX instruction to call the ARM-mode PLT entry. */ BL to a BLX instruction to call the ARM-mode PLT entry. */
@ -5125,7 +5137,7 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto,
if (signed_check > reloc_signed_max || signed_check < reloc_signed_min) if (signed_check > reloc_signed_max || signed_check < reloc_signed_min)
overflow = TRUE; overflow = TRUE;
if ((lower_insn & 0x1800) == 0x0800) if ((lower_insn & 0x5000) == 0x4000)
/* For a BLX instruction, make sure that the relocation is rounded up /* For a BLX instruction, make sure that the relocation is rounded up
to a word boundary. This follows the semantics of the instruction to a word boundary. This follows the semantics of the instruction
which specifies that bit 1 of the target address will come from bit which specifies that bit 1 of the target address will come from bit
@ -5152,79 +5164,6 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto,
} }
break; break;
case R_ARM_THM_JUMP24:
/* Thumb32 unconditional branch instruction. */
{
bfd_vma relocation;
bfd_boolean overflow = FALSE;
bfd_vma upper_insn = bfd_get_16 (input_bfd, hit_data);
bfd_vma lower_insn = bfd_get_16 (input_bfd, hit_data + 2);
bfd_signed_vma reloc_signed_max = ((1 << (howto->bitsize - 1)) - 1) >> howto->rightshift;
bfd_signed_vma reloc_signed_min = ~ reloc_signed_max;
bfd_vma check;
bfd_signed_vma signed_check;
/* Need to refetch the addend, reconstruct the top three bits, and glue the
two pieces together. */
if (globals->use_rel)
{
bfd_vma S = (upper_insn & 0x0400) >> 10;
bfd_vma hi = (upper_insn & 0x03ff);
bfd_vma I1 = (lower_insn & 0x2000) >> 13;
bfd_vma I2 = (lower_insn & 0x0800) >> 11;
bfd_vma lo = (lower_insn & 0x07ff);
I1 = !(I1 ^ S);
I2 = !(I2 ^ S);
S = !S;
signed_addend = (S << 24) | (I1 << 23) | (I2 << 22) | (hi << 12) | (lo << 1);
signed_addend -= (1 << 24); /* Sign extend. */
}
/* ??? Should handle interworking? GCC might someday try to
use this for tail calls. */
relocation = value + signed_addend;
relocation -= (input_section->output_section->vma
+ input_section->output_offset
+ rel->r_offset);
check = relocation >> howto->rightshift;
/* If this is a signed value, the rightshift just dropped
leading 1 bits (assuming twos complement). */
if ((bfd_signed_vma) relocation >= 0)
signed_check = check;
else
signed_check = check | ~((bfd_vma) -1 >> howto->rightshift);
/* Assumes two's complement. */
if (signed_check > reloc_signed_max || signed_check < reloc_signed_min)
overflow = TRUE;
/* Put RELOCATION back into the insn. */
{
bfd_vma S = (relocation & 0x01000000) >> 24;
bfd_vma I1 = (relocation & 0x00800000) >> 23;
bfd_vma I2 = (relocation & 0x00400000) >> 22;
bfd_vma hi = (relocation & 0x003ff000) >> 12;
bfd_vma lo = (relocation & 0x00000ffe) >> 1;
I1 = !(I1 ^ S);
I2 = !(I2 ^ S);
upper_insn = (upper_insn & (bfd_vma) 0xf800) | (S << 10) | hi;
lower_insn = (lower_insn & (bfd_vma) 0xd000) | (I1 << 13) | (I2 << 11) | lo;
}
/* Put the relocated value back in the object file: */
bfd_put_16 (input_bfd, upper_insn, hit_data);
bfd_put_16 (input_bfd, lower_insn, hit_data + 2);
return (overflow ? bfd_reloc_overflow : bfd_reloc_ok);
}
case R_ARM_THM_JUMP19: case R_ARM_THM_JUMP19:
/* Thumb32 conditional branch instruction. */ /* Thumb32 conditional branch instruction. */
{ {
@ -5255,6 +5194,17 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto,
signed_addend = addend; signed_addend = addend;
} }
/* Handle calls via the PLT. */
if (h != NULL && splt != NULL && h->plt.offset != (bfd_vma) -1)
{
value = (splt->output_section->vma
+ splt->output_offset
+ h->plt.offset);
/* Target the Thumb stub before the ARM PLT entry. */
value -= PLT_THUMB_STUB_SIZE;
*unresolved_reloc_p = FALSE;
}
/* ??? Should handle interworking? GCC might someday try to /* ??? Should handle interworking? GCC might someday try to
use this for tail calls. */ use this for tail calls. */
@ -6266,7 +6216,8 @@ arm_add_to_rel (bfd * abfd,
{ {
bfd_signed_vma addend; bfd_signed_vma addend;
if (howto->type == R_ARM_THM_CALL) if (howto->type == R_ARM_THM_CALL
|| howto->type == R_ARM_THM_JUMP24)
{ {
int upper_insn, lower_insn; int upper_insn, lower_insn;
int upper, lower; int upper, lower;
@ -7400,6 +7351,8 @@ elf32_arm_gc_sweep_hook (bfd * abfd,
sym_hashes = elf_sym_hashes (abfd); sym_hashes = elf_sym_hashes (abfd);
local_got_refcounts = elf_local_got_refcounts (abfd); local_got_refcounts = elf_local_got_refcounts (abfd);
check_use_blx(globals);
relend = relocs + sec->reloc_count; relend = relocs + sec->reloc_count;
for (rel = relocs; rel < relend; rel++) for (rel = relocs; rel < relend; rel++)
{ {
@ -7450,6 +7403,8 @@ elf32_arm_gc_sweep_hook (bfd * abfd,
case R_ARM_JUMP24: case R_ARM_JUMP24:
case R_ARM_PREL31: case R_ARM_PREL31:
case R_ARM_THM_CALL: case R_ARM_THM_CALL:
case R_ARM_THM_JUMP24:
case R_ARM_THM_JUMP19:
case R_ARM_MOVW_ABS_NC: case R_ARM_MOVW_ABS_NC:
case R_ARM_MOVT_ABS: case R_ARM_MOVT_ABS:
case R_ARM_MOVW_PREL_NC: case R_ARM_MOVW_PREL_NC:
@ -7471,7 +7426,11 @@ elf32_arm_gc_sweep_hook (bfd * abfd,
if (h->plt.refcount > 0) if (h->plt.refcount > 0)
{ {
h->plt.refcount -= 1; h->plt.refcount -= 1;
if (ELF32_R_TYPE (rel->r_info) == R_ARM_THM_CALL) if (r_type == R_ARM_THM_CALL)
eh->plt_maybe_thumb_refcount--;
if (r_type == R_ARM_THM_JUMP24
|| r_type == R_ARM_THM_JUMP19)
eh->plt_thumb_refcount--; eh->plt_thumb_refcount--;
} }
@ -7673,6 +7632,8 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
case R_ARM_JUMP24: case R_ARM_JUMP24:
case R_ARM_PREL31: case R_ARM_PREL31:
case R_ARM_THM_CALL: case R_ARM_THM_CALL:
case R_ARM_THM_JUMP24:
case R_ARM_THM_JUMP19:
case R_ARM_MOVW_ABS_NC: case R_ARM_MOVW_ABS_NC:
case R_ARM_MOVT_ABS: case R_ARM_MOVT_ABS:
case R_ARM_MOVW_PREL_NC: case R_ARM_MOVW_PREL_NC:
@ -7708,7 +7669,15 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
it, even if it's an ABS32 relocation. */ it, even if it's an ABS32 relocation. */
h->plt.refcount += 1; h->plt.refcount += 1;
/* It's too early to use htab->use_blx here, so we have to
record possible blx references separately from
relocs that definitely need a thumb stub. */
if (r_type == R_ARM_THM_CALL) if (r_type == R_ARM_THM_CALL)
eh->plt_maybe_thumb_refcount += 1;
if (r_type == R_ARM_THM_JUMP24
|| r_type == R_ARM_THM_JUMP19)
eh->plt_thumb_refcount += 1; eh->plt_thumb_refcount += 1;
} }
@ -8059,6 +8028,7 @@ elf32_arm_adjust_dynamic_symbol (struct bfd_link_info * info,
linkage table, and we can just do a PC24 reloc instead. */ linkage table, and we can just do a PC24 reloc instead. */
h->plt.offset = (bfd_vma) -1; h->plt.offset = (bfd_vma) -1;
eh->plt_thumb_refcount = 0; eh->plt_thumb_refcount = 0;
eh->plt_maybe_thumb_refcount = 0;
h->needs_plt = 0; h->needs_plt = 0;
} }
@ -8073,6 +8043,7 @@ elf32_arm_adjust_dynamic_symbol (struct bfd_link_info * info,
the link may change h->type. So fix it now. */ the link may change h->type. So fix it now. */
h->plt.offset = (bfd_vma) -1; h->plt.offset = (bfd_vma) -1;
eh->plt_thumb_refcount = 0; eh->plt_thumb_refcount = 0;
eh->plt_maybe_thumb_refcount = 0;
} }
/* If this is a weak symbol, and there is a real definition, the /* If this is a weak symbol, and there is a real definition, the
@ -8150,6 +8121,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
struct elf32_arm_link_hash_table *htab; struct elf32_arm_link_hash_table *htab;
struct elf32_arm_link_hash_entry *eh; struct elf32_arm_link_hash_entry *eh;
struct elf32_arm_relocs_copied *p; struct elf32_arm_relocs_copied *p;
bfd_signed_vma thumb_refs;
eh = (struct elf32_arm_link_hash_entry *) h; eh = (struct elf32_arm_link_hash_entry *) h;
@ -8191,7 +8163,11 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
/* If we will insert a Thumb trampoline before this PLT, leave room /* If we will insert a Thumb trampoline before this PLT, leave room
for it. */ for it. */
if (!htab->use_blx && eh->plt_thumb_refcount > 0) thumb_refs = eh->plt_thumb_refcount;
if (!htab->use_blx)
thumb_refs += eh->plt_maybe_thumb_refcount;
if (thumb_refs > 0)
{ {
h->plt.offset += PLT_THUMB_STUB_SIZE; h->plt.offset += PLT_THUMB_STUB_SIZE;
s->size += PLT_THUMB_STUB_SIZE; s->size += PLT_THUMB_STUB_SIZE;
@ -8900,6 +8876,7 @@ elf32_arm_finish_dynamic_symbol (bfd * output_bfd, struct bfd_link_info * info,
} }
else else
{ {
bfd_signed_vma thumb_refs;
/* Calculate the displacement between the PLT slot and the /* Calculate the displacement between the PLT slot and the
entry in the GOT. The eight-byte offset accounts for the entry in the GOT. The eight-byte offset accounts for the
value produced by adding to pc in the first instruction value produced by adding to pc in the first instruction
@ -8908,7 +8885,11 @@ elf32_arm_finish_dynamic_symbol (bfd * output_bfd, struct bfd_link_info * info,
BFD_ASSERT ((got_displacement & 0xf0000000) == 0); BFD_ASSERT ((got_displacement & 0xf0000000) == 0);
if (!htab->use_blx && eh->plt_thumb_refcount > 0) thumb_refs = eh->plt_thumb_refcount;
if (!htab->use_blx)
thumb_refs += eh->plt_maybe_thumb_refcount;
if (thumb_refs > 0)
{ {
put_thumb_insn (htab, output_bfd, put_thumb_insn (htab, output_bfd,
elf32_arm_plt_thumb_stub[0], ptr - 4); elf32_arm_plt_thumb_stub[0], ptr - 4);
@ -9638,10 +9619,13 @@ elf32_arm_output_plt_map (struct elf_link_hash_entry *h, void *inf)
} }
else else
{ {
bfd_boolean thumb_stub; bfd_signed_vma thumb_refs;
thumb_stub = eh->plt_thumb_refcount > 0 && !htab->use_blx; thumb_refs = eh->plt_thumb_refcount;
if (thumb_stub) if (!htab->use_blx)
thumb_refs += eh->plt_maybe_thumb_refcount;
if (thumb_refs > 0)
{ {
if (!elf32_arm_ouput_plt_map_sym (osi, ARM_MAP_THUMB, addr - 4)) if (!elf32_arm_ouput_plt_map_sym (osi, ARM_MAP_THUMB, addr - 4))
return FALSE; return FALSE;
@ -9655,7 +9639,7 @@ elf32_arm_output_plt_map (struct elf_link_hash_entry *h, void *inf)
/* A three-word PLT with no Thumb thunk contains only Arm code, /* A three-word PLT with no Thumb thunk contains only Arm code,
so only need to output a mapping symbol for the first PLT entry and so only need to output a mapping symbol for the first PLT entry and
entries with thumb thunks. */ entries with thumb thunks. */
if (thumb_stub || addr == 20) if (thumb_refs > 0 || addr == 20)
{ {
if (!elf32_arm_ouput_plt_map_sym (osi, ARM_MAP_ARM, addr)) if (!elf32_arm_ouput_plt_map_sym (osi, ARM_MAP_ARM, addr))
return FALSE; return FALSE;