Line 1... |
Line 1... |
/* write.c - emit .o file
|
/* write.c - emit .o file
|
Copyright 1986, 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
|
Copyright 1986, 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
|
1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
|
1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
|
2010 Free Software Foundation, Inc.
|
2010, 2011 Free Software Foundation, Inc.
|
|
|
This file is part of GAS, the GNU Assembler.
|
This file is part of GAS, the GNU Assembler.
|
|
|
GAS is free software; you can redistribute it and/or modify
|
GAS is free software; you can redistribute it and/or modify
|
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
Line 706... |
Line 706... |
{
|
{
|
as_bad_where (r->file, r->line, _("invalid reloc expression"));
|
as_bad_where (r->file, r->line, _("invalid reloc expression"));
|
sec = NULL;
|
sec = NULL;
|
}
|
}
|
else if (sym != NULL)
|
else if (sym != NULL)
|
|
{
|
|
if (S_IS_LOCAL (sym) && !symbol_section_p (sym))
|
|
{
|
|
asection *symsec = S_GET_SEGMENT (sym);
|
|
if (!(((symsec->flags & SEC_MERGE) != 0
|
|
&& addend != 0)
|
|
|| (symsec->flags & SEC_THREAD_LOCAL) != 0))
|
|
{
|
|
addend += S_GET_VALUE (sym);
|
|
sym = section_symbol (symsec);
|
|
}
|
|
}
|
symbol_mark_used_in_reloc (sym);
|
symbol_mark_used_in_reloc (sym);
|
}
|
}
|
|
}
|
if (sym == NULL)
|
if (sym == NULL)
|
{
|
{
|
if (abs_section_sym == NULL)
|
if (abs_section_sym == NULL)
|
abs_section_sym = section_symbol (absolute_section);
|
abs_section_sym = section_symbol (absolute_section);
|
sym = abs_section_sym;
|
sym = abs_section_sym;
|
Line 1144... |
Line 1157... |
as_fatal (_("%s:%u: bad return from bfd_install_relocation: %x"),
|
as_fatal (_("%s:%u: bad return from bfd_install_relocation: %x"),
|
file, line, s);
|
file, line, s);
|
}
|
}
|
}
|
}
|
|
|
|
static fragS *
|
|
get_frag_for_reloc (fragS *last_frag,
|
|
const segment_info_type *seginfo,
|
|
const struct reloc_list *r)
|
|
{
|
|
fragS *f;
|
|
|
|
for (f = last_frag; f != NULL; f = f->fr_next)
|
|
if (f->fr_address <= r->u.b.r.address
|
|
&& r->u.b.r.address < f->fr_address + f->fr_fix)
|
|
return f;
|
|
|
|
for (f = seginfo->frchainP->frch_root; f != NULL; f = f->fr_next)
|
|
if (f->fr_address <= r->u.b.r.address
|
|
&& r->u.b.r.address < f->fr_address + f->fr_fix)
|
|
return f;
|
|
|
|
as_bad_where (r->file, r->line,
|
|
_("reloc not within (fixed part of) section"));
|
|
return NULL;
|
|
}
|
|
|
static void
|
static void
|
write_relocs (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
|
write_relocs (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
|
{
|
{
|
segment_info_type *seginfo = seg_info (sec);
|
segment_info_type *seginfo = seg_info (sec);
|
unsigned int i;
|
|
unsigned int n;
|
unsigned int n;
|
struct reloc_list *my_reloc_list, **rp, *r;
|
struct reloc_list *my_reloc_list, **rp, *r;
|
arelent **relocs;
|
arelent **relocs;
|
fixS *fixp;
|
fixS *fixp;
|
|
fragS *last_frag;
|
|
|
/* If seginfo is NULL, we did not create this section; don't do
|
/* If seginfo is NULL, we did not create this section; don't do
|
anything with it. */
|
anything with it. */
|
if (seginfo == NULL)
|
if (seginfo == NULL)
|
return;
|
return;
|
Line 1186... |
Line 1221... |
rp = &r->next;
|
rp = &r->next;
|
}
|
}
|
|
|
relocs = (arelent **) xcalloc (n, sizeof (arelent *));
|
relocs = (arelent **) xcalloc (n, sizeof (arelent *));
|
|
|
i = 0;
|
n = 0;
|
|
r = my_reloc_list;
|
|
last_frag = NULL;
|
for (fixp = seginfo->fix_root; fixp != (fixS *) NULL; fixp = fixp->fx_next)
|
for (fixp = seginfo->fix_root; fixp != (fixS *) NULL; fixp = fixp->fx_next)
|
{
|
{
|
int j;
|
|
int fx_size, slack;
|
int fx_size, slack;
|
offsetT loc;
|
offsetT loc;
|
|
arelent **reloc;
|
|
#ifndef RELOC_EXPANSION_POSSIBLE
|
|
arelent *rel;
|
|
|
|
reloc = &rel;
|
|
#endif
|
|
|
if (fixp->fx_done)
|
if (fixp->fx_done)
|
continue;
|
continue;
|
|
|
fx_size = fixp->fx_size;
|
fx_size = fixp->fx_size;
|
Line 1206... |
Line 1248... |
if (slack >= 0 && loc > fixp->fx_frag->fr_fix)
|
if (slack >= 0 && loc > fixp->fx_frag->fr_fix)
|
as_bad_where (fixp->fx_file, fixp->fx_line,
|
as_bad_where (fixp->fx_file, fixp->fx_line,
|
_("internal error: fixup not contained within frag"));
|
_("internal error: fixup not contained within frag"));
|
|
|
#ifndef RELOC_EXPANSION_POSSIBLE
|
#ifndef RELOC_EXPANSION_POSSIBLE
|
{
|
*reloc = tc_gen_reloc (sec, fixp);
|
arelent *reloc = tc_gen_reloc (sec, fixp);
|
|
|
|
if (!reloc)
|
|
continue;
|
|
relocs[i++] = reloc;
|
|
j = 1;
|
|
}
|
|
#else
|
#else
|
{
|
reloc = tc_gen_reloc (sec, fixp);
|
arelent **reloc = tc_gen_reloc (sec, fixp);
|
#endif
|
|
|
for (j = 0; reloc[j]; j++)
|
while (*reloc)
|
relocs[i++] = reloc[j];
|
{
|
|
while (r != NULL && r->u.b.r.address < (*reloc)->address)
|
|
{
|
|
fragS *f = get_frag_for_reloc (last_frag, seginfo, r);
|
|
if (f != NULL)
|
|
{
|
|
last_frag = f;
|
|
relocs[n++] = &r->u.b.r;
|
|
install_reloc (sec, &r->u.b.r, f, r->file, r->line);
|
|
}
|
|
r = r->next;
|
}
|
}
|
|
relocs[n++] = *reloc;
|
|
install_reloc (sec, *reloc, fixp->fx_frag,
|
|
fixp->fx_file, fixp->fx_line);
|
|
#ifndef RELOC_EXPANSION_POSSIBLE
|
|
break;
|
|
#else
|
|
reloc++;
|
#endif
|
#endif
|
|
}
|
|
}
|
|
|
for ( ; j != 0; --j)
|
while (r != NULL)
|
install_reloc (sec, relocs[i - j], fixp->fx_frag,
|
{
|
fixp->fx_file, fixp->fx_line);
|
fragS *f = get_frag_for_reloc (last_frag, seginfo, r);
|
|
if (f != NULL)
|
|
{
|
|
last_frag = f;
|
|
relocs[n++] = &r->u.b.r;
|
|
install_reloc (sec, &r->u.b.r, f, r->file, r->line);
|
|
}
|
|
r = r->next;
|
}
|
}
|
n = i;
|
|
|
|
#ifdef DEBUG4
|
#ifdef DEBUG4
|
{
|
{
|
unsigned int i, j, nsyms;
|
unsigned int k, j, nsyms;
|
asymbol **sympp;
|
asymbol **sympp;
|
sympp = bfd_get_outsymbols (stdoutput);
|
sympp = bfd_get_outsymbols (stdoutput);
|
nsyms = bfd_get_symcount (stdoutput);
|
nsyms = bfd_get_symcount (stdoutput);
|
for (i = 0; i < n; i++)
|
for (k = 0; k < n; k++)
|
if (((*relocs[i]->sym_ptr_ptr)->flags & BSF_SECTION_SYM) == 0)
|
if (((*relocs[k]->sym_ptr_ptr)->flags & BSF_SECTION_SYM) == 0)
|
{
|
{
|
for (j = 0; j < nsyms; j++)
|
for (j = 0; j < nsyms; j++)
|
if (sympp[j] == *relocs[i]->sym_ptr_ptr)
|
if (sympp[j] == *relocs[k]->sym_ptr_ptr)
|
break;
|
break;
|
if (j == nsyms)
|
if (j == nsyms)
|
abort ();
|
abort ();
|
}
|
}
|
}
|
}
|
#endif
|
#endif
|
|
|
for (r = my_reloc_list; r != NULL; r = r->next)
|
|
{
|
|
fragS *f;
|
|
for (f = seginfo->frchainP->frch_root; f; f = f->fr_next)
|
|
if (f->fr_address <= r->u.b.r.address
|
|
&& r->u.b.r.address < f->fr_address + f->fr_fix)
|
|
break;
|
|
if (f == NULL)
|
|
as_bad_where (r->file, r->line,
|
|
_("reloc not within (fixed part of) section"));
|
|
else
|
|
{
|
|
relocs[n++] = &r->u.b.r;
|
|
install_reloc (sec, &r->u.b.r, f, r->file, r->line);
|
|
}
|
|
}
|
|
|
|
if (n)
|
if (n)
|
{
|
{
|
flagword flags = bfd_get_section_flags (abfd, sec);
|
flagword flags = bfd_get_section_flags (abfd, sec);
|
flags |= SEC_RELOC;
|
flags |= SEC_RELOC;
|
bfd_set_section_flags (abfd, sec, flags);
|
bfd_set_section_flags (abfd, sec, flags);
|
Line 1278... |
Line 1321... |
SET_SECTION_RELOCS (sec, relocs, n);
|
SET_SECTION_RELOCS (sec, relocs, n);
|
#endif
|
#endif
|
|
|
#ifdef DEBUG3
|
#ifdef DEBUG3
|
{
|
{
|
unsigned int i;
|
unsigned int k;
|
arelent *r;
|
|
asymbol *s;
|
|
fprintf (stderr, "relocs for sec %s\n", sec->name);
|
fprintf (stderr, "relocs for sec %s\n", sec->name);
|
for (i = 0; i < n; i++)
|
for (k = 0; k < n; k++)
|
{
|
{
|
r = relocs[i];
|
arelent *rel = relocs[k];
|
s = *r->sym_ptr_ptr;
|
asymbol *s = *rel->sym_ptr_ptr;
|
fprintf (stderr, " reloc %2d @%p off %4lx : sym %-10s addend %lx\n",
|
fprintf (stderr, " reloc %2d @%p off %4lx : sym %-10s addend %lx\n",
|
i, r, (unsigned long)r->address, s->name, (unsigned long)r->addend);
|
k, rel, (unsigned long)rel->address, s->name,
|
|
(unsigned long)rel->addend);
|
}
|
}
|
}
|
}
|
#endif
|
#endif
|
}
|
}
|
|
|