This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[patch committed] SH: Define md_optimize_expr


Hi,

I've applied the attached SH specific patch for gas.
sh-elf assembler fails for the lines below:

  bar:
	.long	0
	.rept	. - bar
	.byte	1
	.endr

with

  test.s:3: Error: bad or irreducible absolute expression

This was reported on sh-linux mailing list ~3 years ago, but I forgot
it completely.  Interestingly, it doesn't fail if the first .long is
replaced with .byte.
In the faulty case, SH uses an rs_align_test frag in the expression
for bar and the difference . - bar wasn't simplified with the expr
function.  On other targets, bar is associated with an rs_fill frag
and the above difference is simplified the constant with expr.
The patch is to simplify it in expr with defining md_optimize_expr
for this target.
It's regtested on sh-elf, sh64-elf and sh4-unknown-linux-gnu with no
new failures.

Regards,
	kaz
--
2007-04-14  Kaz Kojima  <kkojima@rr.iij4u.or.jp>

	* config/tc-sh.c (align_test_frag_offset_fixed_p): New.
	(sh_optimize_expr): Likewise.
	* config/tc-sh.h (md_optimize_expr): Define.
	(sh_optimize_expr): Prototype.

diff -up ORIG/src/gas/config/tc-sh.c LOCAL/src/gas/config/tc-sh.c
--- ORIG/src/gas/config/tc-sh.c	2006-10-29 09:35:25.000000000 +0900
+++ LOCAL/src/gas/config/tc-sh.c	2007-04-11 14:34:38.000000000 +0900
@@ -825,8 +825,91 @@ sh_elf_cons (register int nbytes)
   else
     demand_empty_rest_of_line ();
 }
+
+/* The regular frag_offset_fixed_p doesn't work for rs_align_test
+   frags.  */
+
+static bfd_boolean
+align_test_frag_offset_fixed_p (const fragS *frag1, const fragS *frag2,
+				bfd_vma *offset)
+{
+  const fragS *frag;
+  bfd_vma off;
+
+  /* Start with offset initialised to difference between the two frags.
+     Prior to assigning frag addresses this will be zero.  */
+  off = frag1->fr_address - frag2->fr_address;
+  if (frag1 == frag2)
+    {
+      *offset = off;
+      return TRUE;
+    }
+
+  /* Maybe frag2 is after frag1.  */
+  frag = frag1;
+  while (frag->fr_type == rs_align_test)
+    {
+      off += frag->fr_fix;
+      frag = frag->fr_next;
+      if (frag == NULL)
+	break;
+      if (frag == frag2)
+	{
+	  *offset = off;
+	  return TRUE;
+	}
+    }
+
+  /* Maybe frag1 is after frag2.  */
+  off = frag1->fr_address - frag2->fr_address;
+  frag = frag2;
+  while (frag->fr_type == rs_align_test)
+    {
+      off -= frag->fr_fix;
+      frag = frag->fr_next;
+      if (frag == NULL)
+	break;
+      if (frag == frag1)
+	{
+	  *offset = off;
+	  return TRUE;
+	}
+    }
+
+  return FALSE;
+}
 #endif /* OBJ_ELF */
 
+/* Optimize a difference of symbols which have rs_align_test frag if
+   possible.  */
+
+int
+sh_optimize_expr (expressionS *l, operatorT op, expressionS *r)
+{
+#ifdef OBJ_ELF
+  bfd_vma frag_off;
+
+  if (op == O_subtract
+      && l->X_op == O_symbol
+      && r->X_op == O_symbol
+      && S_GET_SEGMENT (l->X_add_symbol) == S_GET_SEGMENT (r->X_add_symbol)
+      && (SEG_NORMAL (S_GET_SEGMENT (l->X_add_symbol))
+	  || r->X_add_symbol == l->X_add_symbol)
+      && align_test_frag_offset_fixed_p (symbol_get_frag (l->X_add_symbol),
+					 symbol_get_frag (r->X_add_symbol),
+					 &frag_off))
+    {
+      l->X_add_number -= r->X_add_number;
+      l->X_add_number -= frag_off / OCTETS_PER_BYTE;
+      l->X_add_number += (S_GET_VALUE (l->X_add_symbol)
+			  - S_GET_VALUE (r->X_add_symbol));
+      l->X_op = O_constant;
+      l->X_add_symbol = 0;
+      return 1;
+    }
+#endif /* OBJ_ELF */
+  return 0;
+}
 
 /* This function is called once, at assembler startup time.  This should
    set up all the tables, etc that the MD part of the assembler needs.  */
LOCAL/src/gas/configãããïïïïïï: tc-sh.c~
diff -up ORIG/src/gas/config/tc-sh.h LOCAL/src/gas/config/tc-sh.h
--- ORIG/src/gas/config/tc-sh.h	2007-02-27 22:38:04.000000000 +0900
+++ LOCAL/src/gas/config/tc-sh.h	2007-04-04 08:55:46.000000000 +0900
@@ -44,6 +44,12 @@ extern int sh_small;
 #define md_cons_align(nbytes) sh_cons_align (nbytes)
 extern void sh_cons_align (int);
 
+/* We need to optimize expr with taking account of rs_align_test
+   frags.  */
+
+#define md_optimize_expr(l,o,r) sh_optimize_expr (l, o, r)
+extern int sh_optimize_expr (expressionS *, operatorT, expressionS *);
+
 /* When relaxing, we need to generate relocations for alignment
    directives.  */
 #define HANDLE_ALIGN(frag) sh_handle_align (frag)

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]