This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[patch committed] SH: Define md_optimize_expr
- From: Kaz Kojima <kkojima at rr dot iij4u dot or dot jp>
- To: binutils at sources dot redhat dot com
- Date: Sat, 14 Apr 2007 23:23:56 +0900 (JST)
- Subject: [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)