[PATCH][ARM] Fix handling of GOT_PREL in gas.

Doug Kwan (關振德) dougkwan@google.com
Thu Sep 16 08:45:00 GMT 2010


Hi

   This patch fixes a problem in which gas fails to assemble data
expression in the form:

    symbol(GOT_PREL) + (. - (.LPIC0 + 4))

where .LPIC0 is a local label defined in the same function after the
data expression.  Currently, LPIC0 is undefined when the data
expression is processed and that causes an error in the function
expr() because the two operands of the addition have different
segments.  The patch adds code to handle this situation.  This is
tested by the running the gas test suite and the new test case in this
patch.

-Doug

gas/ChangeLog:
2010-09-16  Doug Kwan  <dougkwan@google.com>

        * config/tc-arm.c (s_arm_elf_cons): Handle R_ARM_GOT_PREL specially.

gas/testsuite/ChangeLog:

2010-09-16  Doug Kwan  <dougkwan@google.com>

        * gas/arm/got_prel2.d: New.
        * gas/arm/got_prel2.s: New.
-------------- next part --------------
Index: gas/config/tc-arm.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-arm.c,v
retrieving revision 1.458
diff -u -u -p -r1.458 tc-arm.c
--- gas/config/tc-arm.c	9 Sep 2010 12:08:12 -0000	1.458
+++ gas/config/tc-arm.c	16 Sep 2010 08:25:37 -0000
@@ -3212,20 +3212,54 @@ s_arm_elf_cons (int nbytes)
 			howto->name, nbytes);
 	      else
 		{
-		  /* We've parsed an expression stopping at O_symbol.
-		     But there may be more expression left now that we
-		     have parsed the relocation marker.  Parse it again.
-		     XXX Surely there is a cleaner way to do this.  */
-		  char *p = input_line_pointer;
 		  int offset;
-		  char *save_buf = (char *) alloca (input_line_pointer - base);
-		  memcpy (save_buf, base, input_line_pointer - base);
-		  memmove (base + (input_line_pointer - before_reloc),
-			   base, before_reloc - base);
-
-		  input_line_pointer = base + (input_line_pointer-before_reloc);
-		  expression (&exp);
-		  memcpy (base, save_buf, p - base);
+		  char *p, *save_buf;
+
+		  SKIP_WHITESPACE();
+
+		  /* This could be an expression of the form:
+
+		     foo(GOT_PREL) + (. - (.LPIC0 + 8))
+
+		     and .LPIC0 might be a forward reference.  Generate
+		     an add-expression for fixing up.  We cannot use the
+		     code handling other relocation types below becasue
+		     .LPIC0 may be undefined at this point.  We would get
+		     an error in expression() since foo and .LPIC0 might
+		     have different segments.  */
+		    
+ 		  if (reloc == BFD_RELOC_ARM_GOT_PREL
+		      && *input_line_pointer == '+'
+		      && exp.X_op == O_symbol
+		      && exp.X_op_symbol == NULL)
+		    {
+		      expressionS right;
+		      symbolS *right_symbol;
+
+		      right.X_md = 0;
+		      expression (&right);
+		      right_symbol = make_expr_symbol(&right);
+		      exp.X_op = O_add;
+		      exp.X_op_symbol = right_symbol;
+		    }
+		  else
+		    {
+		      /* We've parsed an expression stopping at O_symbol.
+			 But there may be more expression left now that we
+			 have parsed the relocation marker.  Parse it again.
+			 XXX Surely there is a cleaner way to do this.  */
+		      p = input_line_pointer;
+		      save_buf =
+			(char *) alloca (input_line_pointer - base);
+		      memcpy (save_buf, base, input_line_pointer - base);
+		      memmove (base + (input_line_pointer - before_reloc),
+			       base, before_reloc - base);
+
+		      input_line_pointer =
+			base + (input_line_pointer-before_reloc);
+		      expression (&exp);
+		      memcpy (base, save_buf, p - base);
+		    }
 
 		  offset = nbytes - size;
 		  p = frag_more ((int) nbytes);
Index: gas/testsuite/gas/arm/got_prel2.d
===================================================================
RCS file: gas/testsuite/gas/arm/got_prel2.d
diff -N gas/testsuite/gas/arm/got_prel2.d
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gas/testsuite/gas/arm/got_prel2.d	16 Sep 2010 08:25:41 -0000
@@ -0,0 +1,20 @@
+# name: R_ARM_GOT_PREL relocation with forward PIC reference
+# source: got_prel2.s
+# as: -march=armv5te -meabi=5
+# objdump: -dr --prefix-addresses --show-raw-insn
+# target: *-*-*eabi *-*-symbianelf *-*-linux-* *-*-elf
+
+.*.o: +file format .*arm.*
+
+
+Disassembly of section \.text\.foo:
+0+00 <foo> ea000000 ? 	b	0+08 <foo\+0x8>
+0+04 <foo\+0x4> fffffff4 ?	\.word	0xfffffff4
+			4: R_ARM_GOT_PREL	i
+0+08 <foo\+0x8> e51f300c ?	ldr	r3, \[pc, #\-12\]	; 0+04 <foo\+0x4>
+0+0c <foo\+0xc> e08f3003 ?	add	r3, pc, r3
+0+10 <foo\+0x10> e5933000 ?	ldr	r3, \[r3\]
+0+14 <foo\+0x14> e5932000 ?	ldr	r2, \[r3\]
+0+18 <foo\+0x18> e5830000 ?	str	r0, \[r3\]
+0+1c <foo\+0x1c> e1a00002 ?	mov	r0, r2
+0+20 <foo\+0x20> e12fff1e ?	bx	lr
Index: gas/testsuite/gas/arm/got_prel2.s
===================================================================
RCS file: gas/testsuite/gas/arm/got_prel2.s
diff -N gas/testsuite/gas/arm/got_prel2.s
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gas/testsuite/gas/arm/got_prel2.s	16 Sep 2010 08:25:41 -0000
@@ -0,0 +1,22 @@
+        .text
+.Ltext0:
+        .section        .text.foo,"ax",%progbits
+        .align  2
+        .global foo
+        .type   foo, %function
+foo:
+        .fnstart
+	b	.L3
+.L2:
+        .word   i(GOT_PREL) + (. - (.LPIC0+4))
+.L3:
+        ldr     r3, .L2
+.LPIC0:
+        add     r3, pc, r3
+        ldr     r3, [r3]
+        ldr     r2, [r3]
+        str     r0, [r3]
+        mov     r0, r2
+        bx      lr
+        .align  2
+        .fnend


More information about the Binutils mailing list