/* 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, 1997
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,
{
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:
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))
bfd_set_section_alignment (stdoutput, seg, align);
{
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
+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
{
#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));
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
#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);
+ if (fixp->fx_subsy != NULL && ! fixp->fx_subsy->sy_resolved)
+ resolve_symbol_value (fixp->fx_subsy);
+
+ /* 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:
{
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,
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],
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
}
#endif
-void
+void
write_object_file ()
{
struct frchain *frchainP; /* Track along all frchains. */
for (fragP = text_frag_root; fragP; fragP = fragP->fr_next)
{
- cvt_frag_to_fill (&headers, fragP);
+ cvt_frag_to_fill (&headers, SEG_TEXT, fragP);
/* Some assert macros don't work with # directives mixed in. */
#ifndef NDEBUG
#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)
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 (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)
{
resolve_symbol_value (symp);
}
+ /* 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.
Put them in the common section now. */
if (S_IS_DEFINED (symp) == 0
/* 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
/* Subroutines of relax_segment. */
-static int
+static int
is_dnrange (f1, f2)
struct frag *f1;
struct frag *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_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;
unsigned long was_address;
long offset;
symbolS *symbolP;
- long target;
- long after;
was_address = fragP->fr_address;
address = fragP->fr_address += stretch;
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)
+ + symbolP->sy_frag->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 ("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)
{
#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);
-#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
- {
-#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;
- }
- }
-
- growth = this_type->rlx_length - start_type->rlx_length;
- if (growth != 0)
- fragP->fr_subtype = this_state;
- }
+ TC_GENERIC_RELAX_TABLE. */
+ growth = relax_frag (fragP, stretch);
#endif /* TC_GENERIC_RELAX_TABLE */
#endif
break;
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);
+ 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)
{
"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
/* 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)
#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;
continue;
} /* COBR */
#endif /* TC_I960 */
-
+
#ifdef OBJ_COFF
#ifdef TE_I386AIX
if (S_IS_COMMON (add_symbolP))
else
{
seg_reloc_count++;
+/* start-sanitize-v850 */
+#if !(defined (TC_V850) && defined (OBJ_ELF))
+/* end-sanitize-v850 */
+#if !(defined (TC_M68K) && defined (OBJ_ELF))
#if !defined (TC_I386) || !(defined (OBJ_ELF) || defined (OBJ_COFF))
add_number += S_GET_VALUE (add_symbolP);
+/* start-sanitize-v850 */
+#endif
+/* end-sanitize-v850 */
+#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 < 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);
}
}
+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 ();