RFC: Add AIX .ref support

Richard Sandiford rdsandiford@googlemail.com
Thu Jan 14 19:42:00 GMT 2010


This patch adds .ref support for AIX, to be compatible with the
native assembler.  I didn't go ahead and install it because of the
potentially-contentious change to gas/write.c.

.ref adds a R_REF relocation to the beginning of the current csect,
a bit like an ELF ".reloc ...,R_FOO_NONE".  However, the difficulty
is that relocations must be sorted in section order, so it isn't
appropriate to add a fixup at frag offset 0 after a fixup at frag
offset 4 (say).

Fortunately, we're always adding fixups at the beginning of a frag.
All we need is a version of fix_new that adds the new fixup to the head
of the list rather than the tail.  And the code to do that is already
there, protected by the now-defunct REVERSE_SORT_RELOCS macro.  So I
simply made it a C test and provided a wrapper function.

I suppose in a way this is just me being lazy.  Perhaps a more robust
fix would be to make the XCOFF port sort relocations before writing
them out.  This would make general .relocs work, for example.
Unfortunately, I don't have enough experience of other old formats
(a.out, other flavours of COFF) to know where the code should go.
I'm also not sure which (if any) formats support ELF-like relocation
chains, which would make it wrong to sort relocations against
overlapping fields.

Tested on powerpc-ibm-aix6.1.

Richard


bfd/
	* coff-rs6000.c (xcoff_howto_table): Change size to 0 and bitsize to 1.
	(_bfd_xcoff_reloc_type_lookup): Handle BFD_RELOC_NONE.
	* coff64-rs6000.c (xcoff64_howto_table): Change size to 0 and
	bitsize to 1.
	(xcoff64_reloc_type_lookup): Handle BFD_RELOC_NONE.

gas/
	* write.h (fix_at_start): Declare.
	* write.c (fix_new_internal): Add at_beginning parameter.
	Use it instead of REVERSE_SORT_RELOCS.  Fix the handling of
	seg_fix_tailP for the at_beginning/REVERSE_SORT_RELOCS case.
	(fix_new, fix_new_exp): Update accordingly.
	(fix_at_start): New function.
	* config/tc-ppc.c (md_pseudo_table): Add .ref to the OBJ_XCOFF section.
	(ppc_ref): New function, for OBJ_XCOFF.
	(md_apply_fix): Handle BFD_RELOC_NONE for OBJ_XCOFF.
	* config/te-i386aix.h (REVERSE_SORT_RELOCS): Remove #undef.

gas/testsuite/
	* gas/ppc/xcoff-ref-1.s, gas/ppc/xcoff-ref-1.l: New test.
	* gas/ppc/aix.exp: Run it.


ld/testsuite/
	* ld-powerpc/aix-ref-1-32.od, ld-powerpc/aix-ref-1-64.od,
	ld-powerpc/aix-ref-1.s: New tests.
	* ld-powerpc/aix52.exp: Run them.

Index: bfd/coff-rs6000.c
===================================================================
--- bfd/coff-rs6000.c	2010-01-14 19:18:18.000000000 +0000
+++ bfd/coff-rs6000.c	2010-01-14 19:18:30.000000000 +0000
@@ -896,11 +896,11 @@ reloc_howto_type xcoff_howto_table[] =
 
   EMPTY_HOWTO (0xe),
 
-  /* Non-relocating reference.  */
+  /* Non-relocating reference.  Bitsize is 1 so that r_rsize is 0.  */
   HOWTO (R_REF,			/* type */
 	 0,			/* rightshift */
-	 2,			/* size (0 = byte, 1 = short, 2 = long) */
-	 32,			/* bitsize */
+	 0,			/* size (0 = byte, 1 = short, 2 = long) */
+	 1,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
 	 complain_overflow_dont, /* complain_on_overflow */
@@ -1162,6 +1162,8 @@ _bfd_xcoff_reloc_type_lookup (abfd, code
     case BFD_RELOC_32:
     case BFD_RELOC_CTOR:
       return &xcoff_howto_table[0];
+    case BFD_RELOC_NONE:
+      return &xcoff_howto_table[0xf];
     default:
       return NULL;
     }
Index: bfd/coff64-rs6000.c
===================================================================
--- bfd/coff64-rs6000.c	2010-01-14 19:18:18.000000000 +0000
+++ bfd/coff64-rs6000.c	2010-01-14 19:18:31.000000000 +0000
@@ -1594,11 +1594,11 @@ reloc_howto_type xcoff64_howto_table[] =
 
   EMPTY_HOWTO (0xe),
 
-  /* Non-relocating reference.	*/
+  /* Non-relocating reference.  Bitsize is 1 so that r_rsize is 0.  */
   HOWTO (R_REF,			/* type */
 	 0,			/* rightshift */
-	 2,			/* size (0 = byte, 1 = short, 2 = long) */
-	 32,			/* bitsize */
+	 0,			/* size (0 = byte, 1 = short, 2 = long) */
+	 1,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
 	 complain_overflow_dont, /* complain_on_overflow */
@@ -1882,6 +1882,8 @@ xcoff64_reloc_type_lookup (abfd, code)
       return &xcoff64_howto_table[0x1c];
     case BFD_RELOC_64:
       return &xcoff64_howto_table[0];
+    case BFD_RELOC_NONE:
+      return &xcoff64_howto_table[0xf];
     default:
       return NULL;
     }
Index: gas/write.h
===================================================================
--- gas/write.h	2010-01-14 19:18:18.000000000 +0000
+++ gas/write.h	2010-01-14 19:18:31.000000000 +0000
@@ -176,6 +176,9 @@ extern void number_to_chars_bigendian (c
 extern fixS *fix_new
   (fragS * frag, int where, int size, symbolS * add_symbol,
    offsetT offset, int pcrel, bfd_reloc_code_real_type r_type);
+extern fixS *fix_at_start
+  (fragS * frag, int size, symbolS * add_symbol,
+   offsetT offset, int pcrel, bfd_reloc_code_real_type r_type);
 extern fixS *fix_new_exp
   (fragS * frag, int where, int size, expressionS *exp, int pcrel,
    bfd_reloc_code_real_type r_type);
Index: gas/write.c
===================================================================
--- gas/write.c	2010-01-14 19:18:18.000000000 +0000
+++ gas/write.c	2010-01-14 19:27:17.000000000 +0000
@@ -150,7 +150,8 @@ fix_new_internal (fragS *frag,		/* Which
 		  symbolS *sub_symbol,	/* X_op_symbol.  */
 		  offsetT offset,	/* X_add_number.  */
 		  int pcrel,		/* TRUE if PC-relative relocation.  */
-		  RELOC_ENUM r_type ATTRIBUTE_UNUSED /* Relocation type.  */)
+		  RELOC_ENUM r_type ATTRIBUTE_UNUSED /* Relocation type.  */,
+		  int at_beginning)	/* Add to the start of the list?  */
 {
   fixS *fixP;
 
@@ -194,10 +195,6 @@ fix_new_internal (fragS *frag,		/* Which
 
   as_where (&fixP->fx_file, &fixP->fx_line);
 
-  /* Usually, we want relocs sorted numerically, but while
-     comparing to older versions of gas that have relocs
-     reverse sorted, it is convenient to have this compile
-     time option.  xoxorich.  */
   {
 
     fixS **seg_fix_rootP = (frags_chained
@@ -207,22 +204,22 @@ fix_new_internal (fragS *frag,		/* Which
 			    ? &seg_info (now_seg)->fix_tail
 			    : &frchain_now->fix_tail);
 
-#ifdef REVERSE_SORT_RELOCS
-
-    fixP->fx_next = *seg_fix_rootP;
-    *seg_fix_rootP = fixP;
-
-#else /* REVERSE_SORT_RELOCS  */
-
-    fixP->fx_next = NULL;
-
-    if (*seg_fix_tailP)
-      (*seg_fix_tailP)->fx_next = fixP;
+    if (at_beginning)
+      {
+	fixP->fx_next = *seg_fix_rootP;
+	*seg_fix_rootP = fixP;
+	if (fixP->fx_next == NULL)
+	  *seg_fix_tailP = fixP;
+      }
     else
-      *seg_fix_rootP = fixP;
-    *seg_fix_tailP = fixP;
-
-#endif /* REVERSE_SORT_RELOCS  */
+      {
+	fixP->fx_next = NULL;
+	if (*seg_fix_tailP)
+	  (*seg_fix_tailP)->fx_next = fixP;
+	else
+	  *seg_fix_rootP = fixP;
+	*seg_fix_tailP = fixP;
+      }
   }
 
   return fixP;
@@ -240,7 +237,7 @@ fix_new (fragS *frag,		/* Which frag?  *
 	 RELOC_ENUM r_type		/* Relocation type.  */)
 {
   return fix_new_internal (frag, where, size, add_symbol,
-			   (symbolS *) NULL, offset, pcrel, r_type);
+			   (symbolS *) NULL, offset, pcrel, r_type, FALSE);
 }
 
 /* Create a fixup for an expression.  Currently we only support fixups
@@ -308,7 +305,19 @@ fix_new_exp (fragS *frag,		/* Which frag
       break;
     }
 
-  return fix_new_internal (frag, where, size, add, sub, off, pcrel, r_type);
+  return fix_new_internal (frag, where, size, add, sub, off, pcrel,
+			   r_type, FALSE);
+}
+
+/* Create a fixup at the beginning of FRAG.  The arguments are the same
+   as for fix_new, except that WHERE is implicitly 0.  */
+
+fixS *
+fix_at_start (fragS *frag, int size, symbolS *add_symbol,
+	      offsetT offset, int pcrel, RELOC_ENUM r_type)
+{
+  return fix_new_internal (frag, 0, size, add_symbol,
+			   (symbolS *) NULL, offset, pcrel, r_type, TRUE);
 }
 
 /* Generic function to determine whether a fixup requires a relocation.  */
Index: gas/config/tc-ppc.c
===================================================================
--- gas/config/tc-ppc.c	2010-01-14 19:18:18.000000000 +0000
+++ gas/config/tc-ppc.c	2010-01-14 19:22:40.000000000 +0000
@@ -108,6 +108,7 @@ static void ppc_change_csect (symbolS *,
 static void ppc_function (int);
 static void ppc_extern (int);
 static void ppc_lglobl (int);
+static void ppc_ref (int);
 static void ppc_section (int);
 static void ppc_named_section (int);
 static void ppc_stabx (int);
@@ -212,6 +213,7 @@ const pseudo_typeS md_pseudo_table[] =
   { "extern",	ppc_extern,	0 },
   { "function",	ppc_function,	0 },
   { "lglobl",	ppc_lglobl,	0 },
+  { "ref",	ppc_ref,	0 },
   { "rename",	ppc_rename,	0 },
   { "section",	ppc_named_section, 0 },
   { "stabx",	ppc_stabx,	0 },
@@ -3559,6 +3561,58 @@ ppc_lglobl (int ignore ATTRIBUTE_UNUSED)
   demand_empty_rest_of_line ();
 }
 
+/* The .ref pseudo-op.  It takes a list of symbol names and inserts R_REF
+   relocations at the beginning of the current csect.
+
+   (In principle, there's no reason why the relocations _have_ to be at
+   the beginning.  Anywhere in the csect would do.  However, inserting
+   at the beginning is what the native assmebler does, and it helps to
+   deal with cases where the .ref statements follow the section contents.)
+
+   ??? .refs don't work for empty .csects.  However, the native assembler
+   doesn't report an error in this case, and neither yet do we.  */
+
+static void
+ppc_ref (int ignore ATTRIBUTE_UNUSED)
+{
+  char *name;
+  char c;
+
+  if (ppc_current_csect == NULL)
+    {
+      as_bad (_(".ref outside .csect"));
+      ignore_rest_of_line ();
+      return;
+    }
+
+  do
+    {
+      name = input_line_pointer;
+      c = get_symbol_end ();
+
+      fix_at_start (symbol_get_frag (ppc_current_csect), 0,
+		    symbol_find_or_make (name), 0, FALSE, BFD_RELOC_NONE);
+
+      *input_line_pointer = c;
+      SKIP_WHITESPACE ();
+      c = *input_line_pointer;
+      if (c == ',')
+	{
+	  input_line_pointer++;
+	  SKIP_WHITESPACE ();
+	  if (is_end_of_line[(unsigned char) *input_line_pointer])
+	    {
+	      as_bad (_("missing symbol name"));
+	      ignore_rest_of_line ();
+	      return;
+	    }
+	}
+    }
+  while (c == ',');
+
+  demand_empty_rest_of_line ();
+}
+
 /* The .rename pseudo-op.  The RS/6000 assembler can rename symbols,
    although I don't know why it bothers.  */
 
@@ -6032,6 +6086,11 @@ md_apply_fix (fixS *fixP, valueT *valP, 
 			      PPC_HA (value), 2);
 	  break;
 
+#ifdef OBJ_XCOFF
+	case BFD_RELOC_NONE:
+	  break;
+#endif
+
 #ifdef OBJ_ELF
 	case BFD_RELOC_PPC64_HIGHER:
 	  if (fixP->fx_pcrel)
Index: gas/config/te-i386aix.h
===================================================================
--- gas/config/te-i386aix.h	2010-01-14 19:18:18.000000000 +0000
+++ gas/config/te-i386aix.h	2010-01-14 19:18:31.000000000 +0000
@@ -24,10 +24,6 @@ #define TE_I386AIX 1
 
 #include "obj-format.h"
 
-/* Undefine REVERSE_SORT_RELOCS to keep the relocation entries sorted
-   in ascending vaddr.  */
-#undef REVERSE_SORT_RELOCS
-
 /* Define KEEP_RELOC_INFO so that the strip reloc info flag F_RELFLG is
    not used in the filehdr for COFF output.  */
 #define KEEP_RELOC_INFO
Index: gas/testsuite/gas/ppc/xcoff-ref-1.s
===================================================================
--- /dev/null	2010-01-14 19:00:33.502131340 +0000
+++ gas/testsuite/gas/ppc/xcoff-ref-1.s	2010-01-14 19:18:31.000000000 +0000
@@ -0,0 +1,6 @@
+	.ref	foo
+	.csect	bar[rw]
+	.ref	1234
+	.ref	a,
+	.ref	,
+	.ref
Index: gas/testsuite/gas/ppc/xcoff-ref-1.l
===================================================================
--- /dev/null	2010-01-14 19:00:33.502131340 +0000
+++ gas/testsuite/gas/ppc/xcoff-ref-1.l	2010-01-14 19:18:31.000000000 +0000
@@ -0,0 +1,5 @@
+.*: Assembler messages:
+.*:1: Error: .ref outside .csect
+.*:3: Error: junk at end of line, first unrecognized character is `1'
+.*:4: Error: missing symbol name
+.*:5: Error: missing symbol name
Index: gas/testsuite/gas/ppc/aix.exp
===================================================================
--- gas/testsuite/gas/ppc/aix.exp	2010-01-14 19:18:18.000000000 +0000
+++ gas/testsuite/gas/ppc/aix.exp	2010-01-14 19:18:31.000000000 +0000
@@ -65,4 +65,6 @@ if [istarget powerpc-ibm-aix*] then {
     run_dump_test "textalign-xcoff-002"
     run_dump_test "xcoff-branch-1-32"
     run_dump_test "xcoff-branch-1-64"
+
+    run_list_test "xcoff-ref-1"
 }
Index: ld/testsuite/ld-powerpc/aix-ref-1-32.od
===================================================================
--- /dev/null	2010-01-14 19:00:33.502131340 +0000
+++ ld/testsuite/ld-powerpc/aix-ref-1-32.od	2010-01-14 19:18:31.000000000 +0000
@@ -0,0 +1,30 @@
+
+.*
+
+
+Disassembly of section \.text:
+
+.* <foo1>:
+.*:	60 00 00 00 	oril    r0,r0,0
+			.*: R_REF	foo2\+.*
+.*:	80 22 00 00 	l       r1,0\(r2\)
+			.*: R_TOC	stuff\+.*
+.*:	4e 80 00 20 	br
+
+.* <foo2>:
+.*:	60 00 00 00 	oril    r0,r0,0
+			.*: R_REF	foo6\+.*
+			.*: R_REF	foo4\+.*
+.*:	80 22 00 00 	l       r1,0\(r2\)
+			.*: R_TOC	stuff\+.*
+
+.* <foo4>:
+.*:	60 00 00 00 	oril    r0,r0,0
+.*:	80 22 00 00 	l       r1,0\(r2\)
+			.*: R_TOC	stuff\+.*
+
+.* <foo6>:
+.*:	60 00 00 00 	oril    r0,r0,0
+.*:	80 22 00 00 	l       r1,0\(r2\)
+			.*: R_TOC	stuff\+.*
+	\.\.\.
Index: ld/testsuite/ld-powerpc/aix-ref-1-64.od
===================================================================
--- /dev/null	2010-01-14 19:00:33.502131340 +0000
+++ ld/testsuite/ld-powerpc/aix-ref-1-64.od	2010-01-14 19:18:31.000000000 +0000
@@ -0,0 +1,30 @@
+
+.*
+
+
+Disassembly of section \.text:
+
+.* <foo1>:
+    .*:	60 00 00 00 	nop
+			.*: R_REF	foo2\+.*
+    .*:	e8 22 00 00 	ld      r1,0\(r2\)
+			.*: R_TOC	stuff\+.*
+    .*:	4e 80 00 20 	blr
+
+.* <foo2>:
+    .*:	60 00 00 00 	nop
+			.*: R_REF	foo6\+.*
+			.*: R_REF	foo4\+.*
+    .*:	e8 22 00 00 	ld      r1,0\(r2\)
+			.*: R_TOC	stuff\+.*
+
+.* <foo4>:
+    .*:	60 00 00 00 	nop
+    .*:	e8 22 00 00 	ld      r1,0\(r2\)
+			.*: R_TOC	stuff\+.*
+
+.* <foo6>:
+    .*:	60 00 00 00 	nop
+    .*:	e8 22 00 00 	ld      r1,0\(r2\)
+			.*: R_TOC	stuff\+.*
+	\.\.\.
Index: ld/testsuite/ld-powerpc/aix-ref-1.s
===================================================================
--- /dev/null	2010-01-14 19:00:33.502131340 +0000
+++ ld/testsuite/ld-powerpc/aix-ref-1.s	2010-01-14 19:18:31.000000000 +0000
@@ -0,0 +1,57 @@
+	.macro	loadtoc,sym
+	.if	size == 32
+	lwz	1,\sym(2)
+	.else
+	ld	1,\sym(2)
+	.endif
+	.endm
+
+	.toc
+LC01:	.tc	stuff[TC],stuff[RW]
+
+	.globl	foo1
+	.csect	foo1[pr]
+foo1:
+	.align	8
+	nop
+	loadtoc	LC01
+
+	.globl	foo2
+	.csect	foo2[pr]
+foo2:
+	nop
+	loadtoc	LC01
+	.ref	foo4 , foo6
+
+	.globl	foo3
+	.csect	foo3[pr]
+foo3:
+	nop
+	loadtoc	LC01
+
+	.globl	foo4
+	.csect	foo4[pr]
+foo4:
+	nop
+	loadtoc	LC01
+
+	.globl	foo5
+	.csect	foo5[pr]
+foo5:
+	nop
+	loadtoc	LC01
+	.ref	foo3
+
+	.globl	foo6
+	.csect	foo6[pr]
+foo6:
+	nop
+	loadtoc	LC01
+
+	.csect	foo1[pr]
+	blr
+	.ref	foo2
+
+	.csect	stuff[rw]
+stuff:
+	.long	1
Index: ld/testsuite/ld-powerpc/aix52.exp
===================================================================
--- ld/testsuite/ld-powerpc/aix52.exp	2010-01-14 19:18:19.000000000 +0000
+++ ld/testsuite/ld-powerpc/aix52.exp	2010-01-14 19:18:31.000000000 +0000
@@ -196,6 +196,11 @@ set aix52tests {
      "" {aix-rel-1.s}
      {{objdump -hr aix-rel-1.od}} "aix-rel-1.ro"}
 
+    {".ref test 1" "-efoo1"
+     "" {aix-ref-1.s}
+     {{objdump -dr aix-ref-1-SIZE.od}}
+     "aix-ref-1"}
+
     {"Weak test 1 (rel)" "-r"
      "" {aix-weak-1a.s aix-weak-1b.s}
      {{nm {} aix-weak-1-rel.nd} {objdump -h aix-weak-1-rel.hd}}



More information about the Binutils mailing list