Browse Source
* Many files: Add function prototypes. * cpu-m68k.c (bfd_default_scan_num_mach): Don't declare. * ecofflink.c: Include "libcoff.h" and "libecoff.h". * elf32-ppc.c (ppc_elf_fake_sections): Make static. * opncls.c (bfd_openstreamr): Change stream parameter to PTR. * peicode.h: Change several void * parameters to PTR. * srec.c (srec_get_symbol_info): Make static. * syms.c (bfd_symbol_is_absolute): Remove.gdb-4_18-branch
3 changed files with 803 additions and 11 deletions
@ -0,0 +1,770 @@ |
|||
/* BFD back-end for linux flavored m68k a.out binaries.
|
|||
Copyright (C) 1992, 93, 94, 95, 96, 1997 Free Software Foundation, Inc. |
|||
|
|||
This file is part of BFD, the Binary File Descriptor library. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; either version 2 of the License, or |
|||
(at your option) any later version. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ |
|||
|
|||
#define TARGET_PAGE_SIZE 4096 |
|||
#define ZMAGIC_DISK_BLOCK_SIZE 1024 |
|||
#define SEGMENT_SIZE TARGET_PAGE_SIZE |
|||
#define TEXT_START_ADDR 0x0 |
|||
#define N_SHARED_LIB(x) 0 |
|||
#define BYTES_IN_WORD 4 |
|||
|
|||
#include "bfd.h" |
|||
#include "sysdep.h" |
|||
#include "libbfd.h" |
|||
#include "aout/aout64.h" |
|||
#include "aout/stab_gnu.h" |
|||
#include "aout/ar.h" |
|||
#include "libaout.h" /* BFD a.out internal data structures */ |
|||
|
|||
#define TARGET_IS_BIG_ENDIAN_P |
|||
#define DEFAULT_ARCH bfd_arch_m68k |
|||
#define MY(OP) CAT(m68klinux_,OP) |
|||
#define TARGETNAME "a.out-m68k-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 boolean m68klinux_bfd_final_link |
|||
PARAMS ((bfd *, struct bfd_link_info *)); |
|||
static boolean m68klinux_write_object_contents PARAMS ((bfd *)); |
|||
|
|||
static boolean |
|||
m68klinux_bfd_final_link (abfd, info) |
|||
bfd *abfd; |
|||
struct bfd_link_info *info; |
|||
{ |
|||
obj_aout_subformat (abfd) = q_magic_format; |
|||
return NAME(aout,final_link) (abfd, info, MY_final_link_callback); |
|||
} |
|||
|
|||
#define MY_bfd_final_link m68klinux_bfd_final_link |
|||
|
|||
/* Set the machine type correctly. */ |
|||
|
|||
static boolean |
|||
m68klinux_write_object_contents (abfd) |
|||
bfd *abfd; |
|||
{ |
|||
struct external_exec exec_bytes; |
|||
struct internal_exec *execp = exec_hdr (abfd); |
|||
|
|||
N_SET_MACHTYPE (*execp, M_68020); |
|||
|
|||
obj_reloc_entry_size (abfd) = RELOC_STD_SIZE; |
|||
|
|||
WRITE_HEADERS(abfd, execp); |
|||
|
|||
return true; |
|||
} |
|||
|
|||
#define MY_write_object_contents m68klinux_write_object_contents |
|||
|
|||
/* Code to link against Linux a.out shared libraries. */ |
|||
|
|||
/* See if a symbol name is a reference to the global offset table. */ |
|||
|
|||
#ifndef GOT_REF_PREFIX |
|||
#define GOT_REF_PREFIX "__GOT_" |
|||
#endif |
|||
|
|||
#define IS_GOT_SYM(name) \ |
|||
(strncmp (name, GOT_REF_PREFIX, sizeof GOT_REF_PREFIX - 1) == 0) |
|||
|
|||
/* See if a symbol name is a reference to the procedure linkage table. */ |
|||
|
|||
#ifndef PLT_REF_PREFIX |
|||
#define PLT_REF_PREFIX "__PLT_" |
|||
#endif |
|||
|
|||
#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 |
|||
to the list, and it should always appear in the second slot (the |
|||
first one is a dummy with a magic number that is defined in |
|||
crt0.o). */ |
|||
|
|||
#ifndef SHARABLE_CONFLICTS |
|||
#define SHARABLE_CONFLICTS "__SHARABLE_CONFLICTS__" |
|||
#endif |
|||
|
|||
/* We keep a list of fixups. The terminology is a bit strange, but
|
|||
each fixup contains two 32 bit numbers. A regular fixup contains |
|||
an address and a pointer, and at runtime we should store the |
|||
address at the location pointed to by the pointer. A builtin fixup |
|||
contains two pointers, and we should read the address using one |
|||
pointer and store it at the location pointed to by the other |
|||
pointer. Builtin fixups come into play when we have duplicate |
|||
__GOT__ symbols for the same variable. The builtin fixup will copy |
|||
the GOT pointer from one over into the other. */ |
|||
|
|||
struct fixup |
|||
{ |
|||
struct fixup *next; |
|||
struct linux_link_hash_entry *h; |
|||
bfd_vma value; |
|||
|
|||
/* Nonzero if this is a jump instruction that needs to be fixed,
|
|||
zero if this is just a pointer */ |
|||
char jump; |
|||
|
|||
char builtin; |
|||
}; |
|||
|
|||
/* We don't need a special hash table entry structure, but we do need
|
|||
to keep some information between linker passes, so we use a special |
|||
hash table. */ |
|||
|
|||
struct linux_link_hash_entry |
|||
{ |
|||
struct aout_link_hash_entry root; |
|||
}; |
|||
|
|||
struct linux_link_hash_table |
|||
{ |
|||
struct aout_link_hash_table root; |
|||
|
|||
/* First dynamic object found in link. */ |
|||
bfd *dynobj; |
|||
|
|||
/* Number of fixups. */ |
|||
size_t fixup_count; |
|||
|
|||
/* Number of builtin fixups. */ |
|||
size_t local_builtins; |
|||
|
|||
/* List of fixups. */ |
|||
struct fixup *fixup_list; |
|||
}; |
|||
|
|||
static struct bfd_hash_entry *linux_link_hash_newfunc |
|||
PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *)); |
|||
static struct bfd_link_hash_table *linux_link_hash_table_create |
|||
PARAMS ((bfd *)); |
|||
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 |
|||
PARAMS ((bfd *, struct bfd_link_info *)); |
|||
static boolean linux_add_one_symbol |
|||
PARAMS ((struct bfd_link_info *, bfd *, const char *, flagword, asection *, |
|||
bfd_vma, const char *, boolean, boolean, |
|||
struct bfd_link_hash_entry **)); |
|||
static boolean linux_tally_symbols |
|||
PARAMS ((struct linux_link_hash_entry *, PTR)); |
|||
static boolean linux_finish_dynamic_link |
|||
PARAMS ((bfd *, struct bfd_link_info *)); |
|||
|
|||
/* Routine to create an entry in an Linux link hash table. */ |
|||
|
|||
static struct bfd_hash_entry * |
|||
linux_link_hash_newfunc (entry, table, string) |
|||
struct bfd_hash_entry *entry; |
|||
struct bfd_hash_table *table; |
|||
const char *string; |
|||
{ |
|||
struct linux_link_hash_entry *ret = (struct linux_link_hash_entry *) entry; |
|||
|
|||
/* Allocate the structure if it has not already been allocated by a
|
|||
subclass. */ |
|||
if (ret == (struct linux_link_hash_entry *) NULL) |
|||
ret = ((struct linux_link_hash_entry *) |
|||
bfd_hash_allocate (table, sizeof (struct linux_link_hash_entry))); |
|||
if (ret == NULL) |
|||
return (struct bfd_hash_entry *) ret; |
|||
|
|||
/* Call the allocation method of the superclass. */ |
|||
ret = ((struct linux_link_hash_entry *) |
|||
NAME(aout,link_hash_newfunc) ((struct bfd_hash_entry *) ret, |
|||
table, string)); |
|||
if (ret != NULL) |
|||
{ |
|||
/* Set local fields; there aren't any. */ |
|||
} |
|||
|
|||
return (struct bfd_hash_entry *) ret; |
|||
} |
|||
|
|||
/* Create a Linux link hash table. */ |
|||
|
|||
static struct bfd_link_hash_table * |
|||
linux_link_hash_table_create (abfd) |
|||
bfd *abfd; |
|||
{ |
|||
struct linux_link_hash_table *ret; |
|||
|
|||
ret = ((struct linux_link_hash_table *) |
|||
bfd_alloc (abfd, sizeof (struct linux_link_hash_table))); |
|||
if (ret == (struct linux_link_hash_table *) NULL) |
|||
{ |
|||
bfd_set_error (bfd_error_no_memory); |
|||
return (struct bfd_link_hash_table *) NULL; |
|||
} |
|||
if (! NAME(aout,link_hash_table_init) (&ret->root, abfd, |
|||
linux_link_hash_newfunc)) |
|||
{ |
|||
free (ret); |
|||
return (struct bfd_link_hash_table *) NULL; |
|||
} |
|||
|
|||
ret->dynobj = NULL; |
|||
ret->fixup_count = 0; |
|||
ret->local_builtins = 0; |
|||
ret->fixup_list = NULL; |
|||
|
|||
return &ret->root.root; |
|||
} |
|||
|
|||
/* Look up an entry in a Linux link hash table. */ |
|||
|
|||
#define linux_link_hash_lookup(table, string, create, copy, follow) \ |
|||
((struct linux_link_hash_entry *) \ |
|||
aout_link_hash_lookup (&(table)->root, (string), (create), (copy),\ |
|||
(follow))) |
|||
|
|||
/* Traverse a Linux link hash table. */ |
|||
|
|||
#define linux_link_hash_traverse(table, func, info) \ |
|||
(aout_link_hash_traverse \ |
|||
(&(table)->root, \ |
|||
(boolean (*) PARAMS ((struct aout_link_hash_entry *, PTR))) (func), \ |
|||
(info))) |
|||
|
|||
/* Get the Linux link hash table from the info structure. This is
|
|||
just a cast. */ |
|||
|
|||
#define linux_hash_table(p) ((struct linux_link_hash_table *) ((p)->hash)) |
|||
|
|||
/* Store the information for a new fixup. */ |
|||
|
|||
static struct fixup * |
|||
new_fixup (info, h, value, builtin) |
|||
struct bfd_link_info *info; |
|||
struct linux_link_hash_entry *h; |
|||
bfd_vma value; |
|||
int builtin; |
|||
{ |
|||
struct fixup *f; |
|||
|
|||
f = (struct fixup *) bfd_hash_allocate (&info->hash->table, |
|||
sizeof (struct fixup)); |
|||
if (f == NULL) |
|||
return f; |
|||
f->next = linux_hash_table (info)->fixup_list; |
|||
linux_hash_table (info)->fixup_list = f; |
|||
f->h = h; |
|||
f->value = value; |
|||
f->builtin = builtin; |
|||
f->jump = 0; |
|||
++linux_hash_table (info)->fixup_count; |
|||
return f; |
|||
} |
|||
|
|||
/* We come here once we realize that we are going to link to a shared
|
|||
library. We need to create a special section that contains the |
|||
fixup table, and we ultimately need to add a pointer to this into |
|||
the set vector for SHARABLE_CONFLICTS. At this point we do not |
|||
know the size of the section, but that's OK - we just need to |
|||
create it for now. */ |
|||
|
|||
static boolean |
|||
linux_link_create_dynamic_sections (abfd, info) |
|||
bfd *abfd; |
|||
struct bfd_link_info *info; |
|||
{ |
|||
flagword flags; |
|||
register asection *s; |
|||
|
|||
/* Note that we set the SEC_IN_MEMORY flag. */ |
|||
flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY; |
|||
|
|||
/* We choose to use the name ".linux-dynamic" for the fixup table.
|
|||
Why not? */ |
|||
s = bfd_make_section (abfd, ".linux-dynamic"); |
|||
if (s == NULL |
|||
|| ! bfd_set_section_flags (abfd, s, flags) |
|||
|| ! bfd_set_section_alignment (abfd, s, 2)) |
|||
return false; |
|||
s->_raw_size = 0; |
|||
s->contents = 0; |
|||
|
|||
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 |
|||
linux_add_one_symbol (info, abfd, name, flags, section, value, string, |
|||
copy, collect, hashp) |
|||
struct bfd_link_info *info; |
|||
bfd *abfd; |
|||
const char *name; |
|||
flagword flags; |
|||
asection *section; |
|||
bfd_vma value; |
|||
const char *string; |
|||
boolean copy; |
|||
boolean collect; |
|||
struct bfd_link_hash_entry **hashp; |
|||
{ |
|||
struct linux_link_hash_entry *h; |
|||
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 |
|||
need to create the dynamic sections. |
|||
|
|||
FIXME: What if abfd->xvec != info->hash->creator? We may want to |
|||
be able to link Linux a.out and ELF objects together, but serious |
|||
confusion is possible. */ |
|||
|
|||
insert = false; |
|||
|
|||
if (! info->relocateable |
|||
&& linux_hash_table (info)->dynobj == NULL |
|||
&& strcmp (name, SHARABLE_CONFLICTS) == 0 |
|||
&& (flags & BSF_CONSTRUCTOR) != 0 |
|||
&& abfd->xvec == info->hash->creator) |
|||
{ |
|||
if (! linux_link_create_dynamic_sections (abfd, info)) |
|||
return false; |
|||
linux_hash_table (info)->dynobj = abfd; |
|||
insert = true; |
|||
} |
|||
|
|||
if (bfd_is_abs_section (section) |
|||
&& abfd->xvec == info->hash->creator) |
|||
{ |
|||
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_defweak)) |
|||
{ |
|||
struct fixup *f; |
|||
|
|||
if (hashp != NULL) |
|||
*hashp = (struct bfd_link_hash_entry *) h; |
|||
|
|||
f = new_fixup (info, h, value, ! IS_PLT_SYM (name)); |
|||
if (f == NULL) |
|||
return false; |
|||
f->jump = IS_PLT_SYM (name); |
|||
|
|||
return true; |
|||
} |
|||
} |
|||
|
|||
/* Do the usual procedure for adding a symbol. */ |
|||
if (! _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, |
|||
value, string, copy, collect, |
|||
hashp)) |
|||
return false; |
|||
|
|||
/* Insert a pointer to our table in the set vector. The dynamic
|
|||
linker requires this information */ |
|||
if (insert) |
|||
{ |
|||
asection *s; |
|||
|
|||
/* Here we do our special thing to add the pointer to the
|
|||
dynamic section in the SHARABLE_CONFLICTS set vector. */ |
|||
s = bfd_get_section_by_name (linux_hash_table (info)->dynobj, |
|||
".linux-dynamic"); |
|||
BFD_ASSERT (s != NULL); |
|||
|
|||
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; |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
/* We will crawl the hash table and come here for every global symbol.
|
|||
We will examine each entry and see if there are indications that we |
|||
need to add a fixup. There are two possible cases - one is where |
|||
you have duplicate definitions of PLT or GOT symbols - these will |
|||
have already been caught and added as "builtin" fixups. If we find |
|||
that the corresponding non PLT/GOT symbol is also present, we |
|||
convert it to a regular fixup instead. |
|||
|
|||
This function is called via linux_link_hash_traverse. */ |
|||
|
|||
static boolean |
|||
linux_tally_symbols (h, data) |
|||
struct linux_link_hash_entry *h; |
|||
PTR data; |
|||
{ |
|||
struct bfd_link_info *info = (struct bfd_link_info *) data; |
|||
struct fixup *f, *f1; |
|||
int is_plt; |
|||
struct linux_link_hash_entry *h1, *h2; |
|||
boolean exists; |
|||
|
|||
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 (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); |
|||
|
|||
if (is_plt || IS_GOT_SYM (h->root.root.root.string)) |
|||
{ |
|||
/* Look up this symbol twice. Once just as a regular lookup,
|
|||
and then again following all of the indirect links until we |
|||
reach a real symbol. */ |
|||
h1 = linux_link_hash_lookup (linux_hash_table (info), |
|||
(h->root.root.root.string |
|||
+ sizeof PLT_REF_PREFIX - 1), |
|||
false, false, true); |
|||
/* h2 does not follow indirect symbols. */ |
|||
h2 = linux_link_hash_lookup (linux_hash_table (info), |
|||
(h->root.root.root.string |
|||
+ sizeof PLT_REF_PREFIX - 1), |
|||
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 |
|||
came from the same library. If on the other hand, we had to |
|||
use an indirect symbol to get to the real symbol, we add the |
|||
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_defweak) |
|||
&& ! bfd_is_abs_section (h1->root.root.u.def.section)) |
|||
|| h2->root.root.type == bfd_link_hash_indirect)) |
|||
{ |
|||
/* See if there is a "builtin" fixup already present
|
|||
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; |
|||
for (f1 = linux_hash_table (info)->fixup_list; |
|||
f1 != NULL; |
|||
f1 = f1->next) |
|||
{ |
|||
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)) |
|||
{ |
|||
f = new_fixup (info, h1, f1->h->root.root.u.def.value, 0); |
|||
f->jump = is_plt; |
|||
} |
|||
f1->h = h1; |
|||
f1->jump = is_plt; |
|||
f1->builtin = 0; |
|||
exists = true; |
|||
} |
|||
if (! exists |
|||
&& bfd_is_abs_section (h->root.root.u.def.section)) |
|||
{ |
|||
f = new_fixup (info, h1, h->root.root.u.def.value, 0); |
|||
if (f == NULL) |
|||
{ |
|||
/* FIXME: No way to return error. */ |
|||
abort (); |
|||
} |
|||
f->jump = is_plt; |
|||
} |
|||
} |
|||
|
|||
/* 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; |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
/* This is called to set the size of the .linux-dynamic section is.
|
|||
It is called by the Linux linker emulation before_allocation |
|||
routine. We have finished reading all of the input files, and now |
|||
we just scan the hash tables to find out how many additional fixups |
|||
are required. */ |
|||
|
|||
boolean |
|||
bfd_m68klinux_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, |
|||
(PTR) info); |
|||
|
|||
/* If there are builtin fixups, leave room for a marker. This is
|
|||
used by the dynamic linker so that it knows that all that follow |
|||
are builtin fixups instead of regular fixups. */ |
|||
for (f = linux_hash_table (info)->fixup_list; f != NULL; f = f->next) |
|||
{ |
|||
if (f->builtin) |
|||
{ |
|||
++linux_hash_table (info)->fixup_count; |
|||
++linux_hash_table (info)->local_builtins; |
|||
break; |
|||
} |
|||
} |
|||
|
|||
if (linux_hash_table (info)->dynobj == NULL) |
|||
{ |
|||
if (linux_hash_table (info)->fixup_count > 0) |
|||
abort (); |
|||
return true; |
|||
} |
|||
|
|||
/* Allocate memory for our fixup table. We will fill it in later. */ |
|||
s = bfd_get_section_by_name (linux_hash_table (info)->dynobj, |
|||
".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); |
|||
if (s->contents == NULL) |
|||
{ |
|||
bfd_set_error (bfd_error_no_memory); |
|||
return false; |
|||
} |
|||
memset (s->contents, 0, (size_t) s->_raw_size); |
|||
} |
|||
|
|||
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 |
|||
linux_finish_dynamic_link (output_bfd, info) |
|||
bfd *output_bfd; |
|||
struct bfd_link_info *info; |
|||
{ |
|||
asection *s, *os, *is; |
|||
bfd_byte *fixup_table; |
|||
struct linux_link_hash_entry *h; |
|||
struct fixup *f; |
|||
unsigned int new_addr; |
|||
int section_offset; |
|||
unsigned int fixups_written; |
|||
|
|||
if (linux_hash_table (info)->dynobj == NULL) |
|||
return true; |
|||
|
|||
s = bfd_get_section_by_name (linux_hash_table (info)->dynobj, |
|||
".linux-dynamic"); |
|||
BFD_ASSERT (s != NULL); |
|||
os = s->output_section; |
|||
fixups_written = 0; |
|||
|
|||
#ifdef LINUX_LINK_DEBUG |
|||
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); |
|||
fixup_table += 4; |
|||
|
|||
/* Fill in fixup table. */ |
|||
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 |
|||
&& f->h->root.root.type != bfd_link_hash_defweak) |
|||
{ |
|||
(*_bfd_error_handler) |
|||
("Symbol %s not defined for fixups\n", |
|||
f->h->root.root.root.string); |
|||
continue; |
|||
} |
|||
|
|||
is = f->h->root.root.u.def.section; |
|||
section_offset = is->output_section->vma + is->output_offset; |
|||
new_addr = f->h->root.root.u.def.value + section_offset; |
|||
|
|||
#ifdef LINUX_LINK_DEBUG |
|||
printf ("Fixup(%d) %s: %x %x\n",f->jump, f->h->root.root.string, |
|||
new_addr, f->value); |
|||
#endif |
|||
|
|||
if (f->jump) |
|||
{ |
|||
bfd_put_32 (output_bfd, new_addr, fixup_table); |
|||
fixup_table += 4; |
|||
bfd_put_32 (output_bfd, f->value + 2, fixup_table); |
|||
fixup_table += 4; |
|||
} |
|||
else |
|||
{ |
|||
bfd_put_32 (output_bfd, new_addr, fixup_table); |
|||
fixup_table += 4; |
|||
bfd_put_32 (output_bfd, f->value, fixup_table); |
|||
fixup_table += 4; |
|||
} |
|||
++fixups_written; |
|||
} |
|||
|
|||
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); |
|||
fixup_table += 4; |
|||
bfd_put_32 (output_bfd, 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 |
|||
&& f->h->root.root.type != bfd_link_hash_defweak) |
|||
{ |
|||
(*_bfd_error_handler) |
|||
("Symbol %s not defined for fixups\n", |
|||
f->h->root.root.root.string); |
|||
continue; |
|||
} |
|||
|
|||
is = f->h->root.root.u.def.section; |
|||
section_offset = is->output_section->vma + is->output_offset; |
|||
new_addr = f->h->root.root.u.def.value + section_offset; |
|||
|
|||
#ifdef LINUX_LINK_DEBUG |
|||
printf ("Fixup(B) %s: %x %x\n", f->h->root.root.string, |
|||
new_addr, f->value); |
|||
#endif |
|||
|
|||
bfd_put_32 (output_bfd, new_addr, fixup_table); |
|||
fixup_table += 4; |
|||
bfd_put_32 (output_bfd, f->value, fixup_table); |
|||
fixup_table += 4; |
|||
++fixups_written; |
|||
} |
|||
} |
|||
|
|||
if (linux_hash_table (info)->fixup_count != fixups_written) |
|||
{ |
|||
(*_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); |
|||
fixup_table += 4; |
|||
bfd_put_32 (output_bfd, 0, fixup_table); |
|||
fixup_table += 4; |
|||
++fixups_written; |
|||
} |
|||
} |
|||
|
|||
h = linux_link_hash_lookup (linux_hash_table (info), |
|||
"__BUILTIN_FIXUPS__", |
|||
false, false, false); |
|||
|
|||
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; |
|||
new_addr = h->root.root.u.def.value + section_offset; |
|||
|
|||
#ifdef LINUX_LINK_DEBUG |
|||
printf ("Builtin fixup table at %x\n", new_addr); |
|||
#endif |
|||
|
|||
bfd_put_32 (output_bfd, new_addr, fixup_table); |
|||
} |
|||
else |
|||
bfd_put_32 (output_bfd, 0, fixup_table); |
|||
|
|||
if (bfd_seek (output_bfd, 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; |
|||
|
|||
return true; |
|||
} |
|||
|
|||
#define MY_bfd_link_hash_table_create linux_link_hash_table_create |
|||
#define MY_add_one_symbol linux_add_one_symbol |
|||
#define MY_finish_dynamic_link linux_finish_dynamic_link |
|||
|
|||
#define MY_zmagic_contiguous 1 |
|||
|
|||
#include "aout-target.h" |
|||
Loading…
Reference in new issue