#endif
static object_headers headers;
-
long string_byte_count;
-
static char *the_object_file;
-
char *next_object_file_charP; /* Tracks object file bytes. */
#ifndef OBJ_VMS
#endif /* BFD_ASSEMBLER */
static long fixup_segment PARAMS ((fixS * fixP, segT this_segment_type));
-static relax_addressT relax_align PARAMS ((relax_addressT addr, long align));
+static relax_addressT relax_align PARAMS ((relax_addressT addr, int align));
void relax_segment PARAMS ((struct frag * seg_frag_root, segT seg_type));
/*
short int size; /* 1, 2, or 4 usually. */
symbolS *add_symbol; /* X_add_symbol. */
symbolS *sub_symbol; /* X_subtract_symbol. */
- long offset; /* X_add_number. */
+ offsetT offset; /* X_add_number. */
int pcrel; /* TRUE if PC-relative relocation. */
#ifdef BFD_ASSEMBLER
bfd_reloc_code_real_type r_type; /* Relocation type */
#endif
-#ifndef BFD
+#if !defined (BFD) && !defined (BFD_ASSEMBLER)
void
remove_subsegs (head, seg, root, last)
#endif /* BFD */
-#ifndef BFD
-
static void
cvt_frag_to_fill (x, fragP)
#ifdef BFD_ASSEMBLER
md_convert_frag (headers, fragP);
#endif
- assert (fragP->fr_next == NULL \
- || (fragP->fr_next->fr_address - fragP->fr_address \
- == fragP->fr_fix));
+ assert (fragP->fr_next == NULL || (fragP->fr_next->fr_address - fragP->fr_address == fragP->fr_fix));
/*
* After md_convert_frag, we make the frag into a ".space 0".
flags = bfd_get_section_flags (abfd, sec);
- if (flags & SEC_ALLOC)
+ if (/*flags & SEC_ALLOC*/ 1)
{
fragS *fragp;
segment_info_type *seginfo;
int x;
- unsigned long size, newsize;
+ valueT size, newsize;
seginfo = (segment_info_type *) bfd_get_section_userdata (abfd, sec);
- relax_segment (seginfo->frchainP->frch_root, sec);
- for (fragp = seginfo->frchainP->frch_root; fragp; fragp = fragp->fr_next)
- cvt_frag_to_fill (sec, fragp);
- for (fragp = seginfo->frchainP->frch_root;
- fragp->fr_next;
- fragp = fragp->fr_next)
- /* walk to last elt */;
- size = fragp->fr_address;
+ if (seginfo && seginfo->frchainP)
+ {
+ relax_segment (seginfo->frchainP->frch_root, sec);
+ for (fragp = seginfo->frchainP->frch_root; fragp; fragp = fragp->fr_next)
+ cvt_frag_to_fill (sec, fragp);
+ for (fragp = seginfo->frchainP->frch_root;
+ fragp->fr_next;
+ fragp = fragp->fr_next)
+ /* walk to last elt */;
+ size = fragp->fr_address + fragp->fr_fix;
+ }
+ else
+ size = 0;
if (size > 0)
{
flags |= SEC_HAS_CONTENTS;
/* @@ This is just an approximation. */
if (seginfo->fix_root)
flags |= SEC_RELOC;
+ else
+ flags &= ~SEC_RELOC;
x = bfd_set_section_flags (abfd, sec, flags);
assert (x == true);
}
#endif
}
+#ifdef DEBUG2
+static void
+dump_section_relocs (abfd, sec, stream_)
+ bfd *abfd;
+ asection *sec;
+ char *stream_;
+{
+ FILE *stream = (FILE *) stream_;
+ segment_info_type *seginfo = seg_info (sec);
+ fixS *fixp = seginfo->fix_root;
+
+ if (!fixp)
+ return;
+
+ fprintf (stream, "sec %s relocs:\n", sec->name);
+ while (fixp)
+ {
+ symbolS *s = fixp->fx_addsy;
+ if (s)
+ fprintf (stream, " %08x: %s(%s+%x)+%x\n", fixp,
+ S_GET_NAME (s), s->bsym->section->name,
+ S_GET_VALUE (s), fixp->fx_offset);
+ 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)
+#endif
+
+static void
+adjust_reloc_syms (abfd, sec, xxx)
+ bfd *abfd;
+ asection *sec;
+ char *xxx;
+{
+ segment_info_type *seginfo = seg_info (sec);
+ fixS *fixp;
+
+ if (seginfo == NULL)
+ return;
+
+ dump_section_relocs (abfd, sec, stderr);
+
+ for (fixp = seginfo->fix_root; fixp; fixp = fixp->fx_next)
+ if (fixp->fx_addsy)
+ {
+ symbolS *sym = fixp->fx_addsy;
+ asection *symsec = sym->bsym->section;
+ segment_info_type *symseginfo = seg_info (symsec);
+
+ /* If it's one of these sections, assume the symbol is definitely
+ going to be output. */
+ if (symsec == &bfd_und_section
+ || symsec == &bfd_abs_section
+ || bfd_is_com_section (symsec))
+ continue;
+
+ /* Since we're reducing to section symbols, don't attempt to reduce
+ anything that's already using one. */
+ if (sym->bsym == symsec->symbol)
+ continue;
+
+ /* 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))
+ continue;
+#endif
+ /* 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;
+ if (symseginfo->sym)
+ fixp->fx_addsy = symseginfo->sym;
+ else
+ {
+ fixp->fx_addsy = symbol_find (symsec->name);
+ if (!fixp->fx_addsy)
+ {
+ fixp->fx_addsy = symbol_make (symsec->name);
+ fixp->fx_addsy->bsym = symsec->symbol;
+ }
+ symseginfo->sym = fixp->fx_addsy;
+ }
+ }
+
+ dump_section_relocs (abfd, sec, stderr);
+}
+
static void
write_contents (abfd, sec, xxx)
bfd *abfd;
arelent **relocs;
fixS *fixp;
- if (! (bfd_get_section_flags (abfd, sec) & SEC_LOAD))
+ /* If seginfo is NULL, we did not create this section; don't do
+ anything with it. */
+ if (seginfo == NULL)
return;
fixup_segment (seginfo->fix_root, sec);
n = 0;
- for (i = 0, fixp = seginfo->fix_root; fixp; fixp = fixp->fx_next)
- {
- n++;
- if (fixp->fx_addsy)
- {
- symbolS *sym = fixp->fx_addsy;
- asection *sec = sym->bsym->section;
- if (sec == &bfd_und_section
- || sec == &bfd_abs_section
- || sec == &bfd_com_section)
- continue;
- if (sym->bsym == sec->symbol)
- continue;
- /* 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);
- fixp->fx_addsy = symbol_find (sec->name);
- if (!fixp->fx_addsy)
- {
- fixp->fx_addsy = symbol_make (sec->name);
- fixp->fx_addsy->bsym = sec->symbol;
- }
- }
- }
-
- /* Force calculations (size, vma) to get done. */
- bfd_set_section_contents (stdoutput, sec, "", 0, 0);
+ for (fixp = seginfo->fix_root; fixp; fixp = fixp->fx_next)
+ n++;
+#ifndef RELOC_EXPANSION_POSSIBLE
/* Set up reloc information as well. */
relocs = (arelent **) bfd_alloc_by_size_t (stdoutput,
n * sizeof (arelent *));
+ bzero ((char*)relocs, n * sizeof (arelent*));
i = 0;
for (fixp = seginfo->fix_root; fixp != (fixS *) NULL; fixp = fixp->fx_next)
if (fixp->fx_where + 4
> fixp->fx_frag->fr_fix + fixp->fx_frag->fr_offset)
abort ();
+ /* Pass bogus address so that when bfd_perform_relocation adds
+ `address' back in, it'll come up with `data', which is where
+ we want it to operate. */
s = bfd_perform_relocation (stdoutput, reloc, data - reloc->address,
sec, stdoutput);
switch (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 *));
+
+ i = 0;
+ for (fixp = seginfo->fix_root; fixp != (fixS *) NULL; fixp = fixp->fx_next)
+ {
+ arelent **reloc;
+ extern arelent *tc_gen_reloc ();
+ char *data;
+ bfd_reloc_status_type s;
+ int j;
+
+ if (fixp->fx_addsy == 0)
+ {
+ /* @@ Need some other flag to indicate which have already
+ been performed... */
+ n--;
+ continue;
+ }
+ reloc = tc_gen_reloc (sec, fixp);
+
+ for (j = 0; reloc[j]; j++)
+ {
+ relocs[i++] = reloc[j];
+ assert(i <= n);
+ }
+ data = fixp->fx_frag->fr_literal + fixp->fx_where;
+ if (fixp->fx_where + 4
+ > fixp->fx_frag->fr_fix + fixp->fx_frag->fr_offset)
+ abort ();
+ for (j = 0; reloc[j]; j++)
+ {
+ s = bfd_perform_relocation (stdoutput, reloc[j], data - reloc[j]->address,
+ sec, stdoutput);
+ switch (s)
+ {
+ case bfd_reloc_ok:
+ break;
+ default:
+ as_fatal ("bad return from bfd_perform_relocation");
+ }
+ }
+ }
+ n = i;
+#endif
+
if (n)
bfd_set_reloc (stdoutput, sec, relocs, n);
+ else
+ bfd_set_section_flags (abfd, sec,
+ bfd_get_section_flags (abfd, sec) & ~SEC_RELOC);
+#ifdef DEBUG2
+ {
+ int i;
+ arelent *r;
+ asymbol *s;
+ fprintf (stderr, "relocs for sec %s\n", sec->name);
+ for (i = 0; i < n; i++)
+ {
+ r = relocs[i];
+ s = *r->sym_ptr_ptr;
+ fprintf (stderr, " reloc %2d @%08x off %4x : sym %-10s addend %x\n",
+ i, r, r->address, s->name, r->addend);
+ }
+ }
+#endif
+
+ /* Force calculations (size, vma) to get done. */
+ bfd_set_section_contents (stdoutput, sec, "", 0, (addressT) 0);
/* Write out the frags. */
+ if (! (bfd_get_section_flags (abfd, sec) & SEC_HAS_CONTENTS))
+ return;
+
for (frags = seginfo->frchainP->frch_root;
frags;
frags = frags->fr_next)
while (count--)
{
x = bfd_set_section_contents (stdoutput, sec,
- fill_literal, offset, fill_size);
+ fill_literal, offset,
+ (bfd_size_type) fill_size);
assert (x == true);
offset += fill_size;
}
}
#endif
+#if defined (BFD_ASSEMBLER) || !defined (BFD)
+
void
write_object_file ()
{
register struct frchain *frchainP; /* Track along all frchains. */
register fragS *fragP; /* Track along all frags. */
- register struct frchain *next_frchainP;
- register fragS **prev_fragPP;
+#if !defined (BFD_ASSEMBLER) && !defined (OBJ_VMS)
long object_file_size;
+#endif
/* Do we really want to write it? */
{
#endif
#ifdef BFD_ASSEMBLER
+
bfd_map_over_sections (stdoutput, relax_and_size_seg, (char *) 0);
#else
relax_segment (text_frag_root, SEG_TEXT);
{
#ifdef BFD_ASSEMBLER
fix_new (lie->frag, lie->word_goes_here - lie->frag->fr_literal,
- 2, lie->add, lie->sub, lie->addnum, 0, BFD_RELOC_NONE);
+ 2, lie->add, lie->sub, lie->addnum, 0,
+ BFD_RELOC_NONE);
#else
#if defined(TC_SPARC) || defined(TC_A29K) || defined(NEED_FX_R_TYPE)
fix_new (lie->frag, lie->word_goes_here - lie->frag->fr_literal,
{
struct broken_word *untruth;
char *table_ptr;
- long table_addr;
- long from_addr, to_addr;
+ addressT table_addr;
+ addressT from_addr, to_addr;
int n, m;
fragP = lie->dispfrag;
continue;
/* Patch the jump table */
/* This is the offset from ??? to table_ptr+0 */
- to_addr = table_addr
- - S_GET_VALUE (lie->sub);
+ to_addr = table_addr - S_GET_VALUE (lie->sub);
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)
{
int trsize, drsize;
subseg_change (SEG_TEXT, 0);
- trsize = md_reloc_size * fixup_segment (text_fix_root,
- SEG_TEXT);
+ trsize = md_reloc_size * fixup_segment (text_fix_root, SEG_TEXT);
subseg_change (SEG_DATA, 0);
- drsize = md_reloc_size * fixup_segment (data_fix_root,
- SEG_DATA);
+ drsize = md_reloc_size * fixup_segment (data_fix_root, SEG_DATA);
H_SET_RELOCATION_SIZE (&headers, trsize, drsize);
/* FIXME move this stuff into the pre-write-hook */
#endif /* VMS */
#else /* BFD_ASSEMBLER */
+#ifdef obj_check_file_symbols
+ obj_check_file_symbols ();
+#endif
+
+ bfd_map_over_sections (stdoutput, adjust_reloc_syms, (char *)0);
+
/* Set up symbol table, and write it out. */
if (symbol_rootP)
{
for (symp = symbol_rootP; symp; symp = symbol_next (symp))
{
+ int keep = 0;
+
S_SET_VALUE (symp, S_GET_VALUE (symp) + symp->sy_frag->fr_address);
/* So far, common symbols have been treated like undefined symbols.
Put them in the common section now. */
&& S_GET_VALUE (symp) != 0)
S_SET_SEGMENT (symp, &bfd_com_section);
#if 0
- printf ("symbol `%s'\n\t@%x: value=%d type=%d forward=%x seg=%s\n",
+ printf ("symbol `%s'\n\t@%x: value=%d flags=%x forward=%x seg=%s\n",
S_GET_NAME (symp), symp,
S_GET_VALUE (symp),
- S_GET_DATA_TYPE (symp),
+ symp->bsym->flags,
symp->sy_forward,
segment_name (symp->bsym->section));
#endif
prev = symbol_previous (symp);
next = symbol_next (symp);
#ifdef DEBUG
- /* debugging: verify consistency */
- {
- symbolS *p = symp, *n = symp;
- while (symbol_previous (p))
- p = symbol_previous (p);
- while (symbol_next (n))
- n = symbol_next (n);
- verify_symbol_chain (p, n);
- }
+ verify_symbol_chain_2 (symp);
#endif
if (prev)
{
symbol_next (prev) = next;
symp = prev;
}
+ else if (symp == symbol_rootP)
+ symbol_rootP = next;
else
abort ();
if (next)
else
symbol_lastP = prev;
#ifdef DEBUG
- /* debugging: verify consistency */
- {
- symbolS *p = symp, *n = symp;
- while (symbol_previous (p))
- p = symbol_previous (p);
- while (symbol_next (n))
- n = symbol_next (n);
- verify_symbol_chain (p, n);
- }
+ if (prev)
+ verify_symbol_chain_2 (prev);
+ else if (next)
+ verify_symbol_chain_2 (next);
#endif
continue;
}
{
asymbol **asympp;
boolean result;
+ extern PTR bfd_alloc PARAMS ((bfd *, size_t));
- asympp = (asymbol **) bfd_alloc (stdoutput, n * sizeof (asymbol *));
+ asympp = (asymbol **) bfd_alloc (stdoutput,
+ n * sizeof (asymbol *));
symp = symbol_rootP;
for (i = 0; i < n; i++, symp = symbol_next (symp))
{
}
}
+
#ifdef obj_frob_file
obj_frob_file ();
#endif
output_file_close (out_file_name);
#endif /* BFD_ASSEMBLER */
}
-#endif /* BFD */
+#endif /* ! BFD */
/*
* relax_segment()
* these frag addresses may not be the same as final object-file addresses.
*/
-
+/* Subroutines of relax_segment. */
static int
is_dnrange (f1, f2)
struct frag *f1;
}
/* Relax_align. Advance location counter to next address that has 'alignment'
- lowest order bits all 0s. */
-
-/* How many addresses does the .align take? */
+ lowest order bits all 0s, return size of adjustment made. */
static relax_addressT
relax_align (address, alignment)
register relax_addressT address; /* Address now. */
- register long alignment; /* Alignment (binary). */
+ register int alignment; /* Alignment (binary). */
{
relax_addressT mask;
relax_addressT new_address;
break;
case rs_align:
- address += relax_align (address, fragP->fr_offset);
+ address += relax_align (address, (int) fragP->fr_offset);
break;
case rs_org:
if (offset <= -32768 || offset >= 32767)
{
if (flagseen['K'])
- as_warn (".word %s-%s+%ld didn't fit",
- S_GET_NAME (lie->add),
- S_GET_NAME (lie->sub),
- lie->addnum);
+ {
+ char buf[50];
+ sprint_value (buf, lie->addnum);
+ as_warn (".word %s-%s+%s didn't fit",
+ S_GET_NAME (lie->add),
+ S_GET_NAME (lie->sub),
+ buf);
+ }
lie->added = 1;
if (fragP->fr_subtype == 0)
{
case rs_align:
growth = (relax_align ((relax_addressT) (address
+ fragP->fr_fix),
- offset)
+ (int) offset)
- relax_align ((relax_addressT) (was_address
+ fragP->fr_fix),
- offset));
+ (int) offset));
break;
case rs_org:
/* 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. */
-
- /* JF was just address */
- /* JF also added is_dnrange hack */
- /* There's gotta be a better/faster/etc way
- to do this. . . */
- /* gnu@cygnus.com: I changed this from > to >=
- because I ran into a zero-length frag (fr_fix=0)
- which was created when the obstack needed a new
- chunk JUST AFTER the opcode of a branch. Since
- fr_fix is zero, fr_address of this frag is the same
- as fr_address of the next frag. This
- zero-length frag was variable and jumped to .+2
- (in the next frag), but since the > comparison
- below failed (the two were =, not >), "stretch"
- was not added to the target. Stretch was 178, so
- the offset appeared to be .-176 instead, which did
- not fit into a byte branch, so the assembler
- relaxed the branch to a word. This didn't compare
- with what happened when the same source file was
- assembled on other machines, which is how I found it.
- You might want to think about what other places have
- trouble with zero length frags... */
+ 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;
}
- } /* if there's a symbol attached */
+ }
aim = target - address - fragP->fr_fix;
/* The displacement is affected by the instruction size
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 */
-#ifdef TC_NS32K
+#ifndef TC_NS32K
+ if (fragP->fr_pcrel_adjust)
+ abort ();
+#endif
aim += fragP->fr_pcrel_adjust;
-#endif /* TC_NS32K */
if (aim < 0)
{
register long seg_reloc_count;
register symbolS *add_symbolP;
register symbolS *sub_symbolP;
- long add_number;
+ valueT add_number;
register int size;
register char *place;
register long where;
}
else
{
- as_bad ("Can't emit reloc {- %s-seg symbol \"%s\"} @ file address %d.",
+ char buf[50];
+ sprint_value (buf, fragP->fr_address + where);
+ as_bad ("Can't emit reloc {- %s-seg symbol \"%s\"} @ file address %s.",
segment_name (S_GET_SEGMENT (sub_symbolP)),
- S_GET_NAME (sub_symbolP), fragP->fr_address + where);
- } /* if absolute */
+ S_GET_NAME (sub_symbolP), buf);
+ }
}
- } /* if sub_symbolP */
+ }
if (add_symbolP)
{
if (!fixP->fx_bit_fixP)
{
- if ((size == 1 &&
- (add_number & ~0xFF)
+ if ((size == 1
+ && (add_number & ~0xFF)
&& ((add_number & ~0xFF) != (-1 & ~0xFF)))
|| (size == 2
&& (add_number & ~0xFFFF)
- && ((add_number & ~0xFFFF) != (-1 & ~0xFFFF))))
+ && ((add_number & ~0xFFFF) != (-1 & ~0xFFFF)))
+ || (size == 4
+ && (add_number & ~(valueT)0xFFFFFFFF)
+ && ((add_number & ~(valueT)0xFFFFFFFF) != (-1 & ~(valueT)0xFFFFFFFF)))
+ )
{
- as_bad ("Value of %d too large for field of %d bytes at 0x%x",
- add_number, size, fragP->fr_address + where);
+ char buf[50];
+ sprint_value (buf, fragP->fr_address + where);
+ as_bad ("Value of %d too large for field of %d bytes at %s",
+ add_number, size, buf);
} /* generic error checking */
#ifdef WARN_SIGNED_OVERFLOW_WORD
/* Warn if a .word value is too large when treated as a signed
#endif /* OBJ_COFF */
return (seg_reloc_count);
-} /* fixup_segment() */
+}
/* end of write.c */