/* BFD semi-generic back-end for a.out binaries.
- Copyright 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+ Copyright 1990, 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
Written by Cygnus Support.
This file is part of BFD, the Binary File Descriptor library.
#define TABLE_SIZE(TABLE) (sizeof(TABLE)/sizeof(TABLE[0]))
-CONST struct reloc_howto_struct *
+reloc_howto_type *
NAME(aout,reloc_type_lookup) (abfd,code)
bfd *abfd;
bfd_reloc_code_real_type code;
EXT (BFD_RELOC_SPARC_WDISP22, 7);
EXT (BFD_RELOC_SPARC13, 10);
EXT (BFD_RELOC_SPARC_BASE13, 15);
- default: return (CONST struct reloc_howto_struct *) 0;
+ default: return (reloc_howto_type *) NULL;
}
else
/* std relocs */
STD (BFD_RELOC_32_PCREL, 6);
STD (BFD_RELOC_16_BASEREL, 9);
STD (BFD_RELOC_32_BASEREL, 10);
- default: return (CONST struct reloc_howto_struct *) 0;
+ default: return (reloc_howto_type *) NULL;
}
}
result = (*callback_to_real_object_p)(abfd);
-#ifdef STAT_FOR_EXEC
- /* The original heuristic doesn't work in some important cases. The
- * a.out file has no information about the text start address. For
- * files (like kernels) linked to non-standard addresses (ld -Ttext
- * nnn) the entry point may not be between the default text start
- * (obj_textsec(abfd)->vma) and (obj_textsec(abfd)->vma) + text size
- * This is not just a mach issue. Many kernels are loaded at non
- * standard addresses.
- */
- {
- struct stat stat_buf;
- if (abfd->iostream
- && (fstat(fileno((FILE *) (abfd->iostream)), &stat_buf) == 0)
- && ((stat_buf.st_mode & 0111) != 0))
- abfd->flags |= EXEC_P;
- }
-#else /* ! defined (STAT_FOR_EXEC) */
/* Now that the segment addresses have been worked out, take a better
guess at whether the file is executable. If the entry point
is within the text segment, assume it is. (This makes files
executable even if their entry point address is 0, as long as
- their text starts at zero.)
-
- At some point we should probably break down and stat the file and
- declare it executable if (one of) its 'x' bits are on... */
+ their text starts at zero.). */
if ((execp->a_entry >= obj_textsec(abfd)->vma) &&
(execp->a_entry < obj_textsec(abfd)->vma + obj_textsec(abfd)->_raw_size))
abfd->flags |= EXEC_P;
-#endif /* ! defined (STAT_FOR_EXEC) */
+#ifdef STAT_FOR_EXEC
+ else
+ {
+ struct stat stat_buf;
+
+ /* The original heuristic doesn't work in some important cases.
+ The a.out file has no information about the text start
+ address. For files (like kernels) linked to non-standard
+ addresses (ld -Ttext nnn) the entry point may not be between
+ the default text start (obj_textsec(abfd)->vma) and
+ (obj_textsec(abfd)->vma) + text size. This is not just a mach
+ issue. Many kernels are loaded at non standard addresses. */
+ if (abfd->iostream
+ && (fstat(fileno((FILE *) (abfd->iostream)), &stat_buf) == 0)
+ && ((stat_buf.st_mode & 0111) != 0))
+ abfd->flags |= EXEC_P;
+ }
+#endif /* STAT_FOR_EXEC */
+
if (result)
{
#if 0 /* These should be set correctly anyways. */
if (machine == 0) arch_flags = M_29K;
break;
+ case bfd_arch_arm:
+ if (machine == 0) arch_flags = M_ARM;
+ break;
+
case bfd_arch_mips:
switch (machine) {
case 0:
}
break;
+ case bfd_arch_vax:
+ *unknown = false;
+ break;
+
+ /* start-sanitize-rce */
+ case bfd_arch_rce:
+ arch_flags = M_RCE;
+ break;
+ /* end-sanitize-rce */
+
default:
arch_flags = M_UNKNOWN;
}
/* Text. */
obj_textsec(abfd)->filepos = pos;
+ if (!obj_textsec(abfd)->user_set_vma)
+ obj_textsec(abfd)->vma = vma;
+ else
+ vma = obj_textsec(abfd)->vma;
+
pos += obj_textsec(abfd)->_raw_size;
vma += obj_textsec(abfd)->_raw_size;
vma += pad;
obj_datasec(abfd)->vma = vma;
}
+ else
+ vma = obj_datasec(abfd)->vma;
obj_datasec(abfd)->filepos = pos;
pos += obj_datasec(abfd)->_raw_size;
vma += obj_datasec(abfd)->_raw_size;
file_ptr text_end;
bfd_size_type text_size;
- if (abfd->output_has_begun == false)
- {
- if (NAME(aout,adjust_sizes_and_vmas) (abfd,
- &text_size,
- &text_end) == false)
- return false;
- }
+ if (! abfd->output_has_begun)
+ {
+ if (! NAME(aout,adjust_sizes_and_vmas) (abfd, &text_size, &text_end))
+ return false;
+ }
- /* regardless, once we know what we're doing, we might as well get going */
- if (section != obj_bsssec(abfd))
- {
- if (bfd_seek (abfd, section->filepos + offset, SEEK_SET) != 0)
- return false;
+ if (section == obj_bsssec (abfd))
+ {
+ bfd_set_error (bfd_error_no_contents);
+ return false;
+ }
+
+ if (section != obj_textsec (abfd)
+ && section != obj_datasec (abfd))
+ {
+ bfd_set_error (bfd_error_nonrepresentable_section);
+ return false;
+ }
+
+ if (count != 0)
+ {
+ if (bfd_seek (abfd, section->filepos + offset, SEEK_SET) != 0
+ || bfd_write (location, 1, count, abfd) != count)
+ return false;
+ }
- if (count) {
- return (bfd_write ((PTR)location, 1, count, abfd) == count) ?
- true : false;
- }
- return true;
- }
return true;
}
\f
in->desc = bfd_h_get_16 (abfd, ext->e_desc);
in->other = bfd_h_get_8 (abfd, ext->e_other);
in->type = bfd_h_get_8 (abfd, ext->e_type);
- in->symbol.udata = 0;
+ in->symbol.udata.p = NULL;
if (! translate_from_native_sym_flags (abfd, in))
return false;
if (! aout_get_external_symbols (abfd))
return false;
- if (obj_aout_external_sym_count (abfd) == 0)
- {
- bfd_set_error (bfd_error_no_symbols);
- return false;
- }
-
cached_size = (obj_aout_external_sym_count (abfd)
* sizeof (aout_symbol_type));
cached = (aout_symbol_type *) malloc (cached_size);
- if (cached == NULL)
+ if (cached == NULL && cached_size != 0)
{
bfd_set_error (bfd_error_no_memory);
return false;
}
- memset (cached, 0, cached_size);
+ if (cached_size != 0)
+ memset (cached, 0, cached_size);
/* Convert from external symbol information to internal. */
if (! (NAME(aout,translate_symbol_table)
bfd_size_type index;
/* An index of 0 always means the empty string. */
- if (*str == '\0')
+ if (str == 0 || *str == '\0')
return 0;
/* Don't hash if BFD_TRADITIONAL_FORMAT is set, because SunOS dbx
} \
void
-NAME(aout,swap_ext_reloc_in) (abfd, bytes, cache_ptr, symbols)
+NAME(aout,swap_ext_reloc_in) (abfd, bytes, cache_ptr, symbols, symcount)
bfd *abfd;
struct reloc_ext_external *bytes;
arelent *cache_ptr;
asymbol **symbols;
+ bfd_size_type symcount;
{
int r_index;
int r_extern;
}
cache_ptr->howto = howto_table_ext + r_type;
+
+ /* Base relative relocs are always against the symbol table,
+ regardless of the setting of r_extern. r_extern just reflects
+ whether the symbol the reloc is against is local or global. */
+ if (r_type == RELOC_BASE10
+ || r_type == RELOC_BASE13
+ || r_type == RELOC_BASE22)
+ r_extern = 1;
+
+ if (r_extern && r_index > symcount)
+ {
+ /* We could arrange to return an error, but it might be useful
+ to see the file even if it is bad. */
+ r_extern = 0;
+ r_index = N_ABS;
+ }
+
MOVE_ADDRESS(GET_SWORD(abfd, bytes->r_addend));
}
void
-NAME(aout,swap_std_reloc_in) (abfd, bytes, cache_ptr, symbols)
+NAME(aout,swap_std_reloc_in) (abfd, bytes, cache_ptr, symbols, symcount)
bfd *abfd;
struct reloc_std_external *bytes;
arelent *cache_ptr;
asymbol **symbols;
+ bfd_size_type symcount;
{
int r_index;
int r_extern;
cache_ptr->howto = howto_table_std + howto_idx;
BFD_ASSERT (cache_ptr->howto->type != -1);
+ /* Base relative relocs are always against the symbol table,
+ regardless of the setting of r_extern. r_extern just reflects
+ whether the symbol the reloc is against is local or global. */
+ if (r_baserel)
+ r_extern = 1;
+
+ if (r_extern && r_index > symcount)
+ {
+ /* We could arrange to return an error, but it might be useful
+ to see the file even if it is bad. */
+ r_extern = 0;
+ r_index = N_ABS;
+ }
+
MOVE_ADDRESS(0);
}
(struct reloc_ext_external *) relocs;
for (; counter < count; counter++, rptr++, cache_ptr++)
- NAME(aout,swap_ext_reloc_in) (abfd, rptr, cache_ptr, symbols);
+ NAME(aout,swap_ext_reloc_in) (abfd, rptr, cache_ptr, symbols,
+ bfd_get_symcount (abfd));
}
else
{
(struct reloc_std_external *) relocs;
for (; counter < count; counter++, rptr++, cache_ptr++)
- MY_swap_std_reloc_in(abfd, rptr, cache_ptr, symbols);
+ MY_swap_std_reloc_in (abfd, rptr, cache_ptr, symbols,
+ bfd_get_symcount (abfd));
}
free (relocs);
bfd *abfd;
struct bfd_link_info *info;
{
+ bfd *first;
+
switch (bfd_get_format (abfd))
{
case bfd_object:
return aout_link_add_object_symbols (abfd, info);
case bfd_archive:
+ first = bfd_openr_next_archived_file (abfd, (bfd *) NULL);
+ if (first == NULL)
+ return false;
+ if (! bfd_check_format (first, bfd_object))
+ return false;
+ if (bfd_get_flavour (first) != bfd_target_aout_flavour)
+ {
+ /* On Linux, we may have an ELF archive which got recognized
+ as an a.out archive. Therefore, we treat all archives as
+ though they were actually of the flavour of their first
+ element. */
+ return (*first->xvec->_bfd_link_add_symbols) (abfd, info);
+ }
return _bfd_generic_link_add_archive_symbols
(abfd, info, aout_link_check_archive_element);
default:
/* Turn the current link symbol into a common
symbol. It is already on the undefs list. */
h->type = bfd_link_hash_common;
+ h->u.c.p = ((struct bfd_link_hash_common_entry *)
+ bfd_hash_allocate (&info->hash->table,
+ sizeof (struct bfd_link_hash_common_entry)));
+ if (h->u.c.p == NULL)
+ return false;
+
h->u.c.size = value;
- if (h->u.c.size != value)
- {
- /* The size did not fit in the bitfield. */
- bfd_set_error (bfd_error_bad_value);
- return false;
- }
/* FIXME: This isn't quite right. The maximum
alignment of a common symbol should be set by the
power = bfd_log2 (value);
if (power > bfd_get_arch_info (abfd)->section_align_power)
power = bfd_get_arch_info (abfd)->section_align_power;
- h->u.c.alignment_power = power;
+ h->u.c.p->alignment_power = power;
- h->u.c.section = bfd_make_section_old_way (symbfd,
- "COMMON");
+ h->u.c.p->section = bfd_make_section_old_way (symbfd,
+ "COMMON");
}
else
{
This isn't quite right: it should use the architecture of the
output file, not the input files. */
if ((*sym_hash)->root.type == bfd_link_hash_common
- && ((*sym_hash)->root.u.c.alignment_power >
+ && ((*sym_hash)->root.u.c.p->alignment_power >
bfd_get_arch_info (abfd)->section_align_power))
- (*sym_hash)->root.u.c.alignment_power =
+ (*sym_hash)->root.u.c.p->alignment_power =
bfd_get_arch_info (abfd)->section_align_power;
/* If this is a set symbol, and we are not building sets, then
}
}
- sz = bfd_section_size (sub, obj_textsec (sub));
- if (sz > max_contents_size)
- max_contents_size = sz;
- sz = bfd_section_size (sub, obj_datasec (sub));
- if (sz > max_contents_size)
- max_contents_size = sz;
-
- sz = exec_hdr (sub)->a_trsize;
- if (sz > max_relocs_size)
- max_relocs_size = sz;
- sz = exec_hdr (sub)->a_drsize;
- if (sz > max_relocs_size)
- max_relocs_size = sz;
-
- sz = obj_aout_external_sym_count (sub);
- if (sz > max_sym_count)
- max_sym_count = sz;
+ if (bfd_get_flavour (sub) == bfd_target_aout_flavour)
+ {
+ sz = bfd_section_size (sub, obj_textsec (sub));
+ if (sz > max_contents_size)
+ max_contents_size = sz;
+ sz = bfd_section_size (sub, obj_datasec (sub));
+ if (sz > max_contents_size)
+ max_contents_size = sz;
+
+ sz = exec_hdr (sub)->a_trsize;
+ if (sz > max_relocs_size)
+ max_relocs_size = sz;
+ sz = exec_hdr (sub)->a_drsize;
+ if (sz > max_relocs_size)
+ max_relocs_size = sz;
+
+ sz = obj_aout_external_sym_count (sub);
+ if (sz > max_sym_count)
+ max_sym_count = sz;
+ }
}
if (info->relocateable)
struct aout_link_hash_entry **sym_hash;
int *symbol_map;
boolean pass;
- boolean skip_indirect;
+ boolean skip_next;
output_bfd = finfo->output_bfd;
sym_count = obj_aout_external_sym_count (input_bfd);
}
pass = false;
- skip_indirect = false;
+ skip_next = false;
sym = obj_aout_external_syms (input_bfd);
sym_end = sym + sym_count;
sym_hash = obj_aout_sym_hashes (input_bfd);
val = GET_WORD (input_bfd, sym->e_value);
pass = false;
}
- else if (skip_indirect)
+ else if (skip_next)
{
/* Skip this symbol, which is the target of an indirect
symbol that we have changed to no longer be an indirect
symbol. */
- skip_indirect = false;
+ skip_next = false;
continue;
}
else
&& h->root.type != bfd_link_hash_warning
&& h->written)
{
- if ((type & N_TYPE) == N_INDR)
- skip_indirect = true;
+ if ((type & N_TYPE) == N_INDR
+ || type == N_WARNING)
+ skip_next = true;
*symbol_map = h->indx;
continue;
}
else if (((type & N_TYPE) == N_INDR
&& (hresolve == (struct aout_link_hash_entry *) NULL
|| (hresolve->root.type != bfd_link_hash_defined
+ && hresolve->root.type != bfd_link_hash_defweak
&& hresolve->root.type != bfd_link_hash_common)))
|| type == N_WARNING)
{
a case we do not want to output the next symbol,
which is the target of the indirection. */
if ((type & N_TYPE) == N_INDR)
- skip_indirect = true;
+ skip_next = true;
symsec = NULL;
break;
}
}
- else if (hresolve->root.type == bfd_link_hash_defined)
+ else if (hresolve->root.type == bfd_link_hash_defined
+ || hresolve->root.type == bfd_link_hash_defweak)
{
asection *input_section;
asection *output_section;
- /* This case means a common symbol which was turned
- into a defined symbol. */
+ /* This case usually means a common symbol which was
+ turned into a defined symbol. */
input_section = hresolve->root.u.def.section;
output_section = input_section->output_section;
BFD_ASSERT (bfd_is_abs_section (output_section)
type &=~ N_TYPE;
if (output_section == obj_textsec (output_bfd))
- type |= N_TEXT;
+ type |= (hresolve->root.type == bfd_link_hash_defined
+ ? N_TEXT
+ : N_WEAKT);
else if (output_section == obj_datasec (output_bfd))
- type |= N_DATA;
+ type |= (hresolve->root.type == bfd_link_hash_defined
+ ? N_DATA
+ : N_WEAKD);
else if (output_section == obj_bsssec (output_bfd))
- type |= N_BSS;
+ type |= (hresolve->root.type == bfd_link_hash_defined
+ ? N_BSS
+ : N_WEAKB);
else
- type |= N_ABS;
+ type |= (hresolve->root.type == bfd_link_hash_defined
+ ? N_ABS
+ : N_WEAKA);
}
else if (hresolve->root.type == bfd_link_hash_common)
val = hresolve->root.u.c.size;
- else if (hresolve->root.type == bfd_link_hash_weak)
+ else if (hresolve->root.type == bfd_link_hash_undefweak)
{
val = 0;
type = N_WEAKU;
h->written = true;
- if (finfo->info->strip == strip_all
- || (finfo->info->strip == strip_some
- && bfd_hash_lookup (finfo->info->keep_hash, h->root.root.string,
- false, false) == NULL))
+ /* An indx of -2 means the symbol must be written. */
+ if (h->indx != -2
+ && (finfo->info->strip == strip_all
+ || (finfo->info->strip == strip_some
+ && bfd_hash_lookup (finfo->info->keep_hash, h->root.root.string,
+ false, false) == NULL)))
return true;
switch (h->root.type)
val = 0;
break;
case bfd_link_hash_defined:
+ case bfd_link_hash_defweak:
{
asection *sec;
BFD_ASSERT (bfd_is_abs_section (sec)
|| sec->owner == output_bfd);
if (sec == obj_textsec (output_bfd))
- type = N_TEXT | N_EXT;
+ type = h->root.type == bfd_link_hash_defined ? N_TEXT : N_WEAKT;
else if (sec == obj_datasec (output_bfd))
- type = N_DATA | N_EXT;
+ type = h->root.type == bfd_link_hash_defined ? N_DATA : N_WEAKD;
else if (sec == obj_bsssec (output_bfd))
- type = N_BSS | N_EXT;
+ type = h->root.type == bfd_link_hash_defined ? N_BSS : N_WEAKB;
else
- type = N_ABS | N_EXT;
+ type = h->root.type == bfd_link_hash_defined ? N_ABS : N_WEAKA;
+ type |= N_EXT;
val = (h->root.u.def.value
+ sec->vma
+ h->root.u.def.section->output_offset);
type = N_UNDF | N_EXT;
val = h->root.u.c.size;
break;
- case bfd_link_hash_weak:
+ case bfd_link_hash_undefweak:
type = N_WEAKU;
val = 0;
case bfd_link_hash_indirect:
else
{
relocs = finfo->relocs;
- if (bfd_seek (input_bfd, input_section->rel_filepos, SEEK_SET) != 0
- || bfd_read (relocs, 1, rel_size, input_bfd) != rel_size)
- return false;
+ if (rel_size > 0)
+ {
+ if (bfd_seek (input_bfd, input_section->rel_filepos, SEEK_SET) != 0
+ || bfd_read (relocs, 1, rel_size, input_bfd) != rel_size)
+ return false;
+ }
}
/* Relocate the section contents. */
/* If we are producing relocateable output, the relocs were
modified, and we now write them out. */
- if (finfo->info->relocateable)
+ if (finfo->info->relocateable && rel_size > 0)
{
if (bfd_seek (finfo->output_bfd, *reloff_ptr, SEEK_SET) != 0)
return false;
is what the native linker does. */
h = sym_hashes[r_index];
if (h != (struct aout_link_hash_entry *) NULL
- && h->root.type == bfd_link_hash_defined)
+ && (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak))
{
asection *output_section;
if (r_index == -1)
{
- const char *name;
-
- name = strings + GET_WORD (input_bfd,
- syms[r_index].e_strx);
- if (! ((*finfo->info->callbacks->unattached_reloc)
- (finfo->info, name, input_bfd, input_section,
- r_addr)))
- return false;
- r_index = 0;
+ if (h != NULL)
+ {
+ /* We decided to strip this symbol, but it
+ turns out that we can't. Note that we
+ lose the other and desc information here.
+ I don't think that will ever matter for a
+ global symbol. */
+ if (h->indx < 0)
+ {
+ h->indx = -2;
+ h->written = false;
+ if (! aout_link_write_other_symbol (h,
+ (PTR) finfo))
+ return false;
+ }
+ r_index = h->indx;
+ }
+ else
+ {
+ const char *name;
+
+ name = strings + GET_WORD (input_bfd,
+ syms[r_index].e_strx);
+ if (! ((*finfo->info->callbacks->unattached_reloc)
+ (finfo->info, name, input_bfd, input_section,
+ r_addr)))
+ return false;
+ r_index = 0;
+ }
}
relocation = 0;
}
if (h != (struct aout_link_hash_entry *) NULL
- && h->root.type == bfd_link_hash_defined)
+ && (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak))
{
relocation = (h->root.u.def.value
+ h->root.u.def.section->output_section->vma
+ h->root.u.def.section->output_offset);
}
else if (h != (struct aout_link_hash_entry *) NULL
- && h->root.type == bfd_link_hash_weak)
+ && h->root.type == bfd_link_hash_undefweak)
relocation = 0;
else
{
is what the native linker does. */
h = sym_hashes[r_index];
if (h != (struct aout_link_hash_entry *) NULL
- && h->root.type == bfd_link_hash_defined)
+ && (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak))
{
asection *output_section;
if (r_index == -1)
{
- const char *name;
-
- name = (strings
- + GET_WORD (input_bfd, syms[r_index].e_strx));
- if (! ((*finfo->info->callbacks->unattached_reloc)
- (finfo->info, name, input_bfd, input_section,
- r_addr)))
- return false;
- r_index = 0;
+ if (h != NULL)
+ {
+ /* We decided to strip this symbol, but it
+ turns out that we can't. Note that we
+ lose the other and desc information here.
+ I don't think that will ever matter for a
+ global symbol. */
+ if (h->indx < 0)
+ {
+ h->indx = -2;
+ h->written = false;
+ if (! aout_link_write_other_symbol (h,
+ (PTR) finfo))
+ return false;
+ }
+ r_index = h->indx;
+ }
+ else
+ {
+ const char *name;
+
+ name = strings + GET_WORD (input_bfd,
+ syms[r_index].e_strx);
+ if (! ((*finfo->info->callbacks->unattached_reloc)
+ (finfo->info, name, input_bfd, input_section,
+ r_addr)))
+ return false;
+ r_index = 0;
+ }
}
relocation = 0;
}
if (h != (struct aout_link_hash_entry *) NULL
- && h->root.type == bfd_link_hash_defined)
+ && (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak))
{
relocation = (h->root.u.def.value
+ h->root.u.def.section->output_section->vma
+ h->root.u.def.section->output_offset);
}
else if (h != (struct aout_link_hash_entry *) NULL
- && h->root.type == bfd_link_hash_weak)
+ && h->root.type == bfd_link_hash_undefweak)
relocation = 0;
else
{
struct bfd_link_order_reloc *pr;
int r_index;
int r_extern;
- const reloc_howto_type *howto;
+ reloc_howto_type *howto;
file_ptr *reloff_ptr;
struct reloc_std_external srel;
struct reloc_ext_external erel;
h = aout_link_hash_lookup (aout_hash_table (finfo->info),
pr->u.name, false, false, true);
if (h != (struct aout_link_hash_entry *) NULL
- && h->indx == -1)
+ && h->indx >= 0)
r_index = h->indx;
+ else if (h != NULL)
+ {
+ /* We decided to strip this symbol, but it turns out that we
+ can't. Note that we lose the other and desc information
+ here. I don't think that will ever matter for a global
+ symbol. */
+ h->indx = -2;
+ h->written = false;
+ if (! aout_link_write_other_symbol (h, (PTR) finfo))
+ return false;
+ r_index = h->indx;
+ }
else
{
if (! ((*finfo->info->callbacks->unattached_reloc)
}
howto = bfd_reloc_type_lookup (finfo->output_bfd, pr->reloc);
- if (howto == (const reloc_howto_type *) NULL)
+ if (howto == 0)
{
bfd_set_error (bfd_error_bad_value);
return false;