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 _______________________________________________ bug-binutils mailing list bug-binutils@gnu.org http://lists.gnu.org/mailman/listinfo/bug-binutils