/* BFD back-end for linux flavored i386 a.out binaries.
- Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc.
+ Copyright 1992, 1993, 1994, 1995, 1996, 1997, 2001, 2002, 2003
+ Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
-Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-#define PAGE_SIZE 4096
+#define TARGET_PAGE_SIZE 4096
#define ZMAGIC_DISK_BLOCK_SIZE 1024
-#define SEGMENT_SIZE 4096
+#define SEGMENT_SIZE TARGET_PAGE_SIZE
#define TEXT_START_ADDR 0x0
#define N_SHARED_LIB(x) 0
-#define BYTES_IN_WORD 4
+
+#define MACHTYPE_OK(mtype) ((mtype) == M_386 || (mtype) == M_UNKNOWN)
#include "bfd.h"
#include "sysdep.h"
#include "libaout.h" /* BFD a.out internal data structures */
#define DEFAULT_ARCH bfd_arch_i386
-#define MY(OP) CAT(i386linux_,OP)
+
+/* Do not "beautify" the CONCAT* macro args. Traditional C will not
+ remove whitespace added here, and thus will fail to concatenate
+ the tokens. */
+#define MY(OP) CONCAT2 (i386linux_,OP)
#define TARGETNAME "a.out-i386-linux"
+extern const bfd_target MY(vec);
+
/* We always generate QMAGIC files in preference to ZMAGIC files. It
would be possible to make this a linker option, if that ever
becomes important. */
static void MY_final_link_callback
PARAMS ((bfd *, file_ptr *, file_ptr *, file_ptr *));
+static bfd_boolean i386linux_bfd_final_link
+ PARAMS ((bfd *, struct bfd_link_info *));
+static bfd_boolean i386linux_write_object_contents PARAMS ((bfd *));
-static boolean
+static bfd_boolean
i386linux_bfd_final_link (abfd, info)
bfd *abfd;
struct bfd_link_info *info;
/* Set the machine type correctly. */
-static boolean
+static bfd_boolean
i386linux_write_object_contents (abfd)
bfd *abfd;
{
WRITE_HEADERS(abfd, execp);
- return true;
+ return TRUE;
}
#define MY_write_object_contents i386linux_write_object_contents
#define IS_PLT_SYM(name) \
(strncmp (name, PLT_REF_PREFIX, sizeof PLT_REF_PREFIX - 1) == 0)
+/* This string is used to generate specialized error messages. */
+
+#ifndef NEEDS_SHRLIB
+#define NEEDS_SHRLIB "__NEEDS_SHRLIB_"
+#endif
+
/* This special symbol is a set vector that contains a list of
pointers to fixup tables. It will be present in any dynamicly
linked file. The linker generated fixup table should also be added
static struct fixup *new_fixup
PARAMS ((struct bfd_link_info *, struct linux_link_hash_entry *,
bfd_vma, int));
-static boolean linux_link_create_dynamic_sections
+static bfd_boolean linux_link_create_dynamic_sections
PARAMS ((bfd *, struct bfd_link_info *));
-static boolean linux_add_one_symbol
+static bfd_boolean linux_add_one_symbol
PARAMS ((struct bfd_link_info *, bfd *, const char *, flagword, asection *,
- bfd_vma, const char *, boolean, boolean,
+ bfd_vma, const char *, bfd_boolean, bfd_boolean,
struct bfd_link_hash_entry **));
-static boolean linux_tally_symbols
+static bfd_boolean linux_tally_symbols
PARAMS ((struct linux_link_hash_entry *, PTR));
-static boolean linux_finish_dynamic_link
+static bfd_boolean linux_finish_dynamic_link
PARAMS ((bfd *, struct bfd_link_info *));
/* Routine to create an entry in an Linux link hash table. */
bfd *abfd;
{
struct linux_link_hash_table *ret;
+ bfd_size_type amt = sizeof (struct linux_link_hash_table);
- ret = ((struct linux_link_hash_table *)
- malloc (sizeof (struct linux_link_hash_table)));
+ ret = (struct linux_link_hash_table *) bfd_alloc (abfd, amt);
if (ret == (struct linux_link_hash_table *) NULL)
- {
- bfd_set_error (bfd_error_no_memory);
- return (struct bfd_link_hash_table *) NULL;
- }
+ return (struct bfd_link_hash_table *) NULL;
if (! NAME(aout,link_hash_table_init) (&ret->root, abfd,
linux_link_hash_newfunc))
{
#define linux_link_hash_traverse(table, func, info) \
(aout_link_hash_traverse \
(&(table)->root, \
- (boolean (*) PARAMS ((struct aout_link_hash_entry *, PTR))) (func), \
+ (bfd_boolean (*) PARAMS ((struct aout_link_hash_entry *, PTR))) (func), \
(info)))
/* Get the Linux link hash table from the info structure. This is
know the size of the section, but that's OK - we just need to
create it for now. */
-static boolean
+static bfd_boolean
linux_link_create_dynamic_sections (abfd, info)
bfd *abfd;
- struct bfd_link_info *info;
+ struct bfd_link_info *info ATTRIBUTE_UNUSED;
{
flagword flags;
register asection *s;
if (s == NULL
|| ! bfd_set_section_flags (abfd, s, flags)
|| ! bfd_set_section_alignment (abfd, s, 2))
- return false;
+ return FALSE;
s->_raw_size = 0;
s->contents = 0;
- return true;
+ return TRUE;
}
/* Function to add a single symbol to the linker hash table. This is
a wrapper around _bfd_generic_link_add_one_symbol which handles the
tweaking needed for dynamic linking support. */
-static boolean
+static bfd_boolean
linux_add_one_symbol (info, abfd, name, flags, section, value, string,
copy, collect, hashp)
struct bfd_link_info *info;
asection *section;
bfd_vma value;
const char *string;
- boolean copy;
- boolean collect;
+ bfd_boolean copy;
+ bfd_boolean collect;
struct bfd_link_hash_entry **hashp;
{
struct linux_link_hash_entry *h;
- boolean insert;
+ bfd_boolean insert;
/* Look up and see if we already have this symbol in the hash table.
If we do, and the defining entry is from a shared library, we
be able to link Linux a.out and ELF objects together, but serious
confusion is possible. */
- insert = false;
+ insert = FALSE;
- if (! info->relocateable
+ if (! info->relocatable
&& linux_hash_table (info)->dynobj == NULL
&& strcmp (name, SHARABLE_CONFLICTS) == 0
- && (flags & BSF_CONSTRUCTOR) != 0)
+ && (flags & BSF_CONSTRUCTOR) != 0
+ && abfd->xvec == info->hash->creator)
{
if (! linux_link_create_dynamic_sections (abfd, info))
- return false;
+ return FALSE;
linux_hash_table (info)->dynobj = abfd;
- insert = true;
+ insert = TRUE;
}
if (bfd_is_abs_section (section)
- && (IS_GOT_SYM (name) || IS_PLT_SYM (name)))
+ && abfd->xvec == info->hash->creator)
{
- h = linux_link_hash_lookup (linux_hash_table (info), name, false,
- false, false);
+ h = linux_link_hash_lookup (linux_hash_table (info), name, FALSE,
+ FALSE, FALSE);
if (h != NULL
- && h->root.root.type == bfd_link_hash_defined)
+ && (h->root.root.type == bfd_link_hash_defined
+ || h->root.root.type == bfd_link_hash_defweak))
{
struct fixup *f;
f = new_fixup (info, h, value, ! IS_PLT_SYM (name));
if (f == NULL)
- return false;
+ return FALSE;
f->jump = IS_PLT_SYM (name);
- return true;
+ return TRUE;
}
}
if (! _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section,
value, string, copy, collect,
hashp))
- return false;
+ return FALSE;
/* Insert a pointer to our table in the set vector. The dynamic
linker requires this information */
if (! (_bfd_generic_link_add_one_symbol
(info, linux_hash_table (info)->dynobj, SHARABLE_CONFLICTS,
- BSF_GLOBAL | BSF_CONSTRUCTOR, s, 0, NULL, false, false, NULL)))
- return false;
+ BSF_GLOBAL | BSF_CONSTRUCTOR, s, (bfd_vma) 0, NULL,
+ FALSE, FALSE, NULL)))
+ return FALSE;
}
- return true;
+ return TRUE;
}
/* We will crawl the hash table and come here for every global symbol.
This function is called via linux_link_hash_traverse. */
-static boolean
+static bfd_boolean
linux_tally_symbols (h, data)
struct linux_link_hash_entry *h;
PTR data;
struct fixup *f, *f1;
int is_plt;
struct linux_link_hash_entry *h1, *h2;
- boolean exists;
+ bfd_boolean exists;
+
+ if (h->root.root.type == bfd_link_hash_warning)
+ h = (struct linux_link_hash_entry *) h->root.root.u.i.link;
+
+ if (h->root.root.type == bfd_link_hash_undefined
+ && strncmp (h->root.root.root.string, NEEDS_SHRLIB,
+ sizeof NEEDS_SHRLIB - 1) == 0)
+ {
+ const char *name;
+ char *p;
+ char *alloc = NULL;
+
+ name = h->root.root.root.string + sizeof NEEDS_SHRLIB - 1;
+ p = strrchr (name, '_');
+ if (p != NULL)
+ alloc = (char *) bfd_malloc ((bfd_size_type) strlen (name) + 1);
+
+ if (p == NULL || alloc == NULL)
+ (*_bfd_error_handler) (_("Output file requires shared library `%s'\n"),
+ name);
+ else
+ {
+ strcpy (alloc, name);
+ p = strrchr (alloc, '_');
+ *p++ = '\0';
+ (*_bfd_error_handler)
+ (_("Output file requires shared library `%s.so.%s'\n"),
+ alloc, p);
+ free (alloc);
+ }
+
+ abort ();
+ }
/* If this symbol is not a PLT/GOT, we do not even need to look at it */
is_plt = IS_PLT_SYM (h->root.root.root.string);
h1 = linux_link_hash_lookup (linux_hash_table (info),
(h->root.root.root.string
+ sizeof PLT_REF_PREFIX - 1),
- false, false, true);
+ FALSE, FALSE, TRUE);
/* h2 does not follow indirect symbols. */
- h2 = linux_link_hash_lookup (linux_hash_table (info),
+ h2 = linux_link_hash_lookup (linux_hash_table (info),
(h->root.root.root.string
+ sizeof PLT_REF_PREFIX - 1),
- false, false, false);
+ FALSE, FALSE, FALSE);
/* The real symbol must exist but if it is also an ABS symbol,
there is no need to have a fixup. This is because they both
fixup anyway, since there are cases where these symbols come
from different shared libraries */
if (h1 != NULL
- && ((h1->root.root.type == bfd_link_hash_defined
+ && (((h1->root.root.type == bfd_link_hash_defined
+ || h1->root.root.type == bfd_link_hash_defweak)
&& ! bfd_is_abs_section (h1->root.root.u.def.section))
|| h2->root.root.type == bfd_link_hash_indirect))
{
involving this symbol. If so, convert it to a regular
fixup. In the end, this relaxes some of the requirements
about the order of performing fixups. */
- exists = false;
+ exists = FALSE;
for (f1 = linux_hash_table (info)->fixup_list;
f1 != NULL;
f1 = f1->next)
{
- if (f1->h != h
+ if ((f1->h != h && f1->h != h1)
|| (! f1->builtin && ! f1->jump))
continue;
+ if (f1->h == h1)
+ exists = TRUE;
if (! exists
&& bfd_is_abs_section (h->root.root.u.def.section))
{
f1->h = h1;
f1->jump = is_plt;
f1->builtin = 0;
- exists = true;
+ exists = TRUE;
}
if (! exists
&& bfd_is_abs_section (h->root.root.u.def.section))
/* Quick and dirty way of stripping these symbols from the
symtab. */
if (bfd_is_abs_section (h->root.root.u.def.section))
- h->root.written = true;
+ h->root.written = TRUE;
}
- return true;
+ return TRUE;
}
/* This is called to set the size of the .linux-dynamic section is.
we just scan the hash tables to find out how many additional fixups
are required. */
-boolean
-bfd_linux_size_dynamic_sections (output_bfd, info)
+bfd_boolean
+bfd_i386linux_size_dynamic_sections (output_bfd, info)
bfd *output_bfd;
struct bfd_link_info *info;
{
struct fixup *f;
asection *s;
+ if (output_bfd->xvec != &MY(vec))
+ return TRUE;
+
/* First find the fixups... */
linux_link_hash_traverse (linux_hash_table (info),
linux_tally_symbols,
{
if (linux_hash_table (info)->fixup_count > 0)
abort ();
- return true;
+ return TRUE;
}
/* Allocate memory for our fixup table. We will fill it in later. */
".linux-dynamic");
if (s != NULL)
{
- s->_raw_size = 8 + linux_hash_table (info)->fixup_count * 8;
- s->contents = (bfd_byte *) bfd_alloc (output_bfd, s->_raw_size);
+ s->_raw_size = linux_hash_table (info)->fixup_count + 1;
+ s->_raw_size *= 8;
+ s->contents = (bfd_byte *) bfd_zalloc (output_bfd, s->_raw_size);
if (s->contents == NULL)
- {
- bfd_set_error (bfd_error_no_memory);
- return false;
- }
- memset (s->contents, 0, s->_raw_size);
+ return FALSE;
}
- return true;
+ return TRUE;
}
/* We come here once we are ready to actually write the fixup table to
the output file. Scan the fixup tables and so forth and generate
the stuff we need. */
-static boolean
+static bfd_boolean
linux_finish_dynamic_link (output_bfd, info)
bfd *output_bfd;
struct bfd_link_info *info;
struct fixup *f;
unsigned int new_addr;
int section_offset;
- int fixups_written;
+ unsigned int fixups_written;
if (linux_hash_table (info)->dynobj == NULL)
- return true;
+ return TRUE;
s = bfd_get_section_by_name (linux_hash_table (info)->dynobj,
".linux-dynamic");
fixups_written = 0;
#ifdef LINUX_LINK_DEBUG
- printf ("Fixup table file offset: %x VMA: %x\n",
+ printf ("Fixup table file offset: %x VMA: %x\n",
os->filepos + s->output_offset,
os->vma + s->output_offset);
#endif
fixup_table = s->contents;
- bfd_put_32 (output_bfd, linux_hash_table (info)->fixup_count, fixup_table);
+ bfd_put_32 (output_bfd,
+ (bfd_vma) linux_hash_table (info)->fixup_count, fixup_table);
fixup_table += 4;
/* Fill in fixup table. */
if (f->builtin)
continue;
- if (f->h->root.root.type != bfd_link_hash_defined)
+ if (f->h->root.root.type != bfd_link_hash_defined
+ && f->h->root.root.type != bfd_link_hash_defweak)
{
- /* FIXME! */
- fprintf (stderr,
- "Symbol %s not defined for fixups\n",
- f->h->root.root.root.string);
+ (*_bfd_error_handler)
+ (_("Symbol %s not defined for fixups\n"),
+ f->h->root.root.root.string);
continue;
}
if (f->jump)
{
/* Relative address */
- new_addr = new_addr - (f->value + 5);
- bfd_put_32 (output_bfd, new_addr, fixup_table);
+ new_addr = new_addr - (f->value + 5);
+ bfd_put_32 (output_bfd, (bfd_vma) new_addr, fixup_table);
fixup_table += 4;
bfd_put_32 (output_bfd, f->value + 1, fixup_table);
fixup_table += 4;
}
else
{
- bfd_put_32 (output_bfd, new_addr, fixup_table);
+ bfd_put_32 (output_bfd, (bfd_vma) new_addr, fixup_table);
fixup_table += 4;
bfd_put_32 (output_bfd, f->value, fixup_table);
fixup_table += 4;
if (linux_hash_table (info)->local_builtins != 0)
{
/* Special marker so we know to switch to the other type of fixup */
- bfd_put_32 (output_bfd, 0, fixup_table);
+ bfd_put_32 (output_bfd, (bfd_vma) 0, fixup_table);
fixup_table += 4;
- bfd_put_32 (output_bfd, 0, fixup_table);
+ bfd_put_32 (output_bfd, (bfd_vma) 0, fixup_table);
fixup_table += 4;
++fixups_written;
for (f = linux_hash_table (info)->fixup_list; f != NULL; f = f->next)
if (! f->builtin)
continue;
- if (f->h->root.root.type != bfd_link_hash_defined)
+ if (f->h->root.root.type != bfd_link_hash_defined
+ && f->h->root.root.type != bfd_link_hash_defweak)
{
- /* FIXME! */
- fprintf (stderr,
- "Symbol %s not defined for fixups\n",
- f->h->root.root.root.string);
+ (*_bfd_error_handler)
+ (_("Symbol %s not defined for fixups\n"),
+ f->h->root.root.root.string);
continue;
}
new_addr, f->value);
#endif
- bfd_put_32 (output_bfd, new_addr, fixup_table);
+ bfd_put_32 (output_bfd, (bfd_vma) new_addr, fixup_table);
fixup_table += 4;
bfd_put_32 (output_bfd, f->value, fixup_table);
fixup_table += 4;
if (linux_hash_table (info)->fixup_count != fixups_written)
{
- /* FIXME! */
- fprintf (stderr, "Warning: fixup count mismatch\n");
+ (*_bfd_error_handler) (_("Warning: fixup count mismatch\n"));
while (linux_hash_table (info)->fixup_count > fixups_written)
{
- bfd_put_32 (output_bfd, 0, fixup_table);
+ bfd_put_32 (output_bfd, (bfd_vma) 0, fixup_table);
fixup_table += 4;
- bfd_put_32 (output_bfd, 0, fixup_table);
+ bfd_put_32 (output_bfd, (bfd_vma) 0, fixup_table);
fixup_table += 4;
++fixups_written;
}
}
- h = linux_link_hash_lookup (linux_hash_table (info),
+ h = linux_link_hash_lookup (linux_hash_table (info),
"__BUILTIN_FIXUPS__",
- false, false, false);
+ FALSE, FALSE, FALSE);
- if (h != NULL && h->root.root.type == bfd_link_hash_defined)
+ if (h != NULL
+ && (h->root.root.type == bfd_link_hash_defined
+ || h->root.root.type == bfd_link_hash_defweak))
{
is = h->root.root.u.def.section;
section_offset = is->output_section->vma + is->output_offset;
printf ("Builtin fixup table at %x\n", new_addr);
#endif
- bfd_put_32 (output_bfd, new_addr, fixup_table);
+ bfd_put_32 (output_bfd, (bfd_vma) new_addr, fixup_table);
}
else
- bfd_put_32 (output_bfd, 0, fixup_table);
+ bfd_put_32 (output_bfd, (bfd_vma) 0, fixup_table);
- if (bfd_seek (output_bfd, os->filepos + s->output_offset, SEEK_SET) != 0)
- return false;
+ if (bfd_seek (output_bfd, (file_ptr) (os->filepos + s->output_offset),
+ SEEK_SET) != 0)
+ return FALSE;
- if (bfd_write ((PTR) s->contents, 1, s->_raw_size, output_bfd)
- != s->_raw_size)
- return false;
+ if (bfd_bwrite ((PTR) s->contents, s->_raw_size, output_bfd) != s->_raw_size)
+ return FALSE;
- return true;
+ return TRUE;
}
#define MY_bfd_link_hash_table_create linux_link_hash_table_create