#include "obstack.h"
#include "output-file.h"
+/* This looks like a good idea. Let's try turning it on always, for now. */
+#undef BFD_FAST_SECTION_FILL
+#define BFD_FAST_SECTION_FILL
+
/* The NOP_OPCODE is for the alignment fill value. Fill it with a nop
instruction so that the disassembler does not choke on it. */
#ifndef NOP_OPCODE
#endif
int symbol_table_frozen;
+void print_fixup PARAMS ((fixS *));
#ifdef BFD_ASSEMBLER
+static void renumber_sections PARAMS ((bfd *, asection *, PTR));
+
/* We generally attach relocs to frag chains. However, after we have
chained these all together into a segment, any relocs we add after
that must be attached to a segment. This will include relocs added
fixP->fx_subsy = sub_symbol;
fixP->fx_offset = offset;
fixP->fx_pcrel = pcrel;
+ fixP->fx_plt = 0;
#if defined(NEED_FX_R_TYPE) || defined (BFD_ASSEMBLER)
fixP->fx_r_type = r_type;
#endif
fixP->fx_tcbit = 0;
fixP->fx_done = 0;
-#ifdef TC_something
+#if defined (TC_I960) || defined (TC_NS32K)
fixP->fx_bsr = 0;
#endif
case O_absent:
break;
+ case O_add:
+ /* 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;
+ exp->X_add_symbol = stmp;
+ exp->X_add_number = 0;
+ return fix_new_exp (frag, where, size, exp, pcrel, r_type);
+ }
+
case O_uminus:
sub = exp->X_add_symbol;
off = exp->X_add_number;
#endif
}
+#ifdef BFD_ASSEMBLER
+
+/* Reset the section indices after removing the gas created sections. */
+
+static void
+renumber_sections (abfd, sec, countparg)
+ bfd *abfd;
+ asection *sec;
+ PTR countparg;
+{
+ int *countp = (int *) countparg;
+
+ sec->index = *countp;
+ ++*countp;
+}
+
+#endif /* defined (BFD_ASSEMBLER) */
+
#if defined (BFD_ASSEMBLER) || ! defined (BFD)
static fragS *
struct frchain *frchp;
{
fragS dummy, *prev_frag = &dummy;
- fixS fix_dummy, *prev_fix = &fix_dummy;
+ fixS fix_dummy;
+#ifdef BFD_ASSEMBLER
+ fixS *prev_fix = &fix_dummy;
+#endif
for (; frchp && frchp->frch_seg == section; frchp = frchp->frch_next)
{
switch (fragP->fr_type)
{
case rs_align:
+ case rs_align_code:
case rs_org:
+ case rs_space:
#ifdef HANDLE_ALIGN
HANDLE_ALIGN (fragP);
#endif
- fragP->fr_type = rs_fill;
know (fragP->fr_next != NULL);
fragP->fr_offset = (fragP->fr_next->fr_address
- fragP->fr_address
- fragP->fr_fix) / fragP->fr_var;
+ assert (fragP->fr_offset >= 0);
+ fragP->fr_type = rs_fill;
break;
case rs_fill:
flags = bfd_get_section_flags (abfd, sec);
- seginfo = (segment_info_type *) bfd_get_section_userdata (abfd, sec);
+ seginfo = seg_info (sec);
if (seginfo && seginfo->frchainP)
{
relax_segment (seginfo->frchainP->frch_root, sec);
/* ignore it */;
else if (fixp->fx_addsy)
{
- symbolS *sym = fixp->fx_addsy;
- asection *symsec = sym->bsym->section;
+ 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;
/* If it's one of these sections, assume the symbol is
definitely going to be output. The code in
md_estimate_size_before_relax in tc-mips.c uses this test
as well, so if you change this code you should look at that
code. */
- if (symsec == &bfd_und_section
- || symsec == &bfd_abs_section
+ if (bfd_is_und_section (symsec)
+ || bfd_is_abs_section (symsec)
|| bfd_is_com_section (symsec))
{
fixp->fx_addsy->sy_used_in_reloc = 1;
- continue;
+ goto done;
}
/* Since we're reducing to section symbols, don't attempt to reduce
if (sym->bsym->flags & BSF_SECTION_SYM)
{
fixp->fx_addsy->sy_used_in_reloc = 1;
- continue;
+ goto done;
}
/* Is there some other reason we can't adjust this one? (E.g.,
if (! obj_fix_adjustable (fixp))
{
fixp->fx_addsy->sy_used_in_reloc = 1;
- continue;
+ goto done;
}
#endif
if (! tc_fix_adjustable (fixp))
{
fixp->fx_addsy->sy_used_in_reloc = 1;
- continue;
+ 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. */
fixp->fx_offset += S_GET_VALUE (sym);
- if (sym->sy_frag)
- fixp->fx_offset += sym->sy_frag->fr_address;
fixp->fx_addsy = section_symbol (symsec);
fixp->fx_addsy->sy_used_in_reloc = 1;
+
+ done:
+ ;
}
#if 1/*def RELOC_REQUIRES_SYMBOL*/
else
a local symbol in the absolute section. */
fixp->fx_addsy = section_symbol (absolute_section);
- fixp->fx_addsy->sy_used_in_reloc = 1;
+/* fixp->fx_addsy->sy_used_in_reloc = 1; */
}
#endif
for (fixp = seginfo->fix_root; fixp != (fixS *) NULL; fixp = fixp->fx_next)
{
arelent *reloc;
- char *data;
bfd_reloc_status_type s;
if (fixp->fx_done)
n--;
continue;
}
- 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 ();
- if (reloc->howto->partial_inplace == false
- && reloc->howto->pcrel_offset == true
- && reloc->howto->pc_relative == true)
- {
- /* bfd_perform_relocation screws this up */
- reloc->addend += reloc->address;
- }
- /* Pass bogus address so that when bfd_perform_relocation adds
- `reloc->address' back in, it'll come up with `data', which is where
- we want it to operate. We can't just do it by fudging reloc->address,
- since that might be used in the calculations(?). */
- s = bfd_perform_relocation (stdoutput, reloc, data - reloc->address,
- sec, stdoutput, &err);
+ s = bfd_install_relocation (stdoutput, reloc,
+ fixp->fx_frag->fr_literal,
+ fixp->fx_frag->fr_address,
+ sec, &err);
switch (s)
{
case bfd_reloc_ok:
as_bad_where (fixp->fx_file, fixp->fx_line, "relocation overflow");
break;
default:
- as_fatal ("bad return from bfd_perform_relocation");
+ as_fatal ("%s:%u: bad return from bfd_perform_relocation",
+ fixp->fx_file, fixp->fx_line);
}
relocs[i++] = reloc;
}
abort ();
for (j = 0; reloc[j]; j++)
{
- s = bfd_perform_relocation (stdoutput, reloc[j],
- data - reloc[0]->address,
- sec, stdoutput, &err);
+ s = bfd_install_relocation (stdoutput, reloc[j],
+ fixp->fx_frag->fr_literal,
+ fixp->fx_frag->fr_address,
+ sec, &err);
switch (s)
{
case bfd_reloc_ok:
break;
+ case bfd_reloc_overflow:
+ as_bad_where (fixp->fx_file, fixp->fx_line,
+ "relocation overflow");
+ break;
default:
- as_fatal ("bad return from bfd_perform_relocation");
+ as_fatal ("%s:%u: bad return from bfd_perform_relocation",
+ fixp->fx_file, fixp->fx_line);
}
}
}
{
bfd_perror (stdoutput->filename);
as_perror ("FATAL: Can't write %s", stdoutput->filename);
- exit (42);
+ 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,
{
bfd_perror (stdoutput->filename);
as_perror ("FATAL: Can't write %s", stdoutput->filename);
- exit (42);
+ exit (EXIT_FAILURE);
}
offset += fill_size;
}
+ }
+ else {
+ /* Build a buffer full of fill objects and output it as
+ * often as necessary. This saves on the overhead of potentially
+ * lots of bfd_set_section_contents calls.
+ */
+ int n_per_buf, i;
+ if (fill_size == 1)
+ {
+ n_per_buf = sizeof (buf);
+ memset (buf, *fill_literal, n_per_buf);
+ }
+ else
+ {
+ char *bufp;
+ n_per_buf = sizeof(buf)/fill_size;
+ for (i = n_per_buf, bufp = buf; i; i--, bufp += fill_size)
+ memcpy(bufp, fill_literal, fill_size);
+ }
+ for (; count > 0; count -= n_per_buf)
+ {
+ n_per_buf = n_per_buf > count ? count : n_per_buf;
+ x = bfd_set_section_contents (stdoutput, sec,
+ buf, (file_ptr) offset,
+ (bfd_size_type) n_per_buf * fill_size);
+ assert (x == true);
+ offset += n_per_buf * fill_size;
+ }
+ }
+ }
+#else
+ while (count--)
+ {
+ x = bfd_set_section_contents (stdoutput, sec,
+ fill_literal, (file_ptr) offset,
+ (bfd_size_type) fill_size);
+ assert (x == true);
+ offset += fill_size;
+ }
+#endif
}
}
#endif
/* Under VMS we try to be compatible with VAX-11 "C". Thus, we call
a routine to check for the definition of the procedure "_main",
and if so -- fix it up so that it can be program entry point. */
- VMS_Check_For_Main ();
+ vms_check_for_main ();
#endif /* VMS */
/* After every sub-segment, we fake an ".align ...". This conforms to
/* Remove the sections created by gas for its own purposes. */
{
asection **seclist, *sec;
+ int i;
+
seclist = &stdoutput->sections;
while (seclist && *seclist)
{
if (*seclist)
seclist = &(*seclist)->next;
}
+ i = 0;
+ bfd_map_over_sections (stdoutput, renumber_sections, &i);
}
bfd_map_over_sections (stdoutput, chain_frchains_together, (char *) 0);
exp.X_op_symbol = lie->sub;
exp.X_add_number = lie->addnum;
#ifdef BFD_ASSEMBLER
+#ifdef TC_CONS_FIX_NEW
+ TC_CONS_FIX_NEW (lie->frag,
+ lie->word_goes_here - lie->frag->fr_literal,
+ 2, &exp);
+#else
fix_new_exp (lie->frag,
lie->word_goes_here - lie->frag->fr_literal,
2, &exp, 0, BFD_RELOC_NONE);
+#endif
#else
#if defined(TC_SPARC) || defined(TC_A29K) || defined(NEED_FX_R_TYPE)
fix_new_exp (lie->frag,
/* Patch the jump table */
/* 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;
+#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)
{
/* this is a long jump from table_ptr+0 to the final target */
from_addr = table_addr;
to_addr = S_GET_VALUE (lie->add) + lie->addnum;
+#ifdef BFD_ASSEMBLER
+ to_addr += lie->add->sy_frag->fr_address;
+#endif
md_create_long_jump (table_ptr, from_addr, to_addr, lie->dispfrag, lie->add);
table_ptr += md_long_jump_size;
table_addr += md_long_jump_size;
/*
* Now do the VMS-dependent part of writing the object file
*/
- VMS_write_object_file (H_GET_TEXT_SIZE (&headers),
+ vms_write_object_file (H_GET_TEXT_SIZE (&headers),
H_GET_DATA_SIZE (&headers),
H_GET_BSS_SIZE (&headers),
text_frag_root, data_frag_root);
#endif /* VMS */
#else /* BFD_ASSEMBLER */
+ /* Resolve symbol values. This needs to be done before processing
+ the relocations. */
+ if (symbol_rootP)
+ {
+ symbolS *symp;
+
+ for (symp = symbol_rootP; symp; symp = symbol_next (symp))
+ if (!symp->sy_resolved)
+ resolve_symbol_value (symp);
+ }
+
bfd_map_over_sections (stdoutput, adjust_reloc_syms, (char *)0);
/* Set up symbol table, and write it out. */
{
int punt = 0;
+ /* 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)
{
if (symp->sy_value.X_op == O_constant)
Put them in the common section now. */
if (S_IS_DEFINED (symp) == 0
&& S_GET_VALUE (symp) != 0)
- S_SET_SEGMENT (symp, &bfd_com_section);
+ S_SET_SEGMENT (symp, bfd_com_section_ptr);
#if 0
printf ("symbol `%s'\n\t@%x: value=%d flags=%x seg=%s\n",
S_GET_NAME (symp), symp,
break;
case rs_align:
+ case rs_align_code:
{
int offset = relax_align (address, (int) fragP->fr_offset);
if (offset % fragP->fr_var != 0)
break;
case rs_org:
+ case rs_space:
/* Assume .org is nugatory. It will grow with 1st relax. */
break;
} /* case rs_broken_word */
#endif
case rs_align:
+ case rs_align_code:
growth = (relax_align ((relax_addressT) (address
+ fragP->fr_fix),
(int) offset)
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");
+ fragP->fr_symbol = 0;
+ if (growth < 0)
+ {
+ as_warn (".space or .fill with negative value, ignored");
+ growth = 0;
+ }
+ }
+ else
+ growth = 0;
+ break;
+
case rs_machine_dependent:
#ifdef md_relax_frag
growth = md_relax_frag (fragP, stretch);
}
aim = target - address - fragP->fr_fix;
- /* The displacement is affected by the instruction size
- for the 32k architecture. I think we ought to be able
- to add fragP->fr_pcrel_adjust in all cases (it should be
- zero if not used), but just in case it breaks something
- else we'll put this inside #ifdef NS32K ... #endif */
-#ifndef TC_NS32K
- if (fragP->fr_pcrel_adjust)
- abort ();
+#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
- aim += fragP->fr_pcrel_adjust;
if (aim < 0)
{
#if defined (BFD_ASSEMBLER) || !defined (BFD)
+#ifndef TC_RELOC_RTSYM_LOC_FIXUP
+#define TC_RELOC_RTSYM_LOC_FIXUP(X) (1)
+#endif
+
/* fixup_segment()
Go through all the fixS's in a segment and see which ones can be
int size;
char *place;
long where;
- char pcrel;
+ int pcrel, plt;
fragS *fragP;
segT add_symbol_segment = absolute_section;
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;
sub_symbolP = fixP->fx_subsy;
add_number = fixP->fx_offset;
pcrel = fixP->fx_pcrel;
-
+ plt = fixP->fx_plt;
+
if (add_symbolP)
add_symbol_segment = S_GET_SEGMENT (add_symbolP);
if (add_symbolP)
{
- if (add_symbol_segment == this_segment_type && pcrel)
+ if (add_symbol_segment == this_segment_type && pcrel && !plt
+ && TC_RELOC_RTSYM_LOC_FIXUP (fixP->fx_r_type))
{
/*
* This fixup was made when the symbol's segment was
else
{
seg_reloc_count++;
+#if !defined (TC_I386) || !(defined (OBJ_ELF) || defined (OBJ_COFF))
add_number += S_GET_VALUE (add_symbolP);
+#endif
}
}
}
#endif
}
#ifdef TC_VALIDATE_FIX
- skip:
+ skip: ;
+#endif
+#ifdef DEBUG5
+ fprintf (stderr, "result:\n");
+ print_fixup (fixP);
#endif
- ;
} /* For each fixS in this segment. */
TC_ADJUST_RELOC_COUNT (fixP, seg_reloc_count);
}
}
+/* for debugging */
+extern int indent_level;
+extern void print_symbol_value_1 ();
+
+void
+print_fixup (fixp)
+ fixS *fixp;
+{
+ indent_level = 1;
+ fprintf (stderr, "fix %lx %s:%d", (long) fixp, fixp->fx_file, fixp->fx_line);
+ if (fixp->fx_pcrel)
+ fprintf (stderr, " pcrel");
+ if (fixp->fx_pcrel_adjust)
+ fprintf (stderr, " pcrel_adjust=%d", fixp->fx_pcrel_adjust);
+ if (fixp->fx_im_disp)
+ {
+#ifdef TC_NS32K
+ fprintf (stderr, " im_disp=%d", fixp->fx_im_disp);
+#else
+ fprintf (stderr, " im_disp");
+#endif
+ }
+ if (fixp->fx_tcbit)
+ fprintf (stderr, " tcbit");
+ if (fixp->fx_done)
+ fprintf (stderr, " done");
+ fprintf (stderr, "\n size=%d frag=%lx where=%ld offset=%lx addnumber=%lx",
+ fixp->fx_size, (long) fixp->fx_frag, (long) fixp->fx_where,
+ (long) fixp->fx_offset, (long) fixp->fx_addnumber);
+#ifdef BFD_ASSEMBLER
+ fprintf (stderr, "\n %s (%d)", bfd_get_reloc_code_name (fixp->fx_r_type),
+ fixp->fx_r_type);
+#else
+#ifdef NEED_FX_R_TYPE
+ fprintf (stderr, " r_type=%d", fixp->fx_r_type);
+#endif
+#endif
+ if (fixp->fx_addsy)
+ {
+ fprintf (stderr, "\n +<");
+ print_symbol_value_1 (stderr, fixp->fx_addsy);
+ fprintf (stderr, ">");
+ }
+ if (fixp->fx_subsy)
+ {
+ fprintf (stderr, "\n -<");
+ print_symbol_value_1 (stderr, fixp->fx_subsy);
+ fprintf (stderr, ">");
+ }
+ fprintf (stderr, "\n");
+}
+
/* end of write.c */