diff options
author | Ian Lance Taylor <ian@airs.com> | 1997-10-24 21:29:10 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@airs.com> | 1997-10-24 21:29:10 +0000 |
commit | e59390a7eb132e8592565431b71ba1f19c141a9e (patch) | |
tree | ee2352040fdfa3e533d61a0d03a084c7fd13a852 /gas/config | |
parent | 022278948f2034198be6cdc95cb4bc9b71122698 (diff) | |
download | gdb-e59390a7eb132e8592565431b71ba1f19c141a9e.zip gdb-e59390a7eb132e8592565431b71ba1f19c141a9e.tar.gz gdb-e59390a7eb132e8592565431b71ba1f19c141a9e.tar.bz2 |
* config/tc-ppc.c (md_assemble): When handling @l, always sign
extend if the operand expects a signed value.
PR 13667.
Diffstat (limited to 'gas/config')
-rw-r--r-- | gas/config/tc-ppc.c | 60 |
1 files changed, 50 insertions, 10 deletions
diff --git a/gas/config/tc-ppc.c b/gas/config/tc-ppc.c index 873a8d1..4f8771e 100644 --- a/gas/config/tc-ppc.c +++ b/gas/config/tc-ppc.c @@ -1852,7 +1852,11 @@ md_assemble (str) break; case BFD_RELOC_LO16: - if (ex.X_unsigned) + /* X_unsigned is the default, so if the user has done + something which cleared it, we always produce a + signed value. */ + if (ex.X_unsigned + && (operand->flags & PPC_OPERAND_SIGNED) == 0) ex.X_add_number &= 0xffff; else ex.X_add_number = (((ex.X_add_number & 0xffff) @@ -2424,6 +2428,7 @@ ppc_change_csect (sym) { symbolS **list_ptr; int after_toc; + int hold_chunksize; symbolS *list; /* This is a new csect. We need to look at the symbol class to @@ -2464,7 +2469,16 @@ ppc_change_csect (sym) abort (); } + /* We set the obstack chunk size to a small value before + changing subsegments, so that we don't use a lot of memory + space for what may be a small section. */ + hold_chunksize = chunksize; + chunksize = 64; + subseg_new (segment_name (S_GET_SEGMENT (sym)), sym->sy_tc.subseg); + + chunksize = hold_chunksize; + if (after_toc) ppc_after_toc_frag = frag_now; @@ -4005,7 +4019,7 @@ ppc_frob_symbol (sym) ppc_last_function = sym; if (sym->sy_tc.size != (symbolS *) NULL) { - resolve_symbol_value (sym->sy_tc.size); + resolve_symbol_value (sym->sy_tc.size, 1); SA_SET_SYM_FSIZE (sym, (long) S_GET_VALUE (sym->sy_tc.size)); } } @@ -4064,7 +4078,7 @@ ppc_frob_symbol (sym) - S_GET_VALUE (sym)); else { - resolve_symbol_value (sym->sy_tc.next); + resolve_symbol_value (sym->sy_tc.next, 1); a->x_csect.x_scnlen.l = (S_GET_VALUE (sym->sy_tc.next) - S_GET_VALUE (sym)); } @@ -4117,7 +4131,7 @@ ppc_frob_symbol (sym) } else { - resolve_symbol_value (next); + resolve_symbol_value (next, 1); a->x_csect.x_scnlen.l = (S_GET_VALUE (next) - S_GET_VALUE (sym)); } @@ -4148,7 +4162,7 @@ ppc_frob_symbol (sym) { while (csect->sy_tc.next != (symbolS *) NULL) { - resolve_symbol_value (csect->sy_tc.next); + resolve_symbol_value (csect->sy_tc.next, 1); if (S_GET_VALUE (csect->sy_tc.next) > S_GET_VALUE (sym)) break; csect = csect->sy_tc.next; @@ -4189,7 +4203,7 @@ ppc_frob_symbol (sym) /* The value is the offset from the enclosing csect. */ block = sym->sy_tc.within; csect = block->sy_tc.within; - resolve_symbol_value (csect); + resolve_symbol_value (csect, 1); S_SET_VALUE (sym, S_GET_VALUE (sym) - S_GET_VALUE (csect)); } else if (S_GET_STORAGE_CLASS (sym) == C_BINCL @@ -4414,7 +4428,7 @@ ppc_fix_adjustable (fix) { valueT val; - resolve_symbol_value (fix->fx_addsy); + resolve_symbol_value (fix->fx_addsy, 1); val = S_GET_VALUE (fix->fx_addsy); if (ppc_toc_csect != (symbolS *) NULL && fix->fx_addsy != (symbolS *) NULL @@ -4434,7 +4448,7 @@ ppc_fix_adjustable (fix) continue; if (sy->sy_tc.class != XMC_TC) break; - resolve_symbol_value (sy); + resolve_symbol_value (sy, 1); if (val == S_GET_VALUE (sy)) { fix->fx_addsy = sy; @@ -4513,7 +4527,7 @@ ppc_fix_adjustable (fix) && S_GET_SEGMENT (fix->fx_addsy) == bss_section && ! S_IS_EXTERNAL (fix->fx_addsy)) { - resolve_symbol_value (fix->fx_addsy->sy_frag->fr_symbol); + resolve_symbol_value (fix->fx_addsy->sy_frag->fr_symbol, 1); fix->fx_offset += (S_GET_VALUE (fix->fx_addsy) - S_GET_VALUE (fix->fx_addsy->sy_frag->fr_symbol)); fix->fx_addsy = fix->fx_addsy->sy_frag->fr_symbol; @@ -4798,9 +4812,35 @@ md_apply_fix3 (fixp, valuep, seg) case BFD_RELOC_24_PLT_PCREL: case BFD_RELOC_PPC_LOCAL24PC: - if (!fixp->fx_pcrel) + if (!fixp->fx_pcrel && !fixp->fx_done) abort (); + if (fixp->fx_done) + { + char *where; + unsigned long insn; + + /* Fetch the instruction, insert the fully resolved operand + value, and stuff the instruction back again. */ + where = fixp->fx_frag->fr_literal + fixp->fx_where; + if (target_big_endian) + insn = bfd_getb32 ((unsigned char *) where); + else + insn = bfd_getl32 ((unsigned char *) where); + if ((value & 3) != 0) + as_bad_where (fixp->fx_file, fixp->fx_line, + "must branch to an address a multiple of 4"); + if ((long)value << 6 >> 6 != value) + as_bad_where (fixp->fx_file, fixp->fx_line, + "@local or @plt branch destination is too far " + "away, %ld bytes", + value); + insn = insn | (value & 0x03fffffc); + if (target_big_endian) + bfd_putb32 ((bfd_vma) insn, (unsigned char *) where); + else + bfd_putl32 ((bfd_vma) insn, (unsigned char *) where); + } break; default: |