This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Re: [patch] R_ARM_REL32 and Thumb functions.
- From: Richard Earnshaw <rearnsha at arm dot com>
- To: Paul Brook <paul at codesourcery dot com>
- Cc: binutils at sourceware dot org
- Date: Fri, 21 Apr 2006 09:13:44 +0100
- Subject: Re: [patch] R_ARM_REL32 and Thumb functions.
- References: <200604201929.50393.paul@codesourcery.com>
On Thu, 2006-04-20 at 19:29, Paul Brook wrote:
> The attached patch makes the R_ARM_REL32 relocation set the low bit of the
> value when the relocated symbol is a Thumb function, as required by the ARM
> EABI.
>
> I don't know if the current behavior is considered a bug or a feature for
> pre-EABI objects. For now I'm assuming bug, and making the change
> unconditionally. I can preserver the old behavior if anything depends on it.
>
> A slight complication is that gas will try and fold relative expressions at
> assembly time. This folding is done in generic code, so gets the value wrong.
> e.g.
>
> .thumb_func
> foo:
> .word foo - .
>
> Will be folded to zero by gas/expr.c:expr. I've [ab]used md_optimize_expr to
> prevent this happening.
>
> Initially I disabled the folding if either symbol was a Thumb function.
> However this ends up breaking the explicit cfi directives in libgcc, so I've
> only disabled the folding when the first symbol is a Thumb function.
>
> Tested with cross to arm-eabi.
> Ok?
>
> Paul
>
> 2006-04-20 Paul Brook <paul@codesourcery.com>
>
> bfd/
> * elf32-arm.c (elf32_arm_final_link_relocate): Set thumb funciton bit
> for R_ARM_REL32.
> gas/
> * config/tc-arm.c (arm_optimize_expr): New function.
> (md_apply_fix): Set thumb funciton bit for PC-relative relocations.
> * config/tc-arm.c (md_optimize_expr): Define
> (arm_optimize_expr): Add prototype.
> (TC_FORCE_RELOCATION_SUB_SAME): Define.
> ld/testsuite/
> * ld-arm/arm-elf.exp: Add thumb-rel32.
> * ld-arm/thumb-rel32.d: New test.
> * ld-arm/thumb-rel32.s: New test.
>
> ______________________________________________________________________
> Index: bfd/elf32-arm.c
> ===================================================================
> RCS file: /var/cvsroot/src-cvs/src/bfd/elf32-arm.c,v
> retrieving revision 1.70
> diff -u -p -r1.70 elf32-arm.c
> --- bfd/elf32-arm.c 16 Mar 2006 12:20:15 -0000 1.70
> +++ bfd/elf32-arm.c 20 Apr 2006 14:39:04 -0000
> @@ -3277,6 +3277,8 @@ elf32_arm_final_link_relocate (reloc_how
> value -= (input_section->output_section->vma
> + input_section->output_offset + rel->r_offset);
> value += addend;
> + if (sym_flags == STT_ARM_TFUNC)
> + value |= 1;
> break;
>
> case R_ARM_PREL31:
> Index: gas/config/tc-arm.c
> ===================================================================
> RCS file: /var/cvsroot/src-cvs/src/gas/config/tc-arm.c,v
> retrieving revision 1.256
> diff -u -p -r1.256 tc-arm.c
> --- gas/config/tc-arm.c 7 Apr 2006 15:11:19 -0000 1.256
> +++ gas/config/tc-arm.c 20 Apr 2006 17:31:47 -0000
> @@ -11491,6 +11491,29 @@ get_thumb32_insn (char * buf)
> return insn;
> }
>
> +
> +/* We usually want to set the low bit on the address of thumb function
> + symbols. In particular .word foo - . should have the low bit set.
> + Generic code tries to fold the difference of two symbols to
> + a constant. Prevent this and force a relocation when the first symbols
> + is a thumb function. */
> +int
> +arm_optimize_expr (expressionS *l, operatorT op, expressionS *r)
> +{
> + if (op == O_subtract
> + && l->X_op == O_symbol
> + && r->X_op == O_symbol
> + && THUMB_IS_FUNC (l->X_add_symbol))
> + {
> + l->X_op = O_subtract;
> + l->X_op_symbol = r->X_add_symbol;
> + l->X_add_number -= r->X_add_number;
> + return 1;
> + }
> + /* Process as normal. */
> + return 0;
> +}
> +
> void
> md_apply_fix (fixS * fixP,
> valueT * valP,
> @@ -12106,7 +12129,14 @@ md_apply_fix (fixS * fixP,
> case BFD_RELOC_ARM_TARGET1:
> case BFD_RELOC_ARM_ROSEGREL32:
> case BFD_RELOC_ARM_SBREL32:
> + if (fixP->fx_done || !seg->use_rela_p)
> + md_number_to_chars (buf, value, 4);
> + break;
> +
> case BFD_RELOC_32_PCREL:
> + /* Set the low bit of the value if the target is a thumb function. */
> + if (fixP->fx_done && fixP->fx_addsy && THUMB_IS_FUNC(fixP->fx_addsy))
> + value |= 1;
AFAICT, this is close, but not quite what AAELF says. The relocation
expression is
((S + A) | T) - .
That is, the T bit is orred in before the address of the place is
subtracted.
Normally, this doesn't change anything since the relocation is used with
.word which has 4-byte alignment. However, if a .4byte directive is
used, then there are no alignment constraints and the order of
processing becomes significant.
R.