This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[patch] R_ARM_REL32 and Thumb functions.
- From: Paul Brook <paul at codesourcery dot com>
- To: binutils at sourceware dot org
- Date: Thu, 20 Apr 2006 19:29:49 +0100
- Subject: [patch] R_ARM_REL32 and Thumb functions.
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;
if (fixP->fx_done || !seg->use_rela_p)
md_number_to_chars (buf, value, 4);
break;
Index: gas/config/tc-arm.h
===================================================================
RCS file: /var/cvsroot/src-cvs/src/gas/config/tc-arm.h,v
retrieving revision 1.36
diff -u -p -r1.36 tc-arm.h
--- gas/config/tc-arm.h 8 Oct 2005 17:07:16 -0000 1.36
+++ gas/config/tc-arm.h 20 Apr 2006 17:58:59 -0000
@@ -83,6 +83,9 @@ struct fix;
arm_relax_frag(segment, fragp, stretch)
extern int arm_relax_frag (asection *, struct frag *, long);
+#define md_optimize_expr(l,o,r) arm_optimize_expr (l, o, r)
+extern int arm_optimize_expr (expressionS *, operatorT, expressionS *);
+
#define md_cleanup() arm_cleanup ()
#define md_start_line_hook() arm_start_line_hook ()
@@ -148,6 +151,12 @@ extern void arm_md_end (void);
|| (FIX)->fx_r_type == BFD_RELOC_32 \
|| TC_FORCE_RELOCATION (FIX))
+/* Force output of R_ARM_REL32 relocations against thumb function symbols.
+ This is needed to ensure the low bit is handled correctly. */
+#define TC_FORCE_RELOCATION_SUB_SAME(FIX, SEG) \
+ (THUMB_IS_FUNC ((FIX)->fx_addsy) \
+ || !SEG_NORMAL (SEG))
+
#define TC_CONS_FIX_NEW cons_fix_new_arm
#define MAX_MEM_FOR_RS_ALIGN_CODE 31
Index: ld/testsuite/ld-arm/arm-elf.exp
===================================================================
RCS file: /var/cvsroot/src-cvs/src/ld/testsuite/ld-arm/arm-elf.exp,v
retrieving revision 1.11
diff -u -p -r1.11 arm-elf.exp
--- ld/testsuite/ld-arm/arm-elf.exp 7 Mar 2006 08:39:21 -0000 1.11
+++ ld/testsuite/ld-arm/arm-elf.exp 20 Apr 2006 14:47:23 -0000
@@ -119,6 +119,9 @@ set armelftests {
{"Thumb entry point" "-T arm.ld" "" {thumb-entry.s}
{{readelf -h thumb-entry.d}}
"thumb-entry"}
+ {"thumb-rel32" "-static -T arm.ld" "" {thumb-rel32.s}
+ {{objdump -s thumb-rel32.d}}
+ "thumb-rel32"}
}
run_ld_link_tests $armelftests
Index: ld/testsuite/ld-arm/thumb-rel32.d
===================================================================
RCS file: ld/testsuite/ld-arm/thumb-rel32.d
diff -N ld/testsuite/ld-arm/thumb-rel32.d
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-arm/thumb-rel32.d 20 Apr 2006 14:45:39 -0000
@@ -0,0 +1,7 @@
+
+.*: file format.*
+
+Contents of section .text:
+ 8000 (00000009 fffffffd|09000000 fdffffff) .*
+# Ignore .ARM.attributes section
+#...
Index: ld/testsuite/ld-arm/thumb-rel32.s
===================================================================
RCS file: ld/testsuite/ld-arm/thumb-rel32.s
diff -N ld/testsuite/ld-arm/thumb-rel32.s
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-arm/thumb-rel32.s 20 Apr 2006 16:36:07 -0000
@@ -0,0 +1,15 @@
+ .text
+ .arch armv4t
+ .global _start
+ .type _start, %function
+ .thumb_func
+_start:
+ .word bar - .
+ .word _start - .
+ .section .after, "ax", %progbits
+ .global bar
+ .type bar, %function
+ .thumb_func
+bar:
+ .word 0
+ .ident "GCC: (GNU) 4.1.0 (CodeSourcery ARM)"