/* write.c - emit .o file
- Copyright (C) 1986, 87, 90, 91, 92, 93, 94, 1995
+ Copyright (C) 1986, 87, 90, 91, 92, 93, 94, 95, 96, 97, 98, 1999
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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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;
+
+#ifdef USING_CGEN
+ fixP->fx_cgen.insn = NULL;
+ fixP->fx_cgen.opinfo = 0;
+#endif
-#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);
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])
static void
renumber_sections (abfd, sec, countparg)
- bfd *abfd;
+ bfd *abfd ATTRIBUTE_UNUSED;
asection *sec;
PTR countparg;
{
{
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;
}
static void
chain_frchains_together (abfd, section, xxx)
- bfd *abfd; /* unused */
+ bfd *abfd ATTRIBUTE_UNUSED;
segT section;
- PTR xxx; /* unused */
+ PTR xxx ATTRIBUTE_UNUSED;
{
segment_info_type *info;
#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_fix) / fragP->fr_var;
if (fragP->fr_offset < 0)
{
- as_bad ("attempt to .org/.space backwards? (%ld)",
- (long) fragP->fr_offset);
+ as_bad_where (fragP->fr_file, fragP->fr_line,
+ _("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".
relax_and_size_seg (abfd, sec, xxx)
bfd *abfd;
asection *sec;
- PTR xxx;
+ PTR xxx ATTRIBUTE_UNUSED;
{
flagword flags;
fragS *fragp;
int x;
valueT size, newsize;
+ subseg_change (sec, 0);
+
flags = bfd_get_section_flags (abfd, sec);
seginfo = seg_info (sec);
#ifdef DEBUG2
static void
dump_section_relocs (abfd, sec, stream_)
- bfd *abfd;
+ bfd *abfd ATTRIBUTE_UNUSED;
asection *sec;
char *stream_;
{
while (fixp)
{
symbolS *s = fixp->fx_addsy;
- if (s)
+
+ fprintf (stream, " %08lx: type %d ", (unsigned long) fixp,
+ (int) fixp->fx_r_type);
+ if (s == NULL)
+ fprintf (stream, "no sym\n");
+ else
{
- fprintf (stream, " %08x: %s(%s", fixp, S_GET_NAME (s),
- s->bsym->section->name);
- if (s->bsym->flags & BSF_SECTION_SYM)
- {
- fprintf (stream, " section sym");
- if (S_GET_VALUE (s))
- fprintf (stream, "+%x", S_GET_VALUE (s));
- }
- else
- fprintf (stream, "+%x", S_GET_VALUE (s));
- fprintf (stream, ")+%x\n", fixp->fx_offset);
+ print_symbol_value_1 (stream, s);
+ fprintf (stream, "\n");
}
- else
- fprintf (stream, " %08x: type %d no sym\n", fixp, fixp->fx_r_type);
fixp = fixp->fx_next;
}
}
#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
static void
adjust_reloc_syms (abfd, sec, xxx)
- bfd *abfd;
+ bfd *abfd ATTRIBUTE_UNUSED;
asection *sec;
- PTR xxx;
+ PTR xxx ATTRIBUTE_UNUSED;
{
segment_info_type *seginfo = seg_info (sec);
fixS *fixp;
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)
+ resolve_symbol_value (sym, 1);
+
+ if (fixp->fx_subsy != NULL)
+ 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 != NULL && symbol_equated_p (sym)
+ && (! S_IS_DEFINED (sym) || S_IS_COMMON (sym)))
+ {
+ fixp->fx_offset += symbol_get_value_expression (sym)->X_add_number;
+ sym = symbol_get_value_expression (sym)->X_add_symbol;
+ fixp->fx_addsy = sym;
+ }
+
+ if (sym != NULL && symbol_mri_common_p (sym))
+ {
+ /* These symbols are handled specially in fixup_segment. */
+ goto done;
+ }
+
+ symsec = S_GET_SEGMENT (sym);
+
+ if (symsec == NULL)
+ abort ();
+
+ 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))
+ {
+ symbol_mark_used_in_reloc (fixp->fx_addsy);
+#ifdef UNDEFINED_DIFFERENCE_OK
+ if (fixp->fx_subsy != NULL)
+ symbol_mark_used_in_reloc (fixp->fx_subsy);
+#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;
+ symbol_mark_used_in_reloc (fixp->fx_addsy);
+#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)
+ symbol_mark_used_in_reloc (fixp->fx_subsy);
+#endif
goto done;
}
+ /* Don't try to reduce relocs which refer to non-local symbols
+ in .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 && ! S_IS_LOCAL (sym))
+ {
+ 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)
+ {
+ symbol_mark_used_in_reloc (fixp->fx_addsy);
+#ifdef UNDEFINED_DIFFERENCE_OK
+ if (fixp->fx_subsy != NULL)
+ symbol_mark_used_in_reloc (fixp->fx_subsy);
+#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)
+ if (symbol_section_p (sym))
+ {
+ symbol_mark_used_in_reloc (fixp->fx_addsy);
+ goto done;
+ }
+
+#ifdef BFD_ASSEMBLER
+ /* We can never adjust a reloc against a weak symbol. If we
+ did, and the weak symbol was overridden by a real symbol
+ somewhere else, then our relocation would be pointing at
+ the wrong area of memory. */
+ if (S_IS_WEAK (sym))
{
- fixp->fx_addsy->sy_used_in_reloc = 1;
+ symbol_mark_used_in_reloc (fixp->fx_addsy);
goto done;
}
+#endif
/* Is there some other reason we can't adjust this one? (E.g.,
call/bal links in i960-bout symbols.) */
#ifdef obj_fix_adjustable
if (! obj_fix_adjustable (fixp))
{
- fixp->fx_addsy->sy_used_in_reloc = 1;
+ symbol_mark_used_in_reloc (fixp->fx_addsy);
goto done;
}
#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))
{
- fixp->fx_addsy->sy_used_in_reloc = 1;
+ symbol_mark_used_in_reloc (fixp->fx_addsy);
goto done;
}
#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->sy_used_in_reloc = 1;
+ fixp->fx_addsy = section_symbol (S_GET_SEGMENT (sym));
+ symbol_mark_used_in_reloc (fixp->fx_addsy);
+#ifdef DEBUG5
+ fprintf (stderr, "\nadjusted fixup:\n");
+ print_fixup (fixp);
+#endif
done:
;
write_relocs (abfd, sec, xxx)
bfd *abfd;
asection *sec;
- PTR xxx;
+ PTR xxx ATTRIBUTE_UNUSED;
{
segment_info_type *seginfo = seg_info (sec);
int i;
#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 (symbol_equated_p (sym)
+ && (! S_IS_DEFINED (sym) || S_IS_COMMON (sym)))
+ {
+ symbolS *n;
+
+ /* We must avoid looping, as that can occur with a badly
+ written program. */
+ n = symbol_get_value_expression (sym)->X_add_symbol;
+ if (n == sym)
+ break;
+ fixp->fx_offset += symbol_get_value_expression (sym)->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;
+ case bfd_reloc_outofrange:
+ as_bad_where (fixp->fx_file, fixp->fx_line, _("relocation out of range"));
break;
default:
- as_fatal ("%s:%u: bad return from bfd_perform_relocation",
- fixp->fx_file, fixp->fx_line);
+ as_fatal (_("%s:%u: bad return from bfd_install_relocation: %x"),
+ fixp->fx_file, fixp->fx_line, s);
}
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 (symbol_equated_p (sym)
+ && (! S_IS_DEFINED (sym) || S_IS_COMMON (sym)))
+ sym = symbol_get_value_expression (sym)->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);
}
}
(bfd_get_section_flags (abfd, sec)
& (flagword) ~SEC_RELOC));
+#ifdef SET_SECTION_RELOCS
+ SET_SECTION_RELOCS (sec, relocs, n);
+#endif
+
#ifdef DEBUG3
{
int i;
static void
write_contents (abfd, sec, xxx)
- bfd *abfd;
+ bfd *abfd ATTRIBUTE_UNUSED;
asection *sec;
- PTR xxx;
+ PTR xxx ATTRIBUTE_UNUSED;
{
segment_info_type *seginfo = seg_info (sec);
unsigned long offset = 0;
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);
- if (x != true)
- as_fatal ("Cannot write to output file.");
- 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);
- if (x != true)
- as_fatal ("Cannot write to output file.");
- offset += fill_size;
- }
-#endif
}
}
#endif
symp = symbol_rootP;
for (i = 0; i < nsyms; i++, symp = symbol_next (symp))
{
- asympp[i] = symp->bsym;
- symp->written = 1;
+ asympp[i] = symbol_get_bfdsym (symp);
+ symbol_mark_written (symp);
}
}
else
}
#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);
+
+ /* This now gets called even if we had errors. In that case,
+ any alignment is meaningless, and, moreover, will look weird
+ if we are generating a listing. */
+ frag_align (had_errors () ? 0 : SUB_SEGMENT_ALIGN (now_seg),
+ subseg_text_p (now_seg) ? NOP_OPCODE : 0,
+ 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. */
/* This is the offset from ??? to table_ptr+0 */
to_addr = table_addr - S_GET_VALUE (lie->sub);
#ifdef BFD_ASSEMBLER
- to_addr -= lie->sub->sy_frag->fr_address;
+ to_addr -= symbol_get_frag (lie->sub)->fr_address;
#endif
md_number_to_chars (lie->word_goes_here, to_addr, 2);
for (untruth = lie->next_broken_word; untruth && untruth->dispfrag == fragP; untruth = untruth->next_broken_word)
from_addr = table_addr;
to_addr = S_GET_VALUE (lie->add) + lie->addnum;
#ifdef BFD_ASSEMBLER
- to_addr += lie->add->sy_frag->fr_address;
+ to_addr += symbol_get_frag (lie->add)->fr_address;
#endif
md_create_long_jump (table_ptr, from_addr, to_addr, lie->dispfrag, lie->add);
table_ptr += md_long_jump_size;
symbolS *symp;
for (symp = symbol_rootP; symp; symp = symbol_next (symp))
- if (!symp->sy_resolved)
- resolve_symbol_value (symp);
+ resolve_symbol_value (symp, 1);
}
+ resolve_local_symbol_values ();
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. */
int punt = 0;
const char *name;
+ if (symbol_mri_common_p (symp))
+ {
+ 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)
{
/* 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);
+ 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,
but they'll still need to have the values computed. */
- if (! symp->sy_resolved)
+ resolve_symbol_value (symp, 1);
+
+ /* Skip symbols which were equated to undefined or common
+ symbols. */
+ if (symbol_equated_p (symp)
+ && (! S_IS_DEFINED (symp) || S_IS_COMMON (symp)))
{
- if (symp->sy_value.X_op == O_constant)
- {
- /* This is the normal case; skip the call. */
- S_SET_VALUE (symp,
- (S_GET_VALUE (symp)
- + symp->sy_frag->fr_address));
- symp->sy_resolved = 1;
- }
- else
- resolve_symbol_value (symp);
+ symbol_remove (symp, &symbol_rootP, &symbol_lastP);
+ continue;
}
/* So far, common symbols have been treated like undefined symbols.
printf ("symbol `%s'\n\t@%x: value=%d flags=%x seg=%s\n",
S_GET_NAME (symp), symp,
S_GET_VALUE (symp),
- symp->bsym->flags,
- segment_name (symp->bsym->section));
+ symbol_get_bfdsym (symp)->flags,
+ segment_name (S_GET_SEGMENT (symp)));
#endif
#ifdef obj_frob_symbol
obj_frob_symbol (symp, punt);
#endif
#ifdef tc_frob_symbol
- if (! punt || symp->sy_used_in_reloc)
+ if (! punt || symbol_used_in_reloc_p (symp))
tc_frob_symbol (symp, punt);
#endif
and symbols that the frob_symbol macros told us to punt,
but we keep such symbols if they are used in relocs. */
if ((! EMIT_SECTION_SYMBOLS
- && (symp->bsym->flags & BSF_SECTION_SYM) != 0)
+ && symbol_section_p (symp))
/* Note that S_IS_EXTERN and S_IS_LOCAL are not always
opposites. Sometimes the former checks flags and the
latter examines the name... */
|| (!S_IS_EXTERN (symp)
&& (S_IS_LOCAL (symp) || punt)
- && ! symp->sy_used_in_reloc))
+ && ! symbol_used_in_reloc_p (symp)))
{
symbol_remove (symp, &symbol_rootP, &symbol_lastP);
/* After symbol_remove, symbol_next(symp) still returns
}
/* Make sure we really got a value for the symbol. */
- if (! symp->sy_resolved)
+ if (! symbol_resolved_p (symp))
{
- 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;
+ symbol_mark_resolved (symp);
}
/* Set the value into the BFD symbol. Up til now the value
has only been kept in the gas symbolS struct. */
- symp->bsym->value = S_GET_VALUE (symp);
+ symbol_get_bfdsym (symp)->value = S_GET_VALUE (symp);
}
}
/* 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) + symbol_get_frag (symbolP)->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 (symbol_get_frag (symbolP)->fr_address >= was_address
+ && is_dnrange (fragP, symbol_get_frag (symbolP)))
+ {
+ 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;
if (lie->added)
continue;
- offset = (lie->add->sy_frag->fr_address
+ offset = (symbol_get_frag (lie->add)->fr_address
+ S_GET_VALUE (lie->add)
+ lie->addnum
- - (lie->sub->sy_frag->fr_address
+ - (symbol_get_frag (lie->sub)->fr_address
+ S_GET_VALUE (lie->sub)));
if (offset <= -32768 || offset >= 32767)
{
{
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);
for (untruth = lie->next_broken_word;
untruth && untruth->dispfrag == lie->dispfrag;
untruth = untruth->next_broken_word)
- if ((untruth->add->sy_frag == lie->add->sy_frag)
- && S_GET_VALUE (untruth->add) == S_GET_VALUE (lie->add))
+ if ((symbol_get_frag (untruth->add)
+ == symbol_get_frag (lie->add))
+ && (S_GET_VALUE (untruth->add)
+ == S_GET_VALUE (lie->add)))
{
untruth->added = 2;
untruth->use_jump = lie;
#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;
- 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;
- }
+ 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)
+ + symbol_get_frag (symbolP)->fr_address);
+ } /* if we have a symbol */
- growth -= stretch; /* This is an absolute growth factor */
- break;
+ 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_where (fragP->fr_file, fragP->fr_line,
+ _("attempt to .org backwards ignored"));
+
+ /* We've issued an error message. Change the
+ frag to avoid cascading errors. */
+ fragP->fr_type = rs_align;
+ fragP->fr_subtype = 0;
+ fragP->fr_offset = 0;
+ fragP->fr_fix = after - address;
+ growth = stretch;
+ }
+
+ 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 (symbol_get_frag (symbolP) != &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;
}
}
#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;
- 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_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 = 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 = 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 /* TC_GENERIC_RELAX_TABLE */
-#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
for (; fixP; fixP = fixP->fx_next)
{
+
#ifdef DEBUG5
fprintf (stderr, "\nprocessing fixup:\n");
print_fixup (fixP);
#endif
+
fragP = fixP->fx_frag;
know (fragP);
where = fixP->fx_where;
pcrel = fixP->fx_pcrel;
plt = fixP->fx_plt;
+ if (add_symbolP != NULL
+ && symbol_mri_common_p (add_symbolP))
+ {
+ 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 =
+ symbol_get_value_expression (add_symbolP)->X_add_symbol;
+ }
+
if (add_symbolP)
add_symbol_segment = S_GET_SEGMENT (add_symbolP);
-
+
if (sub_symbolP)
{
- resolve_symbol_value (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);
/* 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);
}
}
}
#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_ARM) && defined (OBJ_ELF))
+#if !(defined (TC_I960) && 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
+#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
#else
fixP->fx_addsy = section_symbol (absolute_section);
#endif
- fixP->fx_addsy->sy_used_in_reloc = 1;
+ symbol_mark_used_in_reloc (fixP->fx_addsy);
++seg_reloc_count;
}
}
- if (!fixP->fx_bit_fixP && size > 0)
+ if (!fixP->fx_done)
+ {
+#ifdef MD_APPLY_FIX3
+ md_apply_fix3 (fixP, &add_number, this_segment_type);
+#else
+#ifdef BFD_ASSEMBLER
+ md_apply_fix (fixP, &add_number);
+#else
+ md_apply_fix (fixP, add_number);
+#endif
+#endif
+
+#ifndef TC_HANDLES_FX_DONE
+ /* If the tc-* files haven't been converted, assume it's handling
+ it the old way, where a null fx_addsy means that the fix has
+ been applied completely, and no further work is needed. */
+ if (fixP->fx_addsy == 0 && fixP->fx_pcrel == 0)
+ fixP->fx_done = 1;
+#endif
+ }
+
+ if (!fixP->fx_bit_fixP && !fixP->fx_no_overflow && size > 0)
{
- valueT mask = 0;
- if (size < sizeof (mask))
+ if ((size_t) size < sizeof (valueT))
{
- /* set all bits to one */
- mask--;
- /* Technically, combining these produces an undefined result
- if size is sizeof (valueT), though I think these two
- half-way operations should both be defined. And the
- compiler should be able to combine them if it's valid on
- the host architecture. */
- mask <<= size * 4;
- mask <<= size * 4;
- if ((add_number & mask) != 0
- && (add_number & mask) != mask)
+ valueT mask;
+
+ mask = 0;
+ mask--; /* set all bits to one */
+ mask <<= size * 8 - (fixP->fx_signed ? 1 : 0);
+ if ((add_number & mask) != 0 && (add_number & mask) != mask)
{
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
} /* not a bit fix */
- if (!fixP->fx_done)
- {
-#ifdef MD_APPLY_FIX3
- md_apply_fix3 (fixP, &add_number, this_segment_type);
-#else
-#ifdef BFD_ASSEMBLER
- md_apply_fix (fixP, &add_number);
-#else
- md_apply_fix (fixP, add_number);
-#endif
-#endif
-
-#ifndef TC_HANDLES_FX_DONE
- /* If the tc-* files haven't been converted, assume it's handling
- it the old way, where a null fx_addsy means that the fix has
- been applied completely, and no further work is needed. */
- if (fixP->fx_addsy == 0 && fixP->fx_pcrel == 0)
- fixP->fx_done = 1;
-#endif
- }
#ifdef TC_VALIDATE_FIX
- skip: ;
+ skip: ATTRIBUTE_UNUSED_LABEL
+ ;
#endif
#ifdef DEBUG5
fprintf (stderr, "result:\n");
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 (file, "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 */