bug-binutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

PATCH: fix incorrect PC-relative relocations with '.word'


From: Mat Hostetter
Subject: PATCH: fix incorrect PC-relative relocations with '.word'
Date: 11 Nov 2008 15:23:10 -0500

This is for gas 2.18, but it looks like the same bug is present in 2.19.

emit_expr, used by '.word' and others, grabs dot_value for the current
frag, does some processing, and later calls frag_more.  Unfortunately,
the frag_more call can realize the frag is not big enough and switch
to a new frag.  That's bad because the dot_value already recorded an
offset into the old frag, which is completely wrong for the new frag.

The result is that you can get PC-relative relocations with incorrect
offsets if they happen to span the byte boundary where a frag fills
up.  I saw this with a PC-relative relocation at a large odd byte
offset, which is probably the only time this can happen.  Unaligned
PC-relative offsets are an unusual case, which is why this probably
hasn't been reported before.

My fix is simply to reserve enough space before calling frag_now_fix
that the frag won't run out of room if frag_more is called later.


--- gas/read.c~ 2008-08-18 12:56:22.864271000 -0400
+++ gas/read.c  2008-11-11 15:00:33.487833000 -0500
@@ -3891,30 +3891,33 @@
 
 /* Put the contents of expression EXP into the object file using
    NBYTES bytes.  If need_pass_2 is 1, this does nothing.  */
 
 void
 emit_expr (expressionS *exp, unsigned int nbytes)
 {
   operatorT op;
   register char *p;
   valueT extra_digit = 0;
 
   /* Don't do anything if we are going to make another pass.  */
   if (need_pass_2)
     return;
 
+  /* Grow the current frag now so that dot_value does not get invalidated
+     if the frag were to fill up in the frag_more() call below. */
+  frag_grow (nbytes);
   dot_value = frag_now_fix ();
 
 #ifndef NO_LISTING
 #ifdef OBJ_ELF
   /* When gcc emits DWARF 1 debugging pseudo-ops, a line number will
      appear as a four byte positive constant in the .line section,
      followed by a 2 byte 0xffff.  Look for that case here.  */
   {
     static int dwarf_line = -1;
 
     if (strcmp (segment_name (now_seg), ".line") != 0)
       dwarf_line = -1;
     else if (dwarf_line >= 0
             && nbytes == 2
             && exp->X_op == O_constant




reply via email to

[Prev in Thread] Current Thread [Next in Thread]