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... */
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()
/* 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;
#if !defined (BFD) && !defined (BFD_ASSEMBLER)
-void
+static void
remove_subsegs (head, seg, root, last)
frchainS *head;
int seg;
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_machine_dependent:
#ifdef BFD_ASSEMBLER
md_convert_frag (stdoutput, sec, fragP);
symbols, though, since they are not in the regular symbol
table. */
if (sym != NULL && ! sym->sy_resolved)
- resolve_symbol_value (sym);
+ resolve_symbol_value (sym, 1);
if (fixp->fx_subsy != NULL && ! fixp->fx_subsy->sy_resolved)
- resolve_symbol_value (fixp->fx_subsy);
+ resolve_symbol_value (fixp->fx_subsy, 1);
/* If this symbol is equated to an undefined symbol, convert
the fixup to being against that symbol. */
#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;
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;
+ {
+ 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);
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)
"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);
}
}
}
#endif
+/* 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
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)
{
+ /* 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. */
for (symp = symbol_rootP; symp; symp = symbol_next (symp))
if (!symp->sy_resolved)
- resolve_symbol_value (symp);
+ resolve_symbol_value (symp, 1);
}
PROGRESS (1);
symp->sy_resolved = 1;
}
else
- resolve_symbol_value (symp);
+ resolve_symbol_value (symp, 1);
}
/* Skip symbols which were equated to undefined or common
* 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
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;
}
+/* 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) */
-#endif /* ! defined (md_relax_frag) */
/* Relax_align. Advance location counter to next address that has 'alignment'
lowest order bits all 0s, return size of adjustment made. */
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;
+
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;
#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)
+ + 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);
+ 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;
default:
if (sub_symbolP)
{
- resolve_symbol_value (sub_symbolP);
+ resolve_symbol_value (sub_symbolP, 1);
if (add_symbolP == NULL || add_symbol_segment == absolute_section)
{
if (add_symbolP != NULL)
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))
+#if !defined (TC_I386) || !(defined (OBJ_ELF) || defined (OBJ_COFF)) || defined (TE_PE)
add_number += S_GET_VALUE (add_symbolP);
-/* start-sanitize-v850 */
#endif
-/* end-sanitize-v850 */
#endif
#endif
}
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;
+ hibit = (valueT) 1 << (size * 8 - 1);
if (((add_number & mask) != 0
|| (fixP->fx_signed
- && (add_number & (mask >> 1)) != 0))
+ && (add_number & hibit) != 0))
&& ((add_number & mask) != mask
- || (fixP->fx_signed
- && (add_number & (mask >> 1)) == 0)))
+ || (add_number & hibit) == 0))
{
char buf[50], buf2[50];
sprint_value (buf, fragP->fr_address + where);
/* for debugging */
extern int indent_level;
-extern void print_symbol_value_1 ();
void
print_fixup (fixp)