/* write.c - emit .o file
- Copyright (C) 1986, 87, 90, 91, 92, 93, 1994 Free Software Foundation, Inc.
+ Copyright (C) 1986, 87, 90, 91, 92, 93, 94, 95, 96, 97, 1998
+ Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with GAS; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+ along with GAS; see the file COPYING. If not, write to the Free
+ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA. */
/* This thing should be set up to do byteordering correctly. But... */
#define TC_FORCE_RELOCATION(FIXP) 0
#endif
+#ifndef TC_FORCE_RELOCATION_SECTION
+#define TC_FORCE_RELOCATION_SECTION(FIXP,SEG) TC_FORCE_RELOCATION(FIXP)
+#endif
+
+#ifndef MD_PCREL_FROM_SECTION
+#define MD_PCREL_FROM_SECTION(FIXP, SEC) md_pcrel_from(FIXP)
+#endif
+
#ifndef WORKING_DOT_WORD
extern CONST int md_short_jump_size;
extern CONST int md_long_jump_size;
#endif /* BFD_ASSEMBLER */
+static int n_fixups;
+
#ifdef BFD_ASSEMBLER
static fixS *fix_new_internal PARAMS ((fragS *, int where, int size,
symbolS *add, symbolS *sub,
static long fixup_segment PARAMS ((fixS * fixP, segT this_segment_type));
#endif
static relax_addressT relax_align PARAMS ((relax_addressT addr, int align));
+#if defined (BFD_ASSEMBLER) || ! defined (BFD)
+static fragS *chain_frchains_together_1 PARAMS ((segT, struct frchain *));
+#endif
+#ifdef BFD_ASSEMBLER
+static void chain_frchains_together PARAMS ((bfd *, segT, PTR));
+static void cvt_frag_to_fill PARAMS ((segT, fragS *));
+static void relax_and_size_seg PARAMS ((bfd *, asection *, PTR));
+static void adjust_reloc_syms PARAMS ((bfd *, asection *, PTR));
+static void write_relocs PARAMS ((bfd *, asection *, PTR));
+static void write_contents PARAMS ((bfd *, asection *, PTR));
+static void set_symtab PARAMS ((void));
+#endif
+#if defined (BFD_ASSEMBLER) || (! defined (BFD) && ! defined (OBJ_AOUT))
+static void merge_data_into_text PARAMS ((void));
+#endif
+#if ! defined (BFD_ASSEMBLER) && ! defined (BFD)
+static void cvt_frag_to_fill PARAMS ((object_headers *, segT, fragS *));
+static void remove_subsegs PARAMS ((frchainS *, int, fragS **, fragS **));
+static void relax_and_size_all_segments PARAMS ((void));
+#endif
/*
* fix_new()
{
fixS *fixP;
+ n_fixups++;
+
fixP = (fixS *) obstack_alloc (¬es, sizeof (fixS));
fixP->fx_frag = frag;
fixP->fx_where = where;
fixP->fx_size = size;
+ /* We've made fx_size a narrow field; check that it's wide enough. */
+ if (fixP->fx_size != size)
+ {
+ as_bad (_("field fx_size too small to hold %d"), size);
+ abort ();
+ }
fixP->fx_addsy = add_symbol;
fixP->fx_subsy = sub_symbol;
fixP->fx_offset = offset;
fixP->fx_pcrel_adjust = 0;
fixP->fx_bit_fixP = 0;
fixP->fx_addnumber = 0;
- fixP->tc_fix_data = NULL;
fixP->fx_tcbit = 0;
fixP->fx_done = 0;
+ fixP->fx_no_overflow = 0;
+ fixP->fx_signed = 0;
-#if defined (TC_I960) || defined (TC_NS32K)
- fixP->fx_bsr = 0;
+#ifdef TC_FIX_TYPE
+ TC_INIT_FIX_DATA(fixP);
#endif
as_where (&fixP->fx_file, &fixP->fx_line);
fix_new (frag, where, size, add_symbol, offset, pcrel, r_type)
fragS *frag; /* Which frag? */
int where; /* Where in that frag? */
- short int size; /* 1, 2, or 4 usually. */
+ int size; /* 1, 2, or 4 usually. */
symbolS *add_symbol; /* X_add_symbol. */
offsetT offset; /* X_add_number. */
int pcrel; /* TRUE if PC-relative relocation. */
fix_new_exp (frag, where, size, exp, pcrel, r_type)
fragS *frag; /* Which frag? */
int where; /* Where in that frag? */
- short int size; /* 1, 2, or 4 usually. */
+ int size; /* 1, 2, or 4 usually. */
expressionS *exp; /* Expression. */
int pcrel; /* TRUE if PC-relative relocation. */
#ifdef BFD_ASSEMBLER
symbolS *add = NULL;
symbolS *sub = NULL;
offsetT off = 0;
-
+
switch (exp->X_op)
{
case O_absent:
/* This comes up when _GLOBAL_OFFSET_TABLE_+(.-L0) is read, if
the difference expression cannot immediately be reduced. */
{
- extern symbolS *make_expr_symbol ();
symbolS *stmp = make_expr_symbol (exp);
exp->X_op = O_symbol;
exp->X_op_symbol = 0;
return fix_new_exp (frag, where, size, exp, pcrel, r_type);
}
+ case O_symbol_rva:
+ add = exp->X_add_symbol;
+ off = exp->X_add_number;
+
+#if defined(BFD_ASSEMBLER)
+ r_type = BFD_RELOC_RVA;
+#else
+#if defined(TC_RVA_RELOC)
+ r_type = TC_RVA_RELOC;
+#else
+ as_fatal(_("rva not supported"));
+#endif
+#endif
+ break;
+
case O_uminus:
sub = exp->X_add_symbol;
off = exp->X_add_number;
case O_constant:
off = exp->X_add_number;
break;
-
+
default:
- as_bad ("expression too complex for fixup");
+ add = make_expr_symbol (exp);
+ break;
}
return fix_new_internal (frag, where, size, add, sub, off,
*charPP += length;
}
-#ifndef BFD_ASSEMBLER
+#ifndef BFD_ASSEMBLER
int section_alignment[SEG_MAXIMUM_ORDINAL];
#endif
* boundary, all of the other alignments within it will work. At
* least one object format really uses this info.
*/
-void
+void
record_alignment (seg, align)
/* Segment to which alignment pertains */
segT seg;
boundary, etc.) */
int align;
{
+ if (seg == absolute_section)
+ return;
#ifdef BFD_ASSEMBLER
- if (align > bfd_get_section_alignment (stdoutput, seg))
+ if ((unsigned int) align > bfd_get_section_alignment (stdoutput, seg))
bfd_set_section_alignment (stdoutput, seg, align);
#else
if (align > section_alignment[(int) seg])
{
prev_frag->fr_next = frchp->frch_root;
prev_frag = frchp->frch_last;
+ assert (prev_frag->fr_type != 0);
#ifdef BFD_ASSEMBLER
if (frchp->fix_root != (fixS *) NULL)
{
}
#endif
}
+ assert (prev_frag->fr_type != 0);
prev_frag->fr_next = 0;
return prev_frag;
}
#if !defined (BFD) && !defined (BFD_ASSEMBLER)
-void
+static void
remove_subsegs (head, seg, root, last)
frchainS *head;
int seg;
fragS *fragP;
#else
static void
-cvt_frag_to_fill (headersP, fragP)
+cvt_frag_to_fill (headersP, sec, fragP)
object_headers *headersP;
+ segT sec;
fragS *fragP;
#endif
{
fragP->fr_offset = (fragP->fr_next->fr_address
- fragP->fr_address
- fragP->fr_fix) / fragP->fr_var;
- assert (fragP->fr_offset >= 0);
+ if (fragP->fr_offset < 0)
+ {
+ as_bad (_("attempt to .org/.space backwards? (%ld)"),
+ (long) fragP->fr_offset);
+ }
fragP->fr_type = rs_fill;
break;
case rs_fill:
break;
+ case rs_leb128:
+ {
+ valueT value = S_GET_VALUE (fragP->fr_symbol);
+ int size;
+
+ size = output_leb128 (fragP->fr_literal + fragP->fr_fix, value,
+ fragP->fr_subtype);
+
+ fragP->fr_fix += size;
+ fragP->fr_type = rs_fill;
+ fragP->fr_var = 0;
+ fragP->fr_offset = 0;
+ fragP->fr_symbol = NULL;
+ }
+ break;
+
+ case rs_cfa:
+ eh_frame_convert_frag (fragP);
+ break;
+
case rs_machine_dependent:
#ifdef BFD_ASSEMBLER
md_convert_frag (stdoutput, sec, fragP);
#else
- md_convert_frag (headersP, fragP);
+ md_convert_frag (headersP, sec, fragP);
#endif
- assert (fragP->fr_next == NULL || (fragP->fr_next->fr_address - fragP->fr_address == fragP->fr_fix));
+ assert (fragP->fr_next == NULL
+ || ((offsetT) (fragP->fr_next->fr_address - fragP->fr_address)
+ == fragP->fr_fix));
/*
* After md_convert_frag, we make the frag into a ".space 0".
int x;
valueT size, newsize;
+ subseg_change (sec, 0);
+
flags = bfd_get_section_flags (abfd, sec);
seginfo = seg_info (sec);
}
}
#else
-#define dump_section_relocs(ABFD,SEC,STREAM) (void)(ABFD,SEC,STREAM)
+#define dump_section_relocs(ABFD,SEC,STREAM) ((void) 0)
#endif
#ifndef EMIT_SECTION_SYMBOLS
symbolS *sym;
asection *symsec;
- reduce_fixup:
-
#ifdef DEBUG5
fprintf (stderr, "\n\nadjusting fixup:\n");
print_fixup (fixp);
#endif
sym = fixp->fx_addsy;
- symsec = sym->bsym->section;
+
+ /* All symbols should have already been resolved at this
+ point. It is possible to see unresolved expression
+ symbols, though, since they are not in the regular symbol
+ table. */
+ if (sym != NULL && ! sym->sy_resolved)
+ resolve_symbol_value (sym, 1);
+ if (fixp->fx_subsy != NULL && ! fixp->fx_subsy->sy_resolved)
+ resolve_symbol_value (fixp->fx_subsy, 1);
+
+ /* If this symbol is equated to an undefined symbol, convert
+ the fixup to being against that symbol. */
+ if (sym->sy_value.X_op == O_symbol
+ && (! S_IS_DEFINED (sym) || S_IS_COMMON (sym)))
+ {
+ fixp->fx_offset += sym->sy_value.X_add_number;
+ sym = sym->sy_value.X_add_symbol;
+ fixp->fx_addsy = sym;
+ }
+
+ symsec = S_GET_SEGMENT (sym);
+
+ if (sym != NULL && sym->sy_mri_common)
+ {
+ /* These symbols are handled specially in fixup_segment. */
+ goto done;
+ }
+
+ if (bfd_is_abs_section (symsec))
+ {
+ /* The fixup_segment routine will not use this symbol in a
+ relocation unless TC_FORCE_RELOCATION returns 1. */
+ if (TC_FORCE_RELOCATION (fixp))
+ {
+ fixp->fx_addsy->sy_used_in_reloc = 1;
+#ifdef UNDEFINED_DIFFERENCE_OK
+ if (fixp->fx_subsy != NULL)
+ fixp->fx_subsy->sy_used_in_reloc = 1;
+#endif
+ }
+ goto done;
+ }
/* If it's one of these sections, assume the symbol is
definitely going to be output. The code in
as well, so if you change this code you should look at that
code. */
if (bfd_is_und_section (symsec)
- || bfd_is_abs_section (symsec)
|| bfd_is_com_section (symsec))
{
fixp->fx_addsy->sy_used_in_reloc = 1;
+#ifdef UNDEFINED_DIFFERENCE_OK
+ /* We have the difference of an undefined symbol and some
+ other symbol. Make sure to mark the other symbol as used
+ in a relocation so that it will always be output. */
+ if (fixp->fx_subsy)
+ fixp->fx_subsy->sy_used_in_reloc = 1;
+#endif
goto done;
}
+ /* Don't try to reduce relocs which refer to .linkonce
+ sections. It can lead to confusion when a debugging
+ section refers to a .linkonce section. I hope this will
+ always be correct. */
+ if (symsec != sec)
+ {
+ boolean linkonce;
+
+ linkonce = false;
+#ifdef BFD_ASSEMBLER
+ if ((bfd_get_section_flags (stdoutput, symsec) & SEC_LINK_ONCE)
+ != 0)
+ linkonce = true;
+#endif
+#ifdef OBJ_ELF
+ /* The GNU toolchain uses an extension for ELF: a section
+ beginning with the magic string .gnu.linkonce is a
+ linkonce section. */
+ if (strncmp (segment_name (symsec), ".gnu.linkonce",
+ sizeof ".gnu.linkonce" - 1) == 0)
+ linkonce = true;
+#endif
+
+ if (linkonce)
+ {
+ fixp->fx_addsy->sy_used_in_reloc = 1;
+#ifdef UNDEFINED_DIFFERENCE_OK
+ if (fixp->fx_subsy != NULL)
+ fixp->fx_subsy->sy_used_in_reloc = 1;
+#endif
+ goto done;
+ }
+ }
+
/* Since we're reducing to section symbols, don't attempt to reduce
anything that's already using one. */
if (sym->bsym->flags & BSF_SECTION_SYM)
#endif
/* Is there some other (target cpu dependent) reason we can't adjust
- this one? (E.g. relocations involving function addresses on
+ this one? (E.g. relocations involving function addresses on
the PA. */
#ifdef tc_fix_adjustable
if (! tc_fix_adjustable (fixp))
}
#endif
- /* For PIC support: We may get expressions like
- "_GLOBAL_OFFSET_TABLE_+(.-L5)" where "." and "L5" may not
- necessarily have had a fixed difference initially. But now
- it should be a known constant, so we can reduce it. Since
- we can't easily handle a symbol value that looks like
- someUndefinedSymbol+const, though, we convert the fixup to
- access the undefined symbol directly, and discard the
- intermediate symbol. */
- if (S_GET_SEGMENT (sym) == expr_section
- && sym->sy_value.X_op == O_add
- && (resolve_symbol_value (sym->sy_value.X_add_symbol),
- S_GET_SEGMENT (sym->sy_value.X_add_symbol) == undefined_section)
- && (resolve_symbol_value (sym->sy_value.X_op_symbol),
- S_GET_SEGMENT (sym->sy_value.X_op_symbol) == absolute_section))
- {
- fixp->fx_offset += S_GET_VALUE (sym->sy_value.X_op_symbol);
- fixp->fx_offset += sym->sy_value.X_add_number;
- fixp->fx_addsy = sym->sy_value.X_add_symbol;
- goto reduce_fixup;
- }
-
/* If the section symbol isn't going to be output, the relocs
at least should still work. If not, figure out what to do
- when we run into that case. */
+ when we run into that case.
+
+ We refetch the segment when calling section_symbol, rather
+ than using symsec, because S_GET_VALUE may wind up changing
+ the section when it calls resolve_symbol_value. */
fixp->fx_offset += S_GET_VALUE (sym);
- fixp->fx_addsy = section_symbol (symsec);
+ fixp->fx_addsy = section_symbol (S_GET_SEGMENT (sym));
fixp->fx_addsy->sy_used_in_reloc = 1;
done:
#ifndef RELOC_EXPANSION_POSSIBLE
/* Set up reloc information as well. */
- relocs = (arelent **) bfd_alloc_by_size_t (stdoutput,
- n * sizeof (arelent *));
+ relocs = (arelent **) xmalloc (n * sizeof (arelent *));
memset ((char*)relocs, 0, n * sizeof (arelent*));
i = 0;
{
arelent *reloc;
bfd_reloc_status_type s;
+ symbolS *sym;
if (fixp->fx_done)
{
n--;
continue;
}
+
+ /* If this is an undefined symbol which was equated to another
+ symbol, then use generate the reloc against the latter symbol
+ rather than the former. */
+ sym = fixp->fx_addsy;
+ while (sym->sy_value.X_op == O_symbol
+ && (! S_IS_DEFINED (sym) || S_IS_COMMON (sym)))
+ {
+ symbolS *n;
+
+ /* We must avoid looping, as that can occur with a badly
+ written program. */
+ n = sym->sy_value.X_add_symbol;
+ if (n == sym)
+ break;
+ fixp->fx_offset += sym->sy_value.X_add_number;
+ sym = n;
+ }
+ fixp->fx_addsy = sym;
+
reloc = tc_gen_reloc (sec, fixp);
if (!reloc)
{
n--;
continue;
}
+
+#if 0
+ /* This test is triggered inappropriately for the SH. */
if (fixp->fx_where + fixp->fx_size
> fixp->fx_frag->fr_fix + fixp->fx_frag->fr_offset)
abort ();
+#endif
s = bfd_install_relocation (stdoutput, reloc,
fixp->fx_frag->fr_literal,
case bfd_reloc_ok:
break;
case bfd_reloc_overflow:
- as_bad_where (fixp->fx_file, fixp->fx_line, "relocation overflow");
+ as_bad_where (fixp->fx_file, fixp->fx_line, _("relocation overflow"));
break;
default:
- as_fatal ("%s:%u: bad return from bfd_perform_relocation",
+ as_fatal (_("%s:%u: bad return from bfd_install_relocation"),
fixp->fx_file, fixp->fx_line);
}
relocs[i++] = reloc;
#else
n = n * MAX_RELOC_EXPANSION;
/* Set up reloc information as well. */
- relocs = (arelent **) bfd_alloc_by_size_t (stdoutput,
- n * sizeof (arelent *));
+ relocs = (arelent **) xmalloc (n * sizeof (arelent *));
i = 0;
for (fixp = seginfo->fix_root; fixp != (fixS *) NULL; fixp = fixp->fx_next)
arelent **reloc;
char *data;
bfd_reloc_status_type s;
+ symbolS *sym;
int j;
if (fixp->fx_done)
n--;
continue;
}
+
+ /* If this is an undefined symbol which was equated to another
+ symbol, then use generate the reloc against the latter symbol
+ rather than the former. */
+ sym = fixp->fx_addsy;
+ while (sym->sy_value.X_op == O_symbol
+ && (! S_IS_DEFINED (sym) || S_IS_COMMON (sym)))
+ sym = sym->sy_value.X_add_symbol;
+ fixp->fx_addsy = sym;
+
reloc = tc_gen_reloc (sec, fixp);
for (j = 0; reloc[j]; j++)
data = fixp->fx_frag->fr_literal + fixp->fx_where;
if (fixp->fx_where + fixp->fx_size
> fixp->fx_frag->fr_fix + fixp->fx_frag->fr_offset)
- abort ();
+ as_bad_where (fixp->fx_file, fixp->fx_line,
+ _("internal error: fixup not contained within frag"));
for (j = 0; reloc[j]; j++)
{
s = bfd_install_relocation (stdoutput, reloc[j],
break;
case bfd_reloc_overflow:
as_bad_where (fixp->fx_file, fixp->fx_line,
- "relocation overflow");
+ _("relocation overflow"));
break;
default:
- as_fatal ("%s:%u: bad return from bfd_perform_relocation",
+ as_fatal (_("%s:%u: bad return from bfd_install_relocation"),
fixp->fx_file, fixp->fx_line);
}
}
if (x == false)
{
bfd_perror (stdoutput->filename);
- as_perror ("FATAL: Can't write %s", stdoutput->filename);
+ as_perror (_("FATAL: Can't write %s"), stdoutput->filename);
exit (EXIT_FAILURE);
}
offset += f->fr_fix;
count = f->fr_offset;
assert (count >= 0);
if (fill_size && count)
-#ifdef BFD_FAST_SECTION_FILL
{
char buf[256];
- if (fill_size > sizeof(buf)) {
- /* Do it the old way. Can this ever happen? */
- while (count--)
- {
- x = bfd_set_section_contents (stdoutput, sec,
- fill_literal, (file_ptr) offset,
- (bfd_size_type) fill_size);
- if (x == false)
- {
- bfd_perror (stdoutput->filename);
- as_perror ("FATAL: Can't write %s", stdoutput->filename);
- exit (EXIT_FAILURE);
- }
- offset += fill_size;
- }
- }
- else {
- /* Build a buffer full of fill objects and output it as
- * often as necessary. This saves on the overhead of potentially
- * lots of bfd_set_section_contents calls.
- */
- int n_per_buf, i;
- if (fill_size == 1)
- {
- n_per_buf = sizeof (buf);
- memset (buf, *fill_literal, n_per_buf);
- }
- else
- {
- char *bufp;
- n_per_buf = sizeof(buf)/fill_size;
- for (i = n_per_buf, bufp = buf; i; i--, bufp += fill_size)
- memcpy(bufp, fill_literal, fill_size);
- }
- for (; count > 0; count -= n_per_buf)
- {
- n_per_buf = n_per_buf > count ? count : n_per_buf;
- x = bfd_set_section_contents (stdoutput, sec,
- buf, (file_ptr) offset,
- (bfd_size_type) n_per_buf * fill_size);
- assert (x == true);
- offset += n_per_buf * fill_size;
- }
- }
+ if (fill_size > sizeof(buf))
+ {
+ /* Do it the old way. Can this ever happen? */
+ while (count--)
+ {
+ x = bfd_set_section_contents (stdoutput, sec,
+ fill_literal,
+ (file_ptr) offset,
+ (bfd_size_type) fill_size);
+ if (x == false)
+ {
+ bfd_perror (stdoutput->filename);
+ as_perror (_("FATAL: Can't write %s"), stdoutput->filename);
+ exit (EXIT_FAILURE);
+ }
+ offset += fill_size;
+ }
+ }
+ else
+ {
+ /* Build a buffer full of fill objects and output it as
+ often as necessary. This saves on the overhead of
+ potentially lots of bfd_set_section_contents calls. */
+ int n_per_buf, i;
+ if (fill_size == 1)
+ {
+ n_per_buf = sizeof (buf);
+ memset (buf, *fill_literal, n_per_buf);
+ }
+ else
+ {
+ char *bufp;
+ n_per_buf = sizeof(buf)/fill_size;
+ for (i = n_per_buf, bufp = buf; i; i--, bufp += fill_size)
+ memcpy(bufp, fill_literal, fill_size);
+ }
+ for (; count > 0; count -= n_per_buf)
+ {
+ n_per_buf = n_per_buf > count ? count : n_per_buf;
+ x = bfd_set_section_contents (stdoutput, sec,
+ buf, (file_ptr) offset,
+ (bfd_size_type) n_per_buf * fill_size);
+ if (x != true)
+ as_fatal (_("Cannot write to output file."));
+ offset += n_per_buf * fill_size;
+ }
+ }
}
-#else
- while (count--)
- {
- x = bfd_set_section_contents (stdoutput, sec,
- fill_literal, (file_ptr) offset,
- (bfd_size_type) fill_size);
- assert (x == true);
- offset += fill_size;
- }
-#endif
}
}
#endif
}
#endif
-void
+/* Finish the subsegments. After every sub-segment, we fake an
+ ".align ...". This conforms to BSD4.2 brane-damage. We then fake
+ ".fill 0" because that is the kind of frag that requires least
+ thought. ".align" frags like to have a following frag since that
+ makes calculating their intended length trivial. */
+
+#ifndef SUB_SEGMENT_ALIGN
+#ifdef BFD_ASSEMBLER
+#define SUB_SEGMENT_ALIGN(SEG) (0)
+#else
+#define SUB_SEGMENT_ALIGN(SEG) (2)
+#endif
+#endif
+
+void
+subsegs_finish ()
+{
+ struct frchain *frchainP;
+
+ for (frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next)
+ {
+ subseg_set (frchainP->frch_seg, frchainP->frch_subseg);
+ frag_align (SUB_SEGMENT_ALIGN (now_seg), NOP_OPCODE, 0);
+
+ /* frag_align will have left a new frag.
+ Use this last frag for an empty ".fill".
+
+ For this segment ...
+ Create a last frag. Do not leave a "being filled in frag". */
+
+ frag_wane (frag_now);
+ frag_now->fr_fix = 0;
+ know (frag_now->fr_next == NULL);
+ }
+}
+
+/* Write the object file. */
+
+void
write_object_file ()
{
- struct frchain *frchainP; /* Track along all frchains. */
#if ! defined (BFD_ASSEMBLER) || ! defined (WORKING_DOT_WORD)
fragS *fragP; /* Track along all frags. */
#endif
if (flag_always_generate_output)
{
if (n_warns || n_errs)
- as_warn ("%d error%s, %d warning%s, generating bad object file.\n",
+ as_warn (_("%d error%s, %d warning%s, generating bad object file.\n"),
n_errs, n_errs == 1 ? "" : "s",
n_warns, n_warns == 1 ? "" : "s");
}
else
{
if (n_errs)
- as_fatal ("%d error%s, %d warning%s, no object file generated.\n",
+ as_fatal (_("%d error%s, %d warning%s, no object file generated.\n"),
n_errs, n_errs == 1 ? "" : "s",
n_warns, n_warns == 1 ? "" : "s");
}
vms_check_for_main ();
#endif /* OBJ_VMS */
- /* After every sub-segment, we fake an ".align ...". This conforms to
- BSD4.2 brane-damage. We then fake ".fill 0" because that is the kind of
- frag that requires least thought. ".align" frags like to have a
- following frag since that makes calculating their intended length
- trivial.
-
- @@ Is this really necessary?? */
-#ifndef SUB_SEGMENT_ALIGN
-#ifdef BFD_ASSEMBLER
-#define SUB_SEGMENT_ALIGN(SEG) (0)
-#else
-#define SUB_SEGMENT_ALIGN(SEG) (2)
-#endif
-#endif
- for (frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next)
- {
- subseg_set (frchainP->frch_seg, frchainP->frch_subseg);
- frag_align (SUB_SEGMENT_ALIGN (now_seg), NOP_OPCODE);
- /* frag_align will have left a new frag.
- Use this last frag for an empty ".fill".
-
- For this segment ...
- Create a last frag. Do not leave a "being filled in frag". */
- frag_wane (frag_now);
- frag_now->fr_fix = 0;
- know (frag_now->fr_next == NULL);
- }
-
/* From now on, we don't care about sub-segments. Build one frag chain
for each segment. Linked thru fr_next. */
for (fragP = text_frag_root; fragP; fragP = fragP->fr_next)
{
- cvt_frag_to_fill (&headers, fragP);
+ /* At this point we have linked all the frags into a single
+ chain. However, cvt_frag_to_fill may call md_convert_frag
+ which may call fix_new. We need to ensure that fix_new adds
+ the fixup to the right section. */
+ if (fragP == data_frag_root)
+ subseg_change (SEG_DATA, 0);
+
+ cvt_frag_to_fill (&headers, SEG_TEXT, fragP);
/* Some assert macros don't work with # directives mixed in. */
#ifndef NDEBUG
{
expressionS exp;
+ subseg_change (lie->seg, lie->subseg);
exp.X_op = O_subtract;
exp.X_add_symbol = lie->add;
exp.X_op_symbol = lie->sub;
#else
fix_new_exp (lie->frag,
lie->word_goes_here - lie->frag->fr_literal,
- 2, &exp, 0, BFD_RELOC_NONE);
+ 2, &exp, 0, BFD_RELOC_16);
#endif
#else
#if defined(TC_SPARC) || defined(TC_A29K) || defined(NEED_FX_R_TYPE)
addressT from_addr, to_addr;
int n, m;
+ subseg_change (lie->seg, lie->subseg);
fragP = lie->dispfrag;
/* Find out how many broken_words go here. */
register char *fill_literal;
register long fill_size;
+ PROGRESS (1);
know (fragP->fr_type == rs_fill);
append (&next_object_file_charP, fragP->fr_literal, (unsigned long) fragP->fr_fix);
fill_literal = fragP->fr_literal + fragP->fr_fix;
for (symp = symbol_rootP; symp; symp = symbol_next (symp))
if (!symp->sy_resolved)
- resolve_symbol_value (symp);
+ resolve_symbol_value (symp, 1);
}
+ PROGRESS (1);
+
+#ifdef tc_frob_file_before_adjust
+ tc_frob_file_before_adjust ();
+#endif
+#ifdef obj_frob_file_before_adjust
+ obj_frob_file_before_adjust ();
+#endif
+
bfd_map_over_sections (stdoutput, adjust_reloc_syms, (char *)0);
/* Set up symbol table, and write it out. */
for (symp = symbol_rootP; symp; symp = symbol_next (symp))
{
int punt = 0;
+ const char *name;
+
+ if (symp->sy_mri_common)
+ {
+ if (S_IS_EXTERNAL (symp))
+ as_bad (_("%s: global symbols not supported in common sections"),
+ S_GET_NAME (symp));
+ symbol_remove (symp, &symbol_rootP, &symbol_lastP);
+ continue;
+ }
+
+ name = S_GET_NAME (symp);
+ if (name)
+ {
+ const char *name2 = decode_local_label_name ((char *)S_GET_NAME (symp));
+ /* They only differ if `name' is a fb or dollar local
+ label name. */
+ if (name2 != name && ! S_IS_DEFINED (symp))
+ as_bad (_("local label %s is not defined"), name2);
+ }
/* Do it again, because adjust_reloc_syms might introduce
more symbols. They'll probably only be section symbols,
symp->sy_resolved = 1;
}
else
- resolve_symbol_value (symp);
+ resolve_symbol_value (symp, 1);
+ }
+
+ /* Skip symbols which were equated to undefined or common
+ symbols. */
+ if (symp->sy_value.X_op == O_symbol
+ && (! S_IS_DEFINED (symp) || S_IS_COMMON (symp)))
+ {
+ symbol_remove (symp, &symbol_rootP, &symbol_lastP);
+ continue;
}
/* So far, common symbols have been treated like undefined symbols.
/* Make sure we really got a value for the symbol. */
if (! symp->sy_resolved)
{
- as_bad ("can't resolve value for symbol \"%s\"",
+ as_bad (_("can't resolve value for symbol \"%s\""),
S_GET_NAME (symp));
symp->sy_resolved = 1;
}
}
}
+ PROGRESS (1);
+
/* Now do any format-specific adjustments to the symbol table, such
as adding file symbols. */
+#ifdef tc_adjust_symtab
+ tc_adjust_symtab ();
+#endif
#ifdef obj_adjust_symtab
obj_adjust_symtab ();
#endif
bfd_map_over_sections (stdoutput, write_relocs, (char *) 0);
+#ifdef tc_frob_file_after_relocs
+ tc_frob_file_after_relocs ();
+#endif
+#ifdef obj_frob_file_after_relocs
+ obj_frob_file_after_relocs ();
+#endif
+
bfd_map_over_sections (stdoutput, write_contents, (char *) 0);
#endif /* BFD_ASSEMBLER */
}
* these frag addresses may not be the same as final object-file addresses.
*/
-#ifndef md_relax_frag
+#ifdef TC_GENERIC_RELAX_TABLE
+
+static int is_dnrange PARAMS ((fragS *, fragS *));
/* Subroutines of relax_segment. */
-static int
+static int
is_dnrange (f1, f2)
- struct frag *f1;
- struct frag *f2;
+ fragS *f1;
+ fragS *f2;
{
for (; f1; f1 = f1->fr_next)
if (f1->fr_next == f2)
return 0;
}
-#endif /* ! defined (md_relax_frag) */
+/* Relax a fragment by scanning TC_GENERIC_RELAX_TABLE. */
+
+long
+relax_frag (fragP, stretch)
+ fragS *fragP;
+ long stretch;
+{
+ const relax_typeS *this_type;
+ const relax_typeS *start_type;
+ relax_substateT next_state;
+ relax_substateT this_state;
+ long aim, target, growth;
+ symbolS *symbolP = fragP->fr_symbol;
+ long offset = fragP->fr_offset;
+ /* Recompute was_address by undoing "+= stretch" done by relax_segment. */
+ unsigned long was_address = fragP->fr_address - stretch;
+ unsigned long address = fragP->fr_address;
+ const relax_typeS *table = TC_GENERIC_RELAX_TABLE;
+
+ this_state = fragP->fr_subtype;
+ start_type = this_type = table + this_state;
+ target = offset;
+
+ if (symbolP)
+ {
+#ifndef DIFF_EXPR_OK
+#if !defined (MANY_SEGMENTS) && !defined (BFD_ASSEMBLER)
+ know ((S_GET_SEGMENT (symbolP) == SEG_ABSOLUTE)
+ || (S_GET_SEGMENT (symbolP) == SEG_DATA)
+ || (S_GET_SEGMENT (symbolP) == SEG_BSS)
+ || (S_GET_SEGMENT (symbolP) == SEG_TEXT));
+#endif
+ know (symbolP->sy_frag);
+#endif
+ know (!(S_GET_SEGMENT (symbolP) == absolute_section)
+ || symbolP->sy_frag == &zero_address_frag);
+ target +=
+ S_GET_VALUE (symbolP)
+ + symbolP->sy_frag->fr_address;
+
+ /* If frag has yet to be reached on this pass,
+ assume it will move by STRETCH just as we did.
+ If this is not so, it will be because some frag
+ between grows, and that will force another pass.
+
+ Beware zero-length frags.
+
+ There should be a faster way to do this. */
+
+ if (symbolP->sy_frag->fr_address >= was_address
+ && is_dnrange (fragP, symbolP->sy_frag))
+ {
+ target += stretch;
+ }
+ }
+
+ aim = target - address - fragP->fr_fix;
+#ifdef TC_PCREL_ADJUST
+ /* Currently only the ns32k family needs this */
+ aim += TC_PCREL_ADJUST(fragP);
+/*#else*/
+ /* This machine doesn't want to use pcrel_adjust.
+ In that case, pcrel_adjust should be zero. */
+/* assert (fragP->fr_targ.ns32k.pcrel_adjust == 0);*/
+#endif
+#ifdef md_prepare_relax_scan /* formerly called M68K_AIM_KLUDGE */
+ md_prepare_relax_scan (fragP, address, aim, this_state, this_type);
+#endif
+
+ if (aim < 0)
+ {
+ /* Look backwards. */
+ for (next_state = this_type->rlx_more; next_state;)
+ if (aim >= this_type->rlx_backward)
+ next_state = 0;
+ else
+ {
+ /* Grow to next state. */
+ this_state = next_state;
+ this_type = table + this_state;
+ next_state = this_type->rlx_more;
+ }
+ }
+ else
+ {
+ /* Look forwards. */
+ for (next_state = this_type->rlx_more; next_state;)
+ if (aim <= this_type->rlx_forward)
+ next_state = 0;
+ else
+ {
+ /* Grow to next state. */
+ this_state = next_state;
+ this_type = table + this_state;
+ next_state = this_type->rlx_more;
+ }
+ }
+
+ growth = this_type->rlx_length - start_type->rlx_length;
+ if (growth != 0)
+ fragP->fr_subtype = this_state;
+ return growth;
+}
+
+#endif /* defined (TC_GENERIC_RELAX_TABLE) */
/* Relax_align. Advance location counter to next address that has 'alignment'
lowest order bits all 0s, return size of adjustment made. */
mask = ~((~0) << alignment);
new_address = (address + mask) & (~mask);
+#ifdef LINKER_RELAXING_SHRINKS_ONLY
if (linkrelax)
/* We must provide lots of padding, so the linker can discard it
when needed. The linker will not add extra space, ever. */
new_address += (1 << alignment);
+#endif
return (new_address - address);
}
-void
+void
relax_segment (segment_frag_root, segment)
struct frag *segment_frag_root;
segT segment;
case rs_align:
case rs_align_code:
{
- int offset = relax_align (address, (int) fragP->fr_offset);
+ addressT offset = relax_align (address, (int) fragP->fr_offset);
+
+ if (fragP->fr_subtype != 0 && offset > fragP->fr_subtype)
+ offset = 0;
+
if (offset % fragP->fr_var != 0)
{
- as_bad ("alignment padding (%d bytes) not a multiple of %ld",
- offset, (long) fragP->fr_var);
+ as_bad (_("alignment padding (%lu bytes) not a multiple of %ld"),
+ (unsigned long) offset, (long) fragP->fr_var);
offset -= (offset % fragP->fr_var);
}
+
address += offset;
}
break;
break;
#endif
+ case rs_leb128:
+ /* Initial guess is always 1; doing otherwise can result in
+ stable solutions that are larger than the minimum. */
+ address += fragP->fr_offset = 1;
+ break;
+
+ case rs_cfa:
+ address += eh_frame_estimate_size_before_relax (fragP);
+ break;
+
default:
BAD_CASE (fragP->fr_type);
break;
for (fragP = segment_frag_root; fragP; fragP = fragP->fr_next)
{
long growth = 0;
- unsigned long was_address;
- long offset;
+ addressT was_address;
+ offsetT offset;
symbolS *symbolP;
- long target;
- long after;
was_address = fragP->fr_address;
address = fragP->fr_address += stretch;
{
char buf[50];
sprint_value (buf, (addressT) lie->addnum);
- as_warn (".word %s-%s+%s didn't fit",
+ as_warn (_(".word %s-%s+%s didn't fit"),
S_GET_NAME (lie->add),
S_GET_NAME (lie->sub),
buf);
#endif
case rs_align:
case rs_align_code:
- growth = (relax_align ((relax_addressT) (address
- + fragP->fr_fix),
- (int) offset)
- - relax_align ((relax_addressT) (was_address
- + fragP->fr_fix),
- (int) offset));
+ {
+ addressT oldoff, newoff;
+
+ oldoff = relax_align (was_address + fragP->fr_fix,
+ (int) offset);
+ newoff = relax_align (address + fragP->fr_fix,
+ (int) offset);
+
+ if (fragP->fr_subtype != 0)
+ {
+ if (oldoff > fragP->fr_subtype)
+ oldoff = 0;
+ if (newoff > fragP->fr_subtype)
+ newoff = 0;
+ }
+
+ growth = newoff - oldoff;
+ }
break;
case rs_org:
- target = offset;
+ {
+ long target = offset;
+ long after;
- if (symbolP)
- {
+ if (symbolP)
+ {
#if !defined (MANY_SEGMENTS) && !defined (BFD_ASSEMBLER)
- know ((S_GET_SEGMENT (symbolP) == SEG_ABSOLUTE)
- || (S_GET_SEGMENT (symbolP) == SEG_DATA)
- || (S_GET_SEGMENT (symbolP) == SEG_TEXT)
- || S_GET_SEGMENT (symbolP) == SEG_BSS);
- know (symbolP->sy_frag);
- know (!(S_GET_SEGMENT (symbolP) == SEG_ABSOLUTE)
- || (symbolP->sy_frag == &zero_address_frag));
-#endif
- target += S_GET_VALUE (symbolP)
- + symbolP->sy_frag->fr_address;
- } /* if we have a symbol */
-
- know (fragP->fr_next);
- after = fragP->fr_next->fr_address;
- growth = ((target - after) > 0) ? (target - after) : 0;
- /* Growth may be negative, but variable part of frag
- cannot have fewer than 0 chars. That is, we can't
- .org backwards. */
-
- growth -= stretch; /* This is an absolute growth factor */
- break;
+ know ((S_GET_SEGMENT (symbolP) == SEG_ABSOLUTE)
+ || (S_GET_SEGMENT (symbolP) == SEG_DATA)
+ || (S_GET_SEGMENT (symbolP) == SEG_TEXT)
+ || S_GET_SEGMENT (symbolP) == SEG_BSS);
+ know (symbolP->sy_frag);
+ know (!(S_GET_SEGMENT (symbolP) == SEG_ABSOLUTE)
+ || (symbolP->sy_frag == &zero_address_frag));
+#endif
+ target += S_GET_VALUE (symbolP)
+ + symbolP->sy_frag->fr_address;
+ } /* if we have a symbol */
+
+ know (fragP->fr_next);
+ after = fragP->fr_next->fr_address;
+ growth = target - after;
+ if (growth < 0)
+ {
+ /* Growth may be negative, but variable part of frag
+ cannot have fewer than 0 chars. That is, we can't
+ .org backwards. */
+ as_bad (_("attempt to .org backwards ignored"));
+ growth = 0;
+ }
+
+ growth -= stretch; /* This is an absolute growth factor */
+ break;
+ }
case rs_space:
if (symbolP)
{
growth = S_GET_VALUE (symbolP);
- if (symbolP->sy_frag != &zero_address_frag)
- as_bad (".space specifies non-absolute value");
+ if (symbolP->sy_frag != &zero_address_frag
+ || S_IS_COMMON (symbolP)
+ || ! S_IS_DEFINED (symbolP))
+ as_bad_where (fragP->fr_file, fragP->fr_line,
+ _(".space specifies non-absolute value"));
fragP->fr_symbol = 0;
if (growth < 0)
{
- as_warn (".space or .fill with negative value, ignored");
+ as_warn (_(".space or .fill with negative value, ignored"));
growth = 0;
}
}
#ifdef md_relax_frag
growth = md_relax_frag (fragP, stretch);
#else
+#ifdef TC_GENERIC_RELAX_TABLE
/* The default way to relax a frag is to look through
- md_relax_table. */
- {
- const relax_typeS *this_type;
- const relax_typeS *start_type;
- relax_substateT next_state;
- relax_substateT this_state;
- long aim;
-
- this_state = fragP->fr_subtype;
- start_type = this_type = md_relax_table + this_state;
- target = offset;
-
- if (symbolP)
- {
-#ifndef DIFF_EXPR_OK
-#if !defined (MANY_SEGMENTS) && !defined (BFD_ASSEMBLER)
- know ((S_GET_SEGMENT (symbolP) == SEG_ABSOLUTE)
- || (S_GET_SEGMENT (symbolP) == SEG_DATA)
- || (S_GET_SEGMENT (symbolP) == SEG_BSS)
- || (S_GET_SEGMENT (symbolP) == SEG_TEXT));
-#endif
- know (symbolP->sy_frag);
-#endif
- know (!(S_GET_SEGMENT (symbolP) == absolute_section)
- || symbolP->sy_frag == &zero_address_frag);
- target +=
- S_GET_VALUE (symbolP)
- + symbolP->sy_frag->fr_address;
-
- /* If frag has yet to be reached on this pass,
- assume it will move by STRETCH just as we did.
- If this is not so, it will be because some frag
- between grows, and that will force another pass.
-
- Beware zero-length frags.
-
- There should be a faster way to do this. */
-
- if (symbolP->sy_frag->fr_address >= was_address
- && is_dnrange (fragP, symbolP->sy_frag))
- {
- target += stretch;
- }
- }
-
- aim = target - address - fragP->fr_fix;
-#ifdef TC_PCREL_ADJUST
- /* Currently only the ns32k family needs this */
- aim += TC_PCREL_ADJUST(fragP);
-#else
- /* This machine doesn't want to use pcrel_adjust.
- In that case, pcrel_adjust should be zero. */
- assert (fragP->fr_pcrel_adjust == 0);
+ TC_GENERIC_RELAX_TABLE. */
+ growth = relax_frag (fragP, stretch);
+#endif /* TC_GENERIC_RELAX_TABLE */
#endif
+ break;
- if (aim < 0)
- {
- /* Look backwards. */
- for (next_state = this_type->rlx_more; next_state;)
- if (aim >= this_type->rlx_backward)
- next_state = 0;
- else
- {
- /* Grow to next state. */
- this_state = next_state;
- this_type = md_relax_table + this_state;
- next_state = this_type->rlx_more;
- }
- }
- else
- {
-#ifdef M68K_AIM_KLUDGE
- M68K_AIM_KLUDGE (aim, this_state, this_type);
-#endif
- /* Look forwards. */
- for (next_state = this_type->rlx_more; next_state;)
- if (aim <= this_type->rlx_forward)
- next_state = 0;
- else
- {
- /* Grow to next state. */
- this_state = next_state;
- this_type = md_relax_table + this_state;
- next_state = this_type->rlx_more;
- }
- }
+ case rs_leb128:
+ {
+ valueT value;
+ int size;
- growth = this_type->rlx_length - start_type->rlx_length;
- if (growth != 0)
- fragP->fr_subtype = this_state;
+ value = resolve_symbol_value (fragP->fr_symbol, 0);
+ size = sizeof_leb128 (value, fragP->fr_subtype);
+ growth = size - fragP->fr_offset;
+ fragP->fr_offset = size;
}
-#endif
+ break;
+
+ case rs_cfa:
+ growth = eh_frame_relax_frag (fragP);
break;
default:
int pcrel, plt;
fragS *fragP;
segT add_symbol_segment = absolute_section;
-
+
/* If the linker is doing the relaxing, we must not do any fixups.
Well, strictly speaking that's not true -- we could do any that are
pcrel = fixP->fx_pcrel;
plt = fixP->fx_plt;
+ if (add_symbolP != NULL
+ && add_symbolP->sy_mri_common)
+ {
+ know (add_symbolP->sy_value.X_op == O_symbol);
+ add_number += S_GET_VALUE (add_symbolP);
+ fixP->fx_offset = add_number;
+ add_symbolP = fixP->fx_addsy = add_symbolP->sy_value.X_add_symbol;
+ }
+
if (add_symbolP)
add_symbol_segment = S_GET_SEGMENT (add_symbolP);
-
+
if (sub_symbolP)
{
- if (!add_symbolP)
+ resolve_symbol_value (sub_symbolP, 1);
+ if (add_symbolP == NULL || add_symbol_segment == absolute_section)
{
- /* Its just -sym */
+ if (add_symbolP != NULL)
+ {
+ add_number += S_GET_VALUE (add_symbolP);
+ add_symbolP = NULL;
+ fixP->fx_addsy = NULL;
+ }
+
+ /* It's just -sym */
if (S_GET_SEGMENT (sub_symbolP) == absolute_section)
- add_number -= S_GET_VALUE (sub_symbolP);
+ {
+ add_number -= S_GET_VALUE (sub_symbolP);
+ fixP->fx_subsy = NULL;
+ }
else if (pcrel
&& S_GET_SEGMENT (sub_symbolP) == this_segment_type)
{
else
bad_sub_reloc:
as_bad_where (fixP->fx_file, fixP->fx_line,
- "Negative of non-absolute symbol %s",
+ _("Negative of non-absolute symbol %s"),
S_GET_NAME (sub_symbolP));
}
- else if ((S_GET_SEGMENT (sub_symbolP) == add_symbol_segment)
- && (SEG_NORMAL (add_symbol_segment)
- || (add_symbol_segment == absolute_section)))
+ else if (S_GET_SEGMENT (sub_symbolP) == add_symbol_segment
+ && SEG_NORMAL (add_symbol_segment))
{
/* Difference of 2 symbols from same segment.
Can't make difference of 2 undefineds: 'value' means
as the target of a call instruction. */
if (fixP->fx_tcbit)
as_bad_where (fixP->fx_file, fixP->fx_line,
- "callj to difference of 2 symbols");
+ _("callj to difference of 2 symbols"));
#endif /* TC_I960 */
add_number += S_GET_VALUE (add_symbolP) -
S_GET_VALUE (sub_symbolP);
add_symbolP = NULL;
+ pcrel = 0; /* No further pcrel processing. */
/* Let the target machine make the final determination
as to whether or not a relocation will be needed to
handle this fixup. */
- if (!TC_FORCE_RELOCATION (fixP))
+ if (!TC_FORCE_RELOCATION_SECTION (fixP, this_segment_type))
{
+ fixP->fx_pcrel = 0;
fixP->fx_addsy = NULL;
+ fixP->fx_subsy = NULL;
}
}
else
)
{
/* Make it pc-relative. */
- add_number += (md_pcrel_from (fixP)
+ add_number += (MD_PCREL_FROM_SECTION (fixP, this_segment_type)
- S_GET_VALUE (sub_symbolP));
pcrel = 1;
fixP->fx_pcrel = 1;
fixP->fx_subsy = 0;
}
#endif
+#ifdef UNDEFINED_DIFFERENCE_OK
+ /* The PA needs this for PIC code generation. We basically
+ don't want to do anything if we have the difference of two
+ symbols at this point. */
+ else if (1)
+ {
+ /* Leave it alone. */
+ }
+#endif
#ifdef BFD_ASSEMBLER
else if (fixP->fx_r_type == BFD_RELOC_GPREL32
|| fixP->fx_r_type == BFD_RELOC_GPREL16)
char buf[50];
sprint_value (buf, fragP->fr_address + where);
as_bad_where (fixP->fx_file, fixP->fx_line,
- "Can't emit reloc {- %s-seg symbol \"%s\"} @ file address %s.",
+ _("Subtraction of two symbols in different sections \"%s\" {%s section} - \"%s\" {%s section} at file address %s."),
+ S_GET_NAME (add_symbolP),
+ segment_name (S_GET_SEGMENT (add_symbolP)),
+ S_GET_NAME (sub_symbolP),
segment_name (S_GET_SEGMENT (sub_symbolP)),
- S_GET_NAME (sub_symbolP), buf);
+ buf);
}
}
}
if (add_symbolP)
{
if (add_symbol_segment == this_segment_type && pcrel && !plt
- && TC_RELOC_RTSYM_LOC_FIXUP (fixP->fx_r_type))
+ && TC_RELOC_RTSYM_LOC_FIXUP (fixP))
{
/*
* This fixup was made when the symbol's segment was
#endif /* TC_I960 */
add_number += S_GET_VALUE (add_symbolP);
- add_number -= md_pcrel_from (fixP);
+ add_number -= MD_PCREL_FROM_SECTION (fixP, this_segment_type);
pcrel = 0; /* Lie. Don't want further pcrel processing. */
-
+
/* Let the target machine make the final determination
as to whether or not a relocation will be needed to
handle this fixup. */
}
else
{
- if (add_symbol_segment == absolute_section)
+ if (add_symbol_segment == absolute_section
+ && ! pcrel)
{
#ifdef TC_I960
/* See comment about reloc_callj() above. */
/* Let the target machine make the final determination
as to whether or not a relocation will be needed to
handle this fixup. */
+
if (!TC_FORCE_RELOCATION (fixP))
{
fixP->fx_addsy = NULL;
* relocation.
*/
as_bad_where (fixP->fx_file, fixP->fx_line,
- "can't use COBR format with external label");
+ _("can't use COBR format with external label"));
fixP->fx_addsy = NULL;
fixP->fx_done = 1;
continue;
} /* COBR */
#endif /* TC_I960 */
-
+
#ifdef OBJ_COFF
#ifdef TE_I386AIX
if (S_IS_COMMON (add_symbolP))
else
{
seg_reloc_count++;
-#if !defined (TC_I386) || !(defined (OBJ_ELF) || defined (OBJ_COFF))
+#if !(defined (TC_V850) && defined (OBJ_ELF))
+#if !(defined (TC_M68K) && defined (OBJ_ELF))
+#if !defined (TC_I386) || !(defined (OBJ_ELF) || defined (OBJ_COFF)) || defined (TE_PE)
add_number += S_GET_VALUE (add_symbolP);
+#endif
+#endif
#endif
}
}
if (pcrel)
{
- add_number -= md_pcrel_from (fixP);
+ add_number -= MD_PCREL_FROM_SECTION (fixP, this_segment_type);
if (add_symbolP == 0)
{
#ifndef BFD_ASSEMBLER
}
}
- if (!fixP->fx_bit_fixP && size > 0)
+ if (!fixP->fx_bit_fixP && !fixP->fx_no_overflow && size > 0)
{
- valueT mask = 0;
- if (size < sizeof (mask))
+ if ((size_t) size < sizeof (valueT))
{
+ valueT mask, hibit;
+
/* set all bits to one */
+ mask = 0;
mask--;
/* Technically, combining these produces an undefined result
if size is sizeof (valueT), though I think these two
the host architecture. */
mask <<= size * 4;
mask <<= size * 4;
- if ((add_number & mask) != 0
- && (add_number & mask) != mask)
+ hibit = (valueT) 1 << (size * 8 - 1);
+ if (((add_number & mask) != 0
+ || (fixP->fx_signed
+ && (add_number & hibit) != 0))
+ && ((add_number & mask) != mask
+ || (add_number & hibit) == 0))
{
char buf[50], buf2[50];
sprint_value (buf, fragP->fr_address + where);
else
sprintf (buf2, "%ld", (long) add_number);
as_bad_where (fixP->fx_file, fixP->fx_line,
- "Value of %s too large for field of %d bytes at %s",
+ _("Value of %s too large for field of %d bytes at %s"),
buf2, size, buf);
} /* generic error checking */
}
&& size == 2
&& add_number > 0x7fff)
as_bad_where (fixP->fx_file, fixP->fx_line,
- "Signed .word overflow; switch may be too large; %ld at 0x%lx",
+ _("Signed .word overflow; switch may be too large; %ld at 0x%lx"),
(long) add_number,
(unsigned long) (fragP->fr_address + where));
#endif
valueT val;
int n;
{
- if (n > sizeof (val)|| n <= 0)
+ if ((size_t) n > sizeof (val) || n <= 0)
abort ();
while (n--)
{
valueT val;
int n;
{
- if (n > sizeof (val) || n <= 0)
+ if ((size_t) n > sizeof (val) || n <= 0)
abort ();
while (n--)
{
}
}
+void
+write_print_statistics (file)
+ FILE *file;
+{
+ fprintf (stderr, "fixups: %d\n", n_fixups);
+}
+
/* for debugging */
extern int indent_level;
-extern void print_symbol_value_1 ();
void
print_fixup (fixp)
fprintf (stderr, ">");
}
fprintf (stderr, "\n");
+#ifdef TC_FIX_DATA_PRINT
+ TC_FIX_DATA_PRINT (stderr, fixp);
+#endif
}
/* end of write.c */